From 4938d992bfc2234ce9d9b28da520e2bb2be7a59c Mon Sep 17 00:00:00 2001 From: Paul Douglas Brimicombe Date: Fri, 1 Apr 2022 13:30:25 +0100 Subject: [PATCH 01/18] Add error locations to TSErrors --- src/index.ts | 16 +++++++-- src/test/index.spec.ts | 81 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 70dfe109b..40719f07f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -471,7 +471,14 @@ export class TSError extends BaseError { name = 'TSError'; diagnosticText!: string; - constructor(diagnosticText: string, public diagnosticCodes: number[]) { + constructor( + diagnosticText: string, + public diagnosticCodes: number[], + public errorLocations: Record< + string, + { start?: number; length?: number } + > = {} + ) { super(`⨯ Unable to compile TypeScript:\n${diagnosticText}`); Object.defineProperty(this, 'diagnosticText', { configurable: true, @@ -829,7 +836,12 @@ export function createFromPreloadedConfig( function createTSError(diagnostics: ReadonlyArray<_ts.Diagnostic>) { const diagnosticText = formatDiagnostics(diagnostics, diagnosticHost); const diagnosticCodes = diagnostics.map((x) => x.code); - return new TSError(diagnosticText, diagnosticCodes); + const errorLocations = Object.fromEntries( + diagnostics.map((x) => { + return [x.code, { start: x.start, length: x.length }]; + }) + ); + return new TSError(diagnosticText, diagnosticCodes, errorLocations); } function reportTSError(configDiagnosticList: _ts.Diagnostic[]) { diff --git a/src/test/index.spec.ts b/src/test/index.spec.ts index 72faf86ea..85b8b5362 100644 --- a/src/test/index.spec.ts +++ b/src/test/index.spec.ts @@ -31,6 +31,7 @@ import { CMD_ESM_LOADER_WITHOUT_PROJECT, EXPERIMENTAL_MODULES_FLAG, } from './helpers'; +import type { TSError } from '..'; const exec = createExec({ cwd: TEST_DIR, @@ -974,6 +975,86 @@ test.suite('ts-node', (test) => { expect(output).toMatch('var x = 10;'); }); + test('should throw errors', ({ context: { service } }) => { + let err: unknown = null; + + try { + service.compile( + ` + console.log('The Error constructor expects a string argument'); + + const error = new Error(123); + `, + 'test.ts' + ); + } catch (error) { + err = error; + } + + if (err === null) { + throw new Error('Command was expected to fail, but it succeeded.'); + } + + expect((err as Error).message).toMatch( + new RegExp( + "TS2345: Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'\\." + ) + ); + }); + + test('should throw errors with diagnostic codes', ({ + context: { service }, + }) => { + let err: unknown = null; + + try { + service.compile( + ` + console.log('The Error constructor expects a string argument'); + + const error = new Error(123); + `, + 'test.ts' + ); + } catch (error) { + err = error; + } + + if (err === null) { + throw new Error('Command was expected to fail, but it succeeded.'); + } + + expect((err as TSError).diagnosticCodes).toEqual([2345]); + }); + + test('should throw errors with error locations', ({ + context: { service }, + }) => { + let err: unknown = null; + + try { + service.compile( + ` + console.log('The Error constructor expects a string argument'); + + const error = new Error(123); + `, + 'test.ts' + ); + } catch (error) { + err = error; + } + + if (err === null) { + throw new Error('Command was expected to fail, but it succeeded.'); + } + + expect((err as TSError).errorLocations).toEqual({ + 2345: { start: 94, length: 3 }, + }); + }); + test.suite('should get type information', (test) => { test('given position of identifier', ({ context: { service } }) => { expect( From 428e50635be772e8100522f435ce4f7d33ba63f9 Mon Sep 17 00:00:00 2001 From: Paul Douglas Brimicombe Date: Fri, 1 Apr 2022 14:00:06 +0100 Subject: [PATCH 02/18] Simplify tests / code formatting --- src/index.ts | 11 +++++---- src/test/index.spec.ts | 52 ++++++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/src/index.ts b/src/index.ts index 40719f07f..48fb61249 100644 --- a/src/index.ts +++ b/src/index.ts @@ -470,14 +470,12 @@ export const DEFAULTS: RegisterOptions = { export class TSError extends BaseError { name = 'TSError'; diagnosticText!: string; + errorLocations!: Record; constructor( diagnosticText: string, public diagnosticCodes: number[], - public errorLocations: Record< - string, - { start?: number; length?: number } - > = {} + errorLocations: Record = {} ) { super(`⨯ Unable to compile TypeScript:\n${diagnosticText}`); Object.defineProperty(this, 'diagnosticText', { @@ -485,6 +483,11 @@ export class TSError extends BaseError { writable: true, value: diagnosticText, }); + Object.defineProperty(this, 'errorLocations', { + configurable: true, + writable: true, + value: errorLocations, + }); } /** diff --git a/src/test/index.spec.ts b/src/test/index.spec.ts index 85b8b5362..7683b0f4c 100644 --- a/src/test/index.spec.ts +++ b/src/test/index.spec.ts @@ -979,14 +979,7 @@ test.suite('ts-node', (test) => { let err: unknown = null; try { - service.compile( - ` - console.log('The Error constructor expects a string argument'); - - const error = new Error(123); - `, - 'test.ts' - ); + service.compile('new Error(123)', 'test.ts'); } catch (error) { err = error; } @@ -1003,20 +996,36 @@ test.suite('ts-node', (test) => { ); }); - test('should throw errors with diagnostic codes', ({ + test('should throw errors with diagnostic text', ({ context: { service }, }) => { let err: unknown = null; try { - service.compile( - ` - console.log('The Error constructor expects a string argument'); + service.compile('new Error(123)', 'test.ts'); + } catch (error) { + err = error; + } - const error = new Error(123); - `, - 'test.ts' - ); + if (err === null) { + throw new Error('Command was expected to fail, but it succeeded.'); + } + + expect((err as TSError).diagnosticText).toMatch( + new RegExp( + "TS2345: Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'\\." + ) + ); + }); + + test('should throw errors with diagnostic codes', ({ + context: { service }, + }) => { + let err: unknown = null; + + try { + service.compile('new Error(123)', 'test.ts'); } catch (error) { err = error; } @@ -1034,14 +1043,7 @@ test.suite('ts-node', (test) => { let err: unknown = null; try { - service.compile( - ` - console.log('The Error constructor expects a string argument'); - - const error = new Error(123); - `, - 'test.ts' - ); + service.compile('new Error(123)', 'test.ts'); } catch (error) { err = error; } @@ -1051,7 +1053,7 @@ test.suite('ts-node', (test) => { } expect((err as TSError).errorLocations).toEqual({ - 2345: { start: 94, length: 3 }, + 2345: { start: 10, length: 3 }, }); }); From 7fb714aa2d066f3d49f578584b6a4c63e9a28a7b Mon Sep 17 00:00:00 2001 From: Paul Douglas Brimicombe Date: Mon, 4 Apr 2022 13:50:48 +0100 Subject: [PATCH 03/18] Expose the full TypeScript diagnostics on TSErrors --- src/index.ts | 15 +++++---------- src/test/index.spec.ts | 14 +++++++++++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/index.ts b/src/index.ts index 48fb61249..735f10293 100644 --- a/src/index.ts +++ b/src/index.ts @@ -470,12 +470,12 @@ export const DEFAULTS: RegisterOptions = { export class TSError extends BaseError { name = 'TSError'; diagnosticText!: string; - errorLocations!: Record; + diagnostics!: ReadonlyArray<_ts.Diagnostic>; constructor( diagnosticText: string, public diagnosticCodes: number[], - errorLocations: Record = {} + diagnostics: ReadonlyArray<_ts.Diagnostic> = [] ) { super(`⨯ Unable to compile TypeScript:\n${diagnosticText}`); Object.defineProperty(this, 'diagnosticText', { @@ -483,10 +483,10 @@ export class TSError extends BaseError { writable: true, value: diagnosticText, }); - Object.defineProperty(this, 'errorLocations', { + Object.defineProperty(this, 'diagnostics', { configurable: true, writable: true, - value: errorLocations, + value: diagnostics, }); } @@ -839,12 +839,7 @@ export function createFromPreloadedConfig( function createTSError(diagnostics: ReadonlyArray<_ts.Diagnostic>) { const diagnosticText = formatDiagnostics(diagnostics, diagnosticHost); const diagnosticCodes = diagnostics.map((x) => x.code); - const errorLocations = Object.fromEntries( - diagnostics.map((x) => { - return [x.code, { start: x.start, length: x.length }]; - }) - ); - return new TSError(diagnosticText, diagnosticCodes, errorLocations); + return new TSError(diagnosticText, diagnosticCodes, diagnostics); } function reportTSError(configDiagnosticList: _ts.Diagnostic[]) { diff --git a/src/test/index.spec.ts b/src/test/index.spec.ts index 7683b0f4c..a5dce0acb 100644 --- a/src/test/index.spec.ts +++ b/src/test/index.spec.ts @@ -1037,7 +1037,7 @@ test.suite('ts-node', (test) => { expect((err as TSError).diagnosticCodes).toEqual([2345]); }); - test('should throw errors with error locations', ({ + test('should throw errors with complete diagnostic information', ({ context: { service }, }) => { let err: unknown = null; @@ -1052,8 +1052,16 @@ test.suite('ts-node', (test) => { throw new Error('Command was expected to fail, but it succeeded.'); } - expect((err as TSError).errorLocations).toEqual({ - 2345: { start: 10, length: 3 }, + const diagnostics = (err as TSError).diagnostics; + + expect(diagnostics).toHaveLength(1); + expect(diagnostics[0]).toMatchObject({ + code: 2345, + start: 10, + length: 3, + messageText: + "Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'.", }); }); From f7afcab3a2f84dc7007ca0866d73ea58d67bdf87 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 13:57:59 -0400 Subject: [PATCH 04/18] Test re-org and deduplication --- src/test/diagnostics.spec.ts | 64 +++++++++++++++++++++++++ src/test/index.spec.ts | 91 ------------------------------------ 2 files changed, 64 insertions(+), 91 deletions(-) create mode 100644 src/test/diagnostics.spec.ts diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts new file mode 100644 index 000000000..21ceda215 --- /dev/null +++ b/src/test/diagnostics.spec.ts @@ -0,0 +1,64 @@ +import type { TSError } from '..'; +import { contextTsNodeUnderTest, ts } from './helpers'; +import { context, expect } from './testlib'; +import * as semver from 'semver'; +import { assert } from 'console'; +const test = context(contextTsNodeUnderTest); + +test.suite('TSError diagnostics', ({ context }) => { + const test = context(async (t) => { + return { + service: t.context.tsNodeUnderTest.create({ + compilerOptions: { target: 'es5' }, + skipProject: true, + }), + }; + }).context(async (t) => { + try { + t.context.service.compile('new Error(123)', 'test.ts'); + } catch (err) { + return { threw: true, err }; + } + return { threw: false, err: undefined }; + }); + + // TS 2.7 does not have the union type for some reason. + const diagnosticMessageRegexp = semver.lte(ts.version, '2.7.0') + ? new RegExp( + "TS2345: Argument of type '123' " + + "is not assignable to parameter of type 'string'\\." + ) + : new RegExp( + "TS2345: Argument of type '123' " + + "is not assignable to parameter of type 'string \\| undefined'\\." + ); + + test('should throw errors', ({ context: { threw, err } }) => { + expect(threw).toBe(true); + expect((err as Error).message).toMatch(diagnosticMessageRegexp); + }); + + test('should throw errors with diagnostic text', ({ context: { err } }) => { + expect((err as TSError).diagnosticText).toMatch(diagnosticMessageRegexp); + }); + + test('should throw errors with diagnostic codes', ({ context: { err } }) => { + expect((err as TSError).diagnosticCodes).toEqual([2345]); + }); + + test('should throw errors with complete diagnostic information', ({ + context: { err }, + }) => { + const diagnostics = (err as TSError).diagnostics; + + expect(diagnostics).toHaveLength(1); + expect(diagnostics[0]).toMatchObject({ + code: 2345, + start: 10, + length: 3, + messageText: + "Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'.", + }); + }); +}); diff --git a/src/test/index.spec.ts b/src/test/index.spec.ts index a5dce0acb..72faf86ea 100644 --- a/src/test/index.spec.ts +++ b/src/test/index.spec.ts @@ -31,7 +31,6 @@ import { CMD_ESM_LOADER_WITHOUT_PROJECT, EXPERIMENTAL_MODULES_FLAG, } from './helpers'; -import type { TSError } from '..'; const exec = createExec({ cwd: TEST_DIR, @@ -975,96 +974,6 @@ test.suite('ts-node', (test) => { expect(output).toMatch('var x = 10;'); }); - test('should throw errors', ({ context: { service } }) => { - let err: unknown = null; - - try { - service.compile('new Error(123)', 'test.ts'); - } catch (error) { - err = error; - } - - if (err === null) { - throw new Error('Command was expected to fail, but it succeeded.'); - } - - expect((err as Error).message).toMatch( - new RegExp( - "TS2345: Argument of type '123' " + - "is not assignable to parameter of type 'string | undefined'\\." - ) - ); - }); - - test('should throw errors with diagnostic text', ({ - context: { service }, - }) => { - let err: unknown = null; - - try { - service.compile('new Error(123)', 'test.ts'); - } catch (error) { - err = error; - } - - if (err === null) { - throw new Error('Command was expected to fail, but it succeeded.'); - } - - expect((err as TSError).diagnosticText).toMatch( - new RegExp( - "TS2345: Argument of type '123' " + - "is not assignable to parameter of type 'string | undefined'\\." - ) - ); - }); - - test('should throw errors with diagnostic codes', ({ - context: { service }, - }) => { - let err: unknown = null; - - try { - service.compile('new Error(123)', 'test.ts'); - } catch (error) { - err = error; - } - - if (err === null) { - throw new Error('Command was expected to fail, but it succeeded.'); - } - - expect((err as TSError).diagnosticCodes).toEqual([2345]); - }); - - test('should throw errors with complete diagnostic information', ({ - context: { service }, - }) => { - let err: unknown = null; - - try { - service.compile('new Error(123)', 'test.ts'); - } catch (error) { - err = error; - } - - if (err === null) { - throw new Error('Command was expected to fail, but it succeeded.'); - } - - const diagnostics = (err as TSError).diagnostics; - - expect(diagnostics).toHaveLength(1); - expect(diagnostics[0]).toMatchObject({ - code: 2345, - start: 10, - length: 3, - messageText: - "Argument of type '123' " + - "is not assignable to parameter of type 'string | undefined'.", - }); - }); - test.suite('should get type information', (test) => { test('given position of identifier', ({ context: { service } }) => { expect( From e0560d878bf84ceaab8eeadb0747a38d92e62d4d Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 14:14:25 -0400 Subject: [PATCH 05/18] lintfix --- src/test/diagnostics.spec.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index 21ceda215..f2f86c8e8 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -23,15 +23,10 @@ test.suite('TSError diagnostics', ({ context }) => { }); // TS 2.7 does not have the union type for some reason. - const diagnosticMessageRegexp = semver.lte(ts.version, '2.7.0') - ? new RegExp( - "TS2345: Argument of type '123' " + - "is not assignable to parameter of type 'string'\\." - ) - : new RegExp( - "TS2345: Argument of type '123' " + - "is not assignable to parameter of type 'string \\| undefined'\\." - ); + const diagnosticMessageRegexp = new RegExp( + "TS2345: Argument of type '123' " + + "is not assignable to parameter of type 'string'\\." + ); test('should throw errors', ({ context: { threw, err } }) => { expect(threw).toBe(true); From b5d6ef6843ccf3dc74c8dc315ac66704619c1e31 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 14:40:00 -0400 Subject: [PATCH 06/18] fix --- src/test/diagnostics.spec.ts | 54 +++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index f2f86c8e8..dbd142596 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -2,39 +2,43 @@ import type { TSError } from '..'; import { contextTsNodeUnderTest, ts } from './helpers'; import { context, expect } from './testlib'; import * as semver from 'semver'; -import { assert } from 'console'; +import { once } from 'lodash'; const test = context(contextTsNodeUnderTest); test.suite('TSError diagnostics', ({ context }) => { - const test = context(async (t) => { - return { - service: t.context.tsNodeUnderTest.create({ + const test = context( + once(async (t) => { + const service = t.context.tsNodeUnderTest.create({ compilerOptions: { target: 'es5' }, skipProject: true, - }), - }; - }).context(async (t) => { - try { - t.context.service.compile('new Error(123)', 'test.ts'); - } catch (err) { - return { threw: true, err }; - } - return { threw: false, err: undefined }; - }); - - // TS 2.7 does not have the union type for some reason. - const diagnosticMessageRegexp = new RegExp( - "TS2345: Argument of type '123' " + - "is not assignable to parameter of type 'string'\\." + }); + try { + service.compile('new Error(123)', 'test.ts'); + } catch (err) { + return { service, threw: true, err }; + } + return { service, threw: false, err: undefined }; + }) ); - test('should throw errors', ({ context: { threw, err } }) => { + const diagnosticCode = 2345; + const diagnosticMessage = semver.lte(ts.version, '2.7.0') + ? "Argument of type 'number' " + + "is not assignable to parameter of type 'string'." + : "Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'."; + const diagnosticErrorMessage = `TS${diagnosticCode}: ${diagnosticMessage}`; + + test('should throw errors', ({ log, context: { threw, err } }) => { expect(threw).toBe(true); - expect((err as Error).message).toMatch(diagnosticMessageRegexp); + expect((err as Error).message).toMatch(diagnosticErrorMessage); }); - test('should throw errors with diagnostic text', ({ context: { err } }) => { - expect((err as TSError).diagnosticText).toMatch(diagnosticMessageRegexp); + test('should throw errors with diagnostic text', ({ + log, + context: { err }, + }) => { + expect((err as TSError).diagnosticText).toMatch(diagnosticErrorMessage); }); test('should throw errors with diagnostic codes', ({ context: { err } }) => { @@ -51,9 +55,7 @@ test.suite('TSError diagnostics', ({ context }) => { code: 2345, start: 10, length: 3, - messageText: - "Argument of type '123' " + - "is not assignable to parameter of type 'string | undefined'.", + messageText: expect.stringMatching(diagnosticMessage), }); }); }); From a5f64f50e12091dd9a254eea4ad18734a5b2662f Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 18:05:45 -0400 Subject: [PATCH 07/18] bang head against wall --- .github/workflows/continuous-integration.yml | 2 +- src/test/diagnostics.spec.ts | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index fba007e2d..909148833 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -192,7 +192,7 @@ jobs: name: ts-node-packed.tgz path: tests/ - run: npm install typescript@${{ matrix.typescript }} --force - - run: npm run test-cov + - run: npm run test-cov -- --match '*TSError*' - name: Upload npm logs if: ${{ failure() }} uses: actions/upload-artifact@v1 diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index dbd142596..f9e1b416b 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -22,14 +22,17 @@ test.suite('TSError diagnostics', ({ context }) => { ); const diagnosticCode = 2345; - const diagnosticMessage = semver.lte(ts.version, '2.7.0') - ? "Argument of type 'number' " + - "is not assignable to parameter of type 'string'." - : "Argument of type '123' " + - "is not assignable to parameter of type 'string | undefined'."; + const diagnosticMessage = + semver.lte(ts.version, '2.7.0') + ? "Argument of type 'number' " + + "is not assignable to parameter of type 'string'." + : "Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'."; const diagnosticErrorMessage = `TS${diagnosticCode}: ${diagnosticMessage}`; - test('should throw errors', ({ log, context: { threw, err } }) => { + test('should throw errors', ({ log, context: { threw, err, service } }) => { + log(service.ts.version); + log(ts.version); expect(threw).toBe(true); expect((err as Error).message).toMatch(diagnosticErrorMessage); }); From 47f769ba7d7161651e106ad02b29b5840e787175 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 18:08:14 -0400 Subject: [PATCH 08/18] lintfix --- src/test/diagnostics.spec.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index f9e1b416b..bb79d0850 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -22,12 +22,11 @@ test.suite('TSError diagnostics', ({ context }) => { ); const diagnosticCode = 2345; - const diagnosticMessage = - semver.lte(ts.version, '2.7.0') - ? "Argument of type 'number' " + - "is not assignable to parameter of type 'string'." - : "Argument of type '123' " + - "is not assignable to parameter of type 'string | undefined'."; + const diagnosticMessage = semver.lte(ts.version, '2.7.0') + ? "Argument of type 'number' " + + "is not assignable to parameter of type 'string'." + : "Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'."; const diagnosticErrorMessage = `TS${diagnosticCode}: ${diagnosticMessage}`; test('should throw errors', ({ log, context: { threw, err, service } }) => { From 992796b32326d14caf3ed0a4a69044ea2f064c7c Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 19:08:56 -0400 Subject: [PATCH 09/18] fix --- ava.config.cjs | 2 +- src/test/diagnostics.spec.ts | 11 ++++------- src/test/init.ts | 3 +++ src/test/pluggable-dep-resolution.spec.ts | 3 ++- src/test/remove-env-var-force-color.js | 1 - 5 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 src/test/init.ts delete mode 100644 src/test/remove-env-var-force-color.js diff --git a/ava.config.cjs b/ava.config.cjs index aa04b33bf..42bc69a63 100644 --- a/ava.config.cjs +++ b/ava.config.cjs @@ -12,7 +12,7 @@ module.exports = { // their behavior. FORCE_COLOR: '3', }, - require: ['./src/test/remove-env-var-force-color.js'], + require: ['./dist/test/init.js'], timeout: '300s', concurrency: 1, }; diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index bb79d0850..86c000be5 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -15,9 +15,9 @@ test.suite('TSError diagnostics', ({ context }) => { try { service.compile('new Error(123)', 'test.ts'); } catch (err) { - return { service, threw: true, err }; + return { service, err }; } - return { service, threw: false, err: undefined }; + return { service, err: undefined }; }) ); @@ -29,15 +29,12 @@ test.suite('TSError diagnostics', ({ context }) => { "is not assignable to parameter of type 'string | undefined'."; const diagnosticErrorMessage = `TS${diagnosticCode}: ${diagnosticMessage}`; - test('should throw errors', ({ log, context: { threw, err, service } }) => { - log(service.ts.version); - log(ts.version); - expect(threw).toBe(true); + test('should throw errors', ({ context: { err } }) => { + expect(err).toBeDefined(); expect((err as Error).message).toMatch(diagnosticErrorMessage); }); test('should throw errors with diagnostic text', ({ - log, context: { err }, }) => { expect((err as TSError).diagnosticText).toMatch(diagnosticErrorMessage); diff --git a/src/test/init.ts b/src/test/init.ts new file mode 100644 index 000000000..dd755ea86 --- /dev/null +++ b/src/test/init.ts @@ -0,0 +1,3 @@ +// Initialize runtime for tests +delete process.env.FORCE_COLOR; +process.chdir(require('./helpers').TEST_DIR); diff --git a/src/test/pluggable-dep-resolution.spec.ts b/src/test/pluggable-dep-resolution.spec.ts index 95504351b..7521c5d3a 100644 --- a/src/test/pluggable-dep-resolution.spec.ts +++ b/src/test/pluggable-dep-resolution.spec.ts @@ -2,6 +2,7 @@ import { context } from './testlib'; import { contextTsNodeUnderTest, resetNodeEnvironment, + TEST_DIR, tsSupportsTsconfigInheritanceViaNodePackages, } from './helpers'; import * as expect from 'expect'; @@ -87,7 +88,7 @@ test.suite( const output = t.context.tsNodeUnderTest .create({ - project: resolve('tests/pluggable-dep-resolution', config), + project: resolve(TEST_DIR, 'pluggable-dep-resolution', config), }) .compile('', 'index.ts'); diff --git a/src/test/remove-env-var-force-color.js b/src/test/remove-env-var-force-color.js deleted file mode 100644 index ebbb349b3..000000000 --- a/src/test/remove-env-var-force-color.js +++ /dev/null @@ -1 +0,0 @@ -delete process.env.FORCE_COLOR; From 52fcbda069cc4d5221353113e2bef671e97fb522 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 19:12:06 -0400 Subject: [PATCH 10/18] fix --- src/test/diagnostics.spec.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index 86c000be5..523e37e0d 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -34,9 +34,7 @@ test.suite('TSError diagnostics', ({ context }) => { expect((err as Error).message).toMatch(diagnosticErrorMessage); }); - test('should throw errors with diagnostic text', ({ - context: { err }, - }) => { + test('should throw errors with diagnostic text', ({ context: { err } }) => { expect((err as TSError).diagnosticText).toMatch(diagnosticErrorMessage); }); From 5143a48e88bcf55cf2f82c747a8a5230e4b567f8 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 20:30:48 -0400 Subject: [PATCH 11/18] fix --- src/test/diagnostics.spec.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index 523e37e0d..38208bc57 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -3,6 +3,7 @@ import { contextTsNodeUnderTest, ts } from './helpers'; import { context, expect } from './testlib'; import * as semver from 'semver'; import { once } from 'lodash'; +import { servicesVersion } from 'typescript'; const test = context(contextTsNodeUnderTest); test.suite('TSError diagnostics', ({ context }) => { @@ -29,7 +30,12 @@ test.suite('TSError diagnostics', ({ context }) => { "is not assignable to parameter of type 'string | undefined'."; const diagnosticErrorMessage = `TS${diagnosticCode}: ${diagnosticMessage}`; - test('should throw errors', ({ context: { err } }) => { + test('should throw errors', ({ log, context: { err, service } }) => { + log({ + version: ts.version, + serviceVersion: service.ts.version, + cwd: process.cwd(), + }); expect(err).toBeDefined(); expect((err as Error).message).toMatch(diagnosticErrorMessage); }); From 9a0d0713eee5e07c700e8e57bdb66de5f9012e32 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 20:58:50 -0400 Subject: [PATCH 12/18] fix --- src/test/diagnostics.spec.ts | 5 ++++- src/test/helpers.ts | 2 ++ src/test/init.ts | 1 - src/test/testlib.ts | 3 +++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index 38208bc57..22f9d3cab 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -3,7 +3,6 @@ import { contextTsNodeUnderTest, ts } from './helpers'; import { context, expect } from './testlib'; import * as semver from 'semver'; import { once } from 'lodash'; -import { servicesVersion } from 'typescript'; const test = context(contextTsNodeUnderTest); test.suite('TSError diagnostics', ({ context }) => { @@ -30,11 +29,15 @@ test.suite('TSError diagnostics', ({ context }) => { "is not assignable to parameter of type 'string | undefined'."; const diagnosticErrorMessage = `TS${diagnosticCode}: ${diagnosticMessage}`; + const cwdBefore = process.cwd(); test('should throw errors', ({ log, context: { err, service } }) => { log({ version: ts.version, serviceVersion: service.ts.version, + cwdBefore, cwd: process.cwd(), + configFilePath: service.configFilePath, + config: service.config.options, }); expect(err).toBeDefined(); expect((err as Error).message).toMatch(diagnosticErrorMessage); diff --git a/src/test/helpers.ts b/src/test/helpers.ts index bdddc21f4..d9bf827af 100644 --- a/src/test/helpers.ts +++ b/src/test/helpers.ts @@ -30,6 +30,8 @@ export const BIN_SCRIPT_PATH = join( ); export const BIN_CWD_PATH = join(TEST_DIR, 'node_modules/.bin/ts-node-cwd'); export const BIN_ESM_PATH = join(TEST_DIR, 'node_modules/.bin/ts-node-esm'); + +process.chdir(TEST_DIR); //#endregion //#region command lines diff --git a/src/test/init.ts b/src/test/init.ts index dd755ea86..16391813e 100644 --- a/src/test/init.ts +++ b/src/test/init.ts @@ -1,3 +1,2 @@ // Initialize runtime for tests delete process.env.FORCE_COLOR; -process.chdir(require('./helpers').TEST_DIR); diff --git a/src/test/testlib.ts b/src/test/testlib.ts index 6304164bb..31659fc70 100644 --- a/src/test/testlib.ts +++ b/src/test/testlib.ts @@ -15,6 +15,9 @@ import * as expect from 'expect'; export { ExecutionContext, expect }; +// HACK ensure ts-node-specific bootstrapping is executed +import './helpers'; + // NOTE: this limits concurrency within a single process, but AVA launches // each .spec file in its own process, so actual concurrency is higher. const concurrencyLimiter = throat(16); From 08a95c6b5fc625b59e9c32c3720b1f21038ee618 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 21:12:56 -0400 Subject: [PATCH 13/18] fix --- package-lock.json | 18 +++++++++++++++--- package.json | 2 +- src/test/diagnostics.spec.ts | 11 ++++++----- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 19319b310..887f218bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -438,6 +438,12 @@ "requires": { "lru-cache": "^6.0.0" } + }, + "typescript": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "dev": true } } }, @@ -4669,9 +4675,9 @@ } }, "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", + "integrity": "sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==", "dev": true }, "typescript-json-schema": { @@ -4708,6 +4714,12 @@ "once": "^1.3.0", "path-is-absolute": "^1.0.0" } + }, + "typescript": { + "version": "4.5.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", + "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "dev": true } } }, diff --git a/package.json b/package.json index 1f158f1fb..48fa3a519 100644 --- a/package.json +++ b/package.json @@ -139,7 +139,7 @@ "semver": "^7.1.3", "throat": "^6.0.1", "typedoc": "^0.22.10", - "typescript": "4.5.5", + "typescript": "4.6.3", "typescript-json-schema": "^0.53.0", "util.promisify": "^1.0.1" }, diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index 22f9d3cab..906481608 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -22,11 +22,12 @@ test.suite('TSError diagnostics', ({ context }) => { ); const diagnosticCode = 2345; - const diagnosticMessage = semver.lte(ts.version, '2.7.0') - ? "Argument of type 'number' " + - "is not assignable to parameter of type 'string'." - : "Argument of type '123' " + - "is not assignable to parameter of type 'string | undefined'."; + const diagnosticMessage = + semver.lte(ts.version, '2.7.0') || true + ? "Argument of type 'number' " + + "is not assignable to parameter of type 'string'." + : "Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'."; const diagnosticErrorMessage = `TS${diagnosticCode}: ${diagnosticMessage}`; const cwdBefore = process.cwd(); From 30b78bd16c112cfc4bd2c8f43736b8b01208478e Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 23:06:05 -0400 Subject: [PATCH 14/18] tweaks --- justfile | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 justfile diff --git a/justfile b/justfile new file mode 100644 index 000000000..37aaf3178 --- /dev/null +++ b/justfile @@ -0,0 +1,66 @@ +# I like using `just` instead of `npm run` or `yarn`. +# If you're like me, this justfile is for you. +# If you are not, you can safely ignore this file. + +set positional-arguments +export PATH := justfile_directory() + "/node_modules/.bin:" + env_var('PATH') + +default: test-local + +regenerate: + #!/usr/bin/env sh + node -e ' + const fs = require("fs"); + let acc = fs.readFileSync("justfile", "utf8").replace(/(# CUT\n)[\s\S]+/, "$1\n"); + for(const [key, value] of Object.entries(require("./package.json").scripts)) { + acc += `${key} *ARGS:\n ${value.replace(/npm run /g, "just ").replace(/ --$/, "")} "$@"\n`; + } + fs.writeFileSync("justfile", acc); + ' + +install: + npm install + +# EVERYTHING BELOW THIS LINE IS AUTO-GENERATED FROM PACKAGE.JSON +# DO NOT MODIFY BY HAND + +# CUT + +lint *ARGS: + prettier --check . "$@" +lint-fix *ARGS: + prettier --write . "$@" +clean *ARGS: + rimraf dist tsconfig.schema.json tsconfig.schemastore-schema.json tsconfig.tsbuildinfo tests/ts-node-packed.tgz "$@" +rebuild *ARGS: + just clean && just build "$@" +build *ARGS: + just build-nopack && just build-pack "$@" +build-nopack *ARGS: + just build-tsc && just build-configSchema "$@" +build-tsc *ARGS: + tsc "$@" +build-configSchema *ARGS: + typescript-json-schema --topRef --refs --validationKeywords allOf --out tsconfig.schema.json tsconfig.build-schema.json TsConfigSchema && node --require ./register ./scripts/create-merged-schema "$@" +build-pack *ARGS: + node ./scripts/build-pack.js "$@" +test-spec *ARGS: + ava "$@" +test-cov *ARGS: + nyc ava "$@" +test *ARGS: + just build && just lint && just test-cov "$@" +test-local *ARGS: + just lint-fix && just build-tsc && just build-pack && just test-spec "$@" +pre-debug *ARGS: + just build-tsc && just build-pack "$@" +coverage-report *ARGS: + nyc report --reporter=lcov "$@" +prepare *ARGS: + just clean && just build-nopack "$@" +api-extractor *ARGS: + api-extractor run --local --verbose "$@" +esm-usage-example *ARGS: + just build-tsc && cd esm-usage-example && node --experimental-specifier-resolution node --loader ../esm.mjs ./index "$@" +esm-usage-example2 *ARGS: + just build-tsc && cd tests && TS_NODE_PROJECT=./module-types/override-to-cjs/tsconfig.json node --loader ../esm.mjs ./module-types/override-to-cjs/test.cjs "$@" From 217e955a27891c341917e8269bd8e3b000b777a8 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sat, 16 Apr 2022 23:06:38 -0400 Subject: [PATCH 15/18] Revert "tweaks" This reverts commit 30b78bd16c112cfc4bd2c8f43736b8b01208478e. --- justfile | 66 -------------------------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 justfile diff --git a/justfile b/justfile deleted file mode 100644 index 37aaf3178..000000000 --- a/justfile +++ /dev/null @@ -1,66 +0,0 @@ -# I like using `just` instead of `npm run` or `yarn`. -# If you're like me, this justfile is for you. -# If you are not, you can safely ignore this file. - -set positional-arguments -export PATH := justfile_directory() + "/node_modules/.bin:" + env_var('PATH') - -default: test-local - -regenerate: - #!/usr/bin/env sh - node -e ' - const fs = require("fs"); - let acc = fs.readFileSync("justfile", "utf8").replace(/(# CUT\n)[\s\S]+/, "$1\n"); - for(const [key, value] of Object.entries(require("./package.json").scripts)) { - acc += `${key} *ARGS:\n ${value.replace(/npm run /g, "just ").replace(/ --$/, "")} "$@"\n`; - } - fs.writeFileSync("justfile", acc); - ' - -install: - npm install - -# EVERYTHING BELOW THIS LINE IS AUTO-GENERATED FROM PACKAGE.JSON -# DO NOT MODIFY BY HAND - -# CUT - -lint *ARGS: - prettier --check . "$@" -lint-fix *ARGS: - prettier --write . "$@" -clean *ARGS: - rimraf dist tsconfig.schema.json tsconfig.schemastore-schema.json tsconfig.tsbuildinfo tests/ts-node-packed.tgz "$@" -rebuild *ARGS: - just clean && just build "$@" -build *ARGS: - just build-nopack && just build-pack "$@" -build-nopack *ARGS: - just build-tsc && just build-configSchema "$@" -build-tsc *ARGS: - tsc "$@" -build-configSchema *ARGS: - typescript-json-schema --topRef --refs --validationKeywords allOf --out tsconfig.schema.json tsconfig.build-schema.json TsConfigSchema && node --require ./register ./scripts/create-merged-schema "$@" -build-pack *ARGS: - node ./scripts/build-pack.js "$@" -test-spec *ARGS: - ava "$@" -test-cov *ARGS: - nyc ava "$@" -test *ARGS: - just build && just lint && just test-cov "$@" -test-local *ARGS: - just lint-fix && just build-tsc && just build-pack && just test-spec "$@" -pre-debug *ARGS: - just build-tsc && just build-pack "$@" -coverage-report *ARGS: - nyc report --reporter=lcov "$@" -prepare *ARGS: - just clean && just build-nopack "$@" -api-extractor *ARGS: - api-extractor run --local --verbose "$@" -esm-usage-example *ARGS: - just build-tsc && cd esm-usage-example && node --experimental-specifier-resolution node --loader ../esm.mjs ./index "$@" -esm-usage-example2 *ARGS: - just build-tsc && cd tests && TS_NODE_PROJECT=./module-types/override-to-cjs/tsconfig.json node --loader ../esm.mjs ./module-types/override-to-cjs/test.cjs "$@" From 715d3ac0d9704426007c203c8cfc1b8ca4fca550 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sun, 17 Apr 2022 00:16:27 -0400 Subject: [PATCH 16/18] fix --- src/test/diagnostics.spec.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/test/diagnostics.spec.ts b/src/test/diagnostics.spec.ts index 906481608..79771564c 100644 --- a/src/test/diagnostics.spec.ts +++ b/src/test/diagnostics.spec.ts @@ -22,12 +22,11 @@ test.suite('TSError diagnostics', ({ context }) => { ); const diagnosticCode = 2345; - const diagnosticMessage = - semver.lte(ts.version, '2.7.0') || true - ? "Argument of type 'number' " + - "is not assignable to parameter of type 'string'." - : "Argument of type '123' " + - "is not assignable to parameter of type 'string | undefined'."; + const diagnosticMessage = semver.satisfies(ts.version, '2.7') + ? "Argument of type '123' " + + "is not assignable to parameter of type 'string | undefined'." + : "Argument of type 'number' " + + "is not assignable to parameter of type 'string'."; const diagnosticErrorMessage = `TS${diagnosticCode}: ${diagnosticMessage}`; const cwdBefore = process.cwd(); From cd107ed363f73fe0b553ac50575cc5f5d6e85ce0 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sun, 17 Apr 2022 00:18:47 -0400 Subject: [PATCH 17/18] finally --- .github/workflows/continuous-integration.yml | 2 +- ava.config.cjs | 2 +- src/test/{init.ts => remove-env-var-force-color.js} | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) rename src/test/{init.ts => remove-env-var-force-color.js} (50%) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 909148833..fba007e2d 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -192,7 +192,7 @@ jobs: name: ts-node-packed.tgz path: tests/ - run: npm install typescript@${{ matrix.typescript }} --force - - run: npm run test-cov -- --match '*TSError*' + - run: npm run test-cov - name: Upload npm logs if: ${{ failure() }} uses: actions/upload-artifact@v1 diff --git a/ava.config.cjs b/ava.config.cjs index 42bc69a63..aa04b33bf 100644 --- a/ava.config.cjs +++ b/ava.config.cjs @@ -12,7 +12,7 @@ module.exports = { // their behavior. FORCE_COLOR: '3', }, - require: ['./dist/test/init.js'], + require: ['./src/test/remove-env-var-force-color.js'], timeout: '300s', concurrency: 1, }; diff --git a/src/test/init.ts b/src/test/remove-env-var-force-color.js similarity index 50% rename from src/test/init.ts rename to src/test/remove-env-var-force-color.js index 16391813e..ebbb349b3 100644 --- a/src/test/init.ts +++ b/src/test/remove-env-var-force-color.js @@ -1,2 +1 @@ -// Initialize runtime for tests delete process.env.FORCE_COLOR; From b6e01c8025dbb9120698e7991f21c317d5be8f09 Mon Sep 17 00:00:00 2001 From: Andrew Bradley Date: Sun, 17 Apr 2022 01:21:00 -0400 Subject: [PATCH 18/18] fix --- package.json | 2 +- src/test/repl/repl-environment.spec.ts | 7 +++---- src/test/repl/repl.spec.ts | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 48fa3a519..131049632 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ ], "scripts": { "lint": "prettier --check .", - "lint-fix": "prettier --write .", + "lint-fix": "prettier --loglevel warn --write .", "clean": "rimraf dist tsconfig.schema.json tsconfig.schemastore-schema.json tsconfig.tsbuildinfo tests/ts-node-packed.tgz", "rebuild": "npm run clean && npm run build", "build": "npm run build-nopack && npm run build-pack", diff --git a/src/test/repl/repl-environment.spec.ts b/src/test/repl/repl-environment.spec.ts index f54d2030e..50c68255f 100644 --- a/src/test/repl/repl-environment.spec.ts +++ b/src/test/repl/repl-environment.spec.ts @@ -137,7 +137,6 @@ test.suite( /** Every possible ./node_modules directory ascending upwards starting with ./tests/node_modules */ const modulePaths = createModulePaths(TEST_DIR); - const rootModulePaths = createModulePaths(ROOT_DIR); function createModulePaths(dir: string) { const modulePaths: string[] = []; for (let path = dir; ; path = dirname(path)) { @@ -430,7 +429,7 @@ test.suite( // Note: vanilla node uses different name. See #1360 stackTest: expect.stringContaining( - ` at ${join(ROOT_DIR, '.ts')}:1:` + ` at ${join(TEST_DIR, '.ts')}:1:` ), }, }); @@ -455,13 +454,13 @@ test.suite( modulePath: '.', moduleFilename: null, modulePaths: expect.objectContaining({ - ...[join(ROOT_DIR, `repl/node_modules`), ...rootModulePaths], + ...[join(TEST_DIR, `repl/node_modules`), ...modulePaths], }), // Note: vanilla node REPL does not set exports exportsTest: true, // Note: vanilla node uses different name. See #1360 stackTest: expect.stringContaining( - ` at ${join(ROOT_DIR, '.ts')}:1:` + ` at ${join(TEST_DIR, '.ts')}:1:` ), moduleAccessorsTest: true, }, diff --git a/src/test/repl/repl.spec.ts b/src/test/repl/repl.spec.ts index d23ed445e..40ea33fc5 100644 --- a/src/test/repl/repl.spec.ts +++ b/src/test/repl/repl.spec.ts @@ -246,13 +246,13 @@ test.suite('top level await', (_test) => { 'should error with typing information when importing a file with type errors', async (t) => { const { stdout, stderr } = await t.context.executeInTlaRepl( - `const {foo} = await import('./tests/repl/tla-import');`, + `const {foo} = await import('./repl/tla-import');`, 'error' ); expect(stdout).toBe('> > '); expect(stderr.replace(/\r\n/g, '\n')).toBe( - 'tests/repl/tla-import.ts(1,14): error TS2322: ' + + 'repl/tla-import.ts(1,14): error TS2322: ' + (semver.gte(ts.version, '4.0.0') ? `Type 'number' is not assignable to type 'string'.\n` : `Type '1' is not assignable to type 'string'.\n`) +