From 14f2ca833fc9665cbe3c6f8a70610443d356137d Mon Sep 17 00:00:00 2001 From: David Sanders Date: Thu, 2 May 2024 14:43:09 -0700 Subject: [PATCH 1/2] chore!: remove @ts-ignore syntax [skip release] BREAKING CHANGE: removed @ts-ignore syntax for lint-markdown-ts-check --- README.md | 4 +- bin/lint-markdown-ts-check.ts | 49 +++---------- ...lint-roller-markdown-ts-check.spec.ts.snap | 70 +++++++++---------- tests/fixtures/ts-check.md | 49 +------------ 4 files changed, 47 insertions(+), 125 deletions(-) diff --git a/README.md b/README.md index f61ca35..f677800 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ by adding `@nolint` to the info string. `lint-roller-markdown-ts-check` is a command to type check JS/TS code blocks in Markdown with `tsc`. Type checking can be disabled for specific code blocks -by adding `@ts-nocheck` to the info string, specific lines can be ignored -by adding `@ts-ignore=[,]` to the info string, and additional +by adding `@ts-nocheck` to the info string, specific lines can be ignored by +adding `@ts-expect-error=[,]` to the info string, and additional globals can be defined with `@ts-type={name:type}`. The `Window` object can be extended with more types using `@ts-window-type={name:type}`. When type checking TypeScript blocks in the same Markdown file, global augmentation diff --git a/bin/lint-markdown-ts-check.ts b/bin/lint-markdown-ts-check.ts index 22a365e..cf00af5 100644 --- a/bin/lint-markdown-ts-check.ts +++ b/bin/lint-markdown-ts-check.ts @@ -51,8 +51,8 @@ async function typeCheckFiles( '', ); - // Strip any @ts-expect-error/@ts-ignore comments we added - correctedOutput = correctedOutput.replace(/ \/\/ @ts-(?:expect-error|ignore)/g, ''); + // Strip any @ts-expect-error comments we added + correctedOutput = correctedOutput.replace(/ \/\/ @ts-expect-error/g, ''); if (correctedOutput.trim()) { for (const [filename, originalFilename] of filenameMapping.entries()) { @@ -110,38 +110,16 @@ async function main( ?.match(/\B@ts-expect-error=\[([\d,]*)\]\B/)?.[1] .split(',') .map((line) => parseInt(line)); - const tsIgnoreLines = codeBlock.meta - ?.match(/\B@ts-ignore=\[([\d,]*)\]\B/)?.[1] - .split(',') - .map((line) => parseInt(line)); const tsTypeLines = codeBlock.meta ? parseDirectives('@ts-type', codeBlock.meta) : []; const tsWindowTypeLines = codeBlock.meta ? parseDirectives('@ts-window-type', codeBlock.meta) : []; - if ( - tsNoCheck && - (tsExpectErrorLines || tsIgnoreLines || tsTypeLines.length || tsWindowTypeLines.length) - ) { - console.log( - `${filepath}:${line}:${ - indent + 1 - }: Code block has both @ts-nocheck and @ts-expect-error/@ts-ignore/@ts-type/@ts-window-type, they conflict`, - ); - errors = true; - continue; - } - - // There should be no overlap between @ts-expect-error and @ts-ignore - if ( - tsExpectErrorLines && - tsIgnoreLines && - tsExpectErrorLines.some((line) => tsIgnoreLines.includes(line)) - ) { + if (tsNoCheck && (tsExpectErrorLines || tsTypeLines.length || tsWindowTypeLines.length)) { console.log( `${filepath}:${line}:${ indent + 1 - }: Code block has both @ts-expect-error and @ts-ignore with same line number(s)`, + }: Code block has both @ts-nocheck and @ts-expect-error/@ts-type/@ts-window-type, they conflict`, ); errors = true; continue; @@ -165,11 +143,11 @@ async function main( const insertComment = (comment: string, line: number) => { // Inserting additional lines will make the tsc output // incorrect which would be a pain to manually adjust, - // and there is no @ts-ignore-line, so tack the comment - // on to the end of the previous line - looks ugly but - // we never have to see it since it's in a temp file. - // The first line of the file is an edge case where an - // insertion is necessary, so take that into account + // and there is no @ts-expect-error-line, so tack the + // comment on to the end of the previous line - looks + // ugly but we never have to see it since it's in a temp + // file. The first line of the file is an edge case where + // an insertion is necessary, so take that into account if (line === 1) { codeLines.unshift(comment); insertedInitialLine = true; @@ -186,15 +164,10 @@ async function main( } }; - // Blocks can have @ts-ignore=[1,10,50] in their info string - // (1-based lines) to insert an "// @ts-ignore" comment before + // Blocks can have @ts-expect-error=[1,10,50] in their info string + // (1-based lines) to insert an "// @ts-expect-error" comment before // specified lines, in order to ignore specific lines (like // requires of extra modules) without skipping the whole block - for (const line of tsIgnoreLines ?? []) { - insertComment('// @ts-ignore', line); - } - - // Blocks can also have @ts-expect-error for (const line of tsExpectErrorLines ?? []) { insertComment('// @ts-expect-error', line); } diff --git a/tests/__snapshots__/lint-roller-markdown-ts-check.spec.ts.snap b/tests/__snapshots__/lint-roller-markdown-ts-check.spec.ts.snap index edce19e..4e4c775 100644 --- a/tests/__snapshots__/lint-roller-markdown-ts-check.spec.ts.snap +++ b/tests/__snapshots__/lint-roller-markdown-ts-check.spec.ts.snap @@ -1,51 +1,46 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`lint-roller-markdown-ts-check should type check code blocks 1`] = ` -"ts-check.md:49:1: Code block has both @ts-nocheck and @ts-expect-error/@ts-ignore/@ts-type/@ts-window-type, they conflict -ts-check.md:55:1: Code block has both @ts-nocheck and @ts-expect-error/@ts-ignore/@ts-type/@ts-window-type, they conflict -ts-check.md:128:8 - error TS2339: Property 'myAwesomeAPI' does not exist on type 'Window & typeof globalThis'. +"ts-check.md:37:1: Code block has both @ts-nocheck and @ts-expect-error/@ts-type/@ts-window-type, they conflict +ts-check.md:43:1: Code block has both @ts-nocheck and @ts-expect-error/@ts-type/@ts-window-type, they conflict +ts-check.md:109:5 - error TS2304: Cannot find name 'a'. -128 window.myAwesomeAPI() -   ~~~~~~~~~~~~ - -ts-check.md:154:5 - error TS2304: Cannot find name 'a'. - -154 if (a > b) { +109 if (a > b) {    ~ -ts-check.md:154:9 - error TS2304: Cannot find name 'b'. +ts-check.md:109:9 - error TS2304: Cannot find name 'b'. -154 if (a > b) { +109 if (a > b) {    ~ -ts-check.md:157:28 - error TS2304: Cannot find name 'a'. +ts-check.md:112:28 - error TS2304: Cannot find name 'a'. -157 console.log(\`not true: \${a} < \${b}\`) +112 console.log(\`not true: \${a} < \${b}\`)    ~ -ts-check.md:157:35 - error TS2304: Cannot find name 'b'. +ts-check.md:112:35 - error TS2304: Cannot find name 'b'. -157 console.log(\`not true: \${a} < \${b}\`) +112 console.log(\`not true: \${a} < \${b}\`)    ~ -ts-check.md:160:8 - error TS2339: Property 'AwesomeAPI' does not exist on type 'Window & typeof globalThis'. +ts-check.md:115:8 - error TS2339: Property 'AwesomeAPI' does not exist on type 'Window & typeof globalThis'. -160 window.AwesomeAPI.bar('baz') +115 window.AwesomeAPI.bar('baz')    ~~~~~~~~~~ -ts-check.md:174:15 - error TS2339: Property 'wrongAPI' does not exist on type 'typeof BrowserWindow'. +ts-check.md:129:15 - error TS2339: Property 'wrongAPI' does not exist on type 'typeof BrowserWindow'. -174 BrowserWindow.wrongAPI('foo') +129 BrowserWindow.wrongAPI('foo')    ~~~~~~~~ -ts-check.md:180:15 - error TS2339: Property 'wrongAPI' does not exist on type 'typeof BrowserWindow'. +ts-check.md:135:15 - error TS2339: Property 'wrongAPI' does not exist on type 'typeof BrowserWindow'. -180 BrowserWindow.wrongAPI('foo') +135 BrowserWindow.wrongAPI('foo')    ~~~~~~~~ -ts-check.md:212:8 - error TS2339: Property 'AwesomeAPI' does not exist on type 'Window & typeof globalThis'. +ts-check.md:167:8 - error TS2339: Property 'AwesomeAPI' does not exist on type 'Window & typeof globalThis'. -212 window.AwesomeAPI.foo(42) +167 window.AwesomeAPI.foo(42)    ~~~~~~~~~~ ts-check.md:4:9 - error TS2339: Property 'foo' does not exist on type 'Console'. @@ -53,14 +48,14 @@ ts-check.md:55:1: Code block has both @ts-nocheck and @ts-expect-error/@ts-ignor 4 console.foo('whoops')    ~~~ -ts-check.md:66:15 - error TS2339: Property 'wrongAPI' does not exist on type 'typeof BrowserWindow'. +ts-check.md:54:15 - error TS2339: Property 'wrongAPI' does not exist on type 'typeof BrowserWindow'. -66 BrowserWindow.wrongAPI('foo') +54 BrowserWindow.wrongAPI('foo')    ~~~~~~~~ -ts-check.md:72:15 - error TS2339: Property 'wrongAPI' does not exist on type 'typeof BrowserWindow'. +ts-check.md:60:15 - error TS2339: Property 'wrongAPI' does not exist on type 'typeof BrowserWindow'. -72 BrowserWindow.wrongAPI('foo') +60 BrowserWindow.wrongAPI('foo')    ~~~~~~~~ ts-check.md:8:9 - error TS2339: Property 'foo' does not exist on type 'Console'. @@ -68,25 +63,24 @@ ts-check.md:55:1: Code block has both @ts-nocheck and @ts-expect-error/@ts-ignor 8 console.foo('whoops')    ~~~ -ts-check.md:95:8 - error TS2339: Property 'myAwesomeAPI' does not exist on type 'Window & typeof globalThis'. +ts-check.md:83:8 - error TS2339: Property 'myAwesomeAPI' does not exist on type 'Window & typeof globalThis'. -95 window.myAwesomeAPI() +83 window.myAwesomeAPI()    ~~~~~~~~~~~~ -Found 14 errors in 10 files. +Found 13 errors in 9 files. Errors Files - 1 ts-check.md:128 - 5 ts-check.md:154 - 1 ts-check.md:174 - 1 ts-check.md:180 - 1 ts-check.md:212 + 5 ts-check.md:109 + 1 ts-check.md:129 + 1 ts-check.md:135 + 1 ts-check.md:167 1 ts-check.md:4 - 1 ts-check.md:66 - 1 ts-check.md:72 + 1 ts-check.md:54 + 1 ts-check.md:60 1 ts-check.md:8 - 1 ts-check.md:95 + 1 ts-check.md:83 " `; diff --git a/tests/fixtures/ts-check.md b/tests/fixtures/ts-check.md index 5ba7cf5..efdac11 100644 --- a/tests/fixtures/ts-check.md +++ b/tests/fixtures/ts-check.md @@ -20,18 +20,6 @@ console.bar('whoops') These blocks suppress specific lines (1-based) -```js @ts-ignore=[3] -console.log('test') - -window.myAwesomeAPI() -``` - -```js title='main.js' @ts-ignore=[3] -console.log('test') - -window.myAwesomeAPI() -``` - ```js @ts-expect-error=[3] console.log('test') @@ -46,13 +34,13 @@ window.myAwesomeAPI() These blocks have conflicting options -```js @ts-nocheck @ts-ignore=[3] +```js @ts-nocheck @ts-expect-error=[3] console.log('test') window.myAwesomeAPI() ``` -```js @ts-nocheck title='main.js' @ts-ignore=[3] +```js @ts-nocheck title='main.js' @ts-expect-error=[3] console.log('test') window.myAwesomeAPI() @@ -72,39 +60,6 @@ const { BrowserWindow } = require('electron') BrowserWindow.wrongAPI('foo') ``` -These blocks have multiple @ts-ignore lines - -```js @ts-ignore=[3,5] -console.log('test') - -window.myAwesomeAPI() - -window.myOtherAwesomeAPI() -``` - -```js @ts-ignore=[1,4] -window.myAwesomeAPI() - -console.log('test') -window.myOtherAwesomeAPI() -``` - -This confirms @ts-ignore output is stripped - -```js @ts-ignore=[2] -window.myAwesomeAPI() -window.myOtherAwesomeAPI() -``` - -This confirms @ts-ignore works if the previous line is a comment - -```js @ts-ignore=[4] -console.log('test') - -// This is a comment -window.myAwesomeAPI() -``` - These blocks have multiple @ts-expect-error lines ```js @ts-expect-error=[3,5] From 68e40fe2716463bdc8ef506947a12cf554d305db Mon Sep 17 00:00:00 2001 From: David Sanders Date: Tue, 7 May 2024 11:05:43 -0700 Subject: [PATCH 2/2] test: ignore Node.js deprecation warnings during test --- tests/lint-roller-markdown-ts-check.spec.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/lint-roller-markdown-ts-check.spec.ts b/tests/lint-roller-markdown-ts-check.spec.ts index 6703777..50c0d2e 100644 --- a/tests/lint-roller-markdown-ts-check.spec.ts +++ b/tests/lint-roller-markdown-ts-check.spec.ts @@ -7,7 +7,12 @@ function runLintMarkdownTsCheck(...args: string[]) { return cp.spawnSync( process.execPath, [path.resolve(__dirname, '../dist/bin/lint-markdown-ts-check.js'), ...args], - { stdio: 'pipe', encoding: 'utf-8', cwd: FIXTURES_DIR }, + { + stdio: 'pipe', + encoding: 'utf-8', + cwd: FIXTURES_DIR, + env: { NODE_OPTIONS: '--no-deprecation' }, + }, ); }