Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion deps/amaro/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ console.log(code); // "const foo = 'bar';"

It is possible to use Amaro as an external loader to execute TypeScript files.
This allows the installed Amaro to override the Amaro version used by Node.js.
In order to use Amaro as an external loader, type stripping needs to be enabled.

```bash
node --experimental-strip-types --import="amaro/register" script.ts
Expand All @@ -51,7 +52,7 @@ node --experimental-transform-types --import="amaro/transform" script.ts

### TypeScript Version

The supported TypeScript version is 5.5.4, except the stage 3 decorator proposal.
The supported TypeScript version is 5.8.

## License (MIT)

Expand Down
9 changes: 7 additions & 2 deletions deps/amaro/dist/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ export function isSwcError(error) {
return error.code !== void 0;
}
export function wrapAndReThrowSwcError(error) {
const errorHints = `${error.filename}:${error.startLine}${error.snippet}`;
switch (error.code) {
case "UnsupportedSyntax": {
const unsupportedSyntaxError = new Error(error.message);
unsupportedSyntaxError.name = "UnsupportedSyntaxError";
unsupportedSyntaxError.stack = `${errorHints}${unsupportedSyntaxError.stack}`;
throw unsupportedSyntaxError;
}
case "InvalidSyntax":
throw new SyntaxError(error.message);
case "InvalidSyntax": {
const syntaxError = new SyntaxError(error.message);
syntaxError.stack = `${errorHints}${syntaxError.stack}`;
throw syntaxError;
}
default:
throw new Error(error.message);
}
Expand Down
27 changes: 21 additions & 6 deletions deps/amaro/dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion deps/amaro/dist/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"강동윤 <[email protected]>"
],
"description": "wasm module for swc",
"version": "1.11.5",
"version": "1.11.12",
"license": "Apache-2.0",
"repository": {
"type": "git",
Expand Down
6 changes: 3 additions & 3 deletions deps/amaro/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "amaro",
"version": "0.4.1",
"version": "0.5.0",
"description": "Node.js TypeScript wrapper",
"license": "MIT",
"type": "commonjs",
Expand All @@ -24,8 +24,8 @@
"build": "node esbuild.config.mjs",
"build:wasm": "node tools/build-wasm.js",
"typecheck": "tsc --noEmit",
"test": "node --test --experimental-test-snapshots \"**/*.test.js\"",
"test:regenerate": "node --test --experimental-test-snapshots --test-update-snapshots \"**/*.test.js\""
"test": "node --test \"**/*.test.js\"",
"test:regenerate": "node --test --test-update-snapshots \"**/*.test.js\""
},
"devDependencies": {
"@biomejs/biome": "1.8.3",
Expand Down
24 changes: 20 additions & 4 deletions lib/internal/modules/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,14 @@ function parseTypeScript(source, options) {
* It allows us to distinguish between invalid syntax and unsupported syntax.
*/
switch (error?.code) {
case 'UnsupportedSyntax':
throw new ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX(error.message);
case 'InvalidSyntax':
throw new ERR_INVALID_TYPESCRIPT_SYNTAX(error.message);
case 'UnsupportedSyntax': {
const unsupportedSyntaxError = new ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX(error.message);
throw decorateErrorWithSnippet(unsupportedSyntaxError, error); /* node-do-not-add-exception-line */
}
case 'InvalidSyntax': {
const invalidSyntaxError = new ERR_INVALID_TYPESCRIPT_SYNTAX(error.message);
throw decorateErrorWithSnippet(invalidSyntaxError, error); /* node-do-not-add-exception-line */
}
default:
// SWC may throw strings when something goes wrong.
if (typeof error === 'string') { assert.fail(error); }
Expand All @@ -76,6 +80,18 @@ function parseTypeScript(source, options) {
}
}

/**
*
* @param {Error} error the error to decorate: ERR_INVALID_TYPESCRIPT_SYNTAX, ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX
* @param {object} amaroError the error object from amaro
* @returns {Error} the decorated error
*/
function decorateErrorWithSnippet(error, amaroError) {
const errorHints = `${amaroError.filename}:${amaroError.startLine}${amaroError.snippet}`;
error.stack = `${errorHints}${error.stack}`;
return error;
}

/**
* Performs type-stripping to TypeScript source code.
* @param {string} code TypeScript code to parse.
Expand Down
10 changes: 6 additions & 4 deletions lib/internal/process/execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ const { emitExperimentalWarning } = require('internal/util');
// communication with JS.
const { shouldAbortOnUncaughtToggle } = internalBinding('util');

const kEvalTag = '[eval]';

function tryGetCwd() {
try {
return process.cwd();
Expand Down Expand Up @@ -259,7 +261,7 @@ function evalTypeScript(name, source, breakFirstLine, print, shouldLoadESM = fal
compiledScript = compileScript(name, source, baseUrl);
} catch (originalError) {
try {
sourceToRun = stripTypeScriptModuleTypes(source, name, false);
sourceToRun = stripTypeScriptModuleTypes(source, kEvalTag, false);
// Retry the CJS/ESM syntax detection after stripping the types.
if (shouldUseModuleEntryPoint(name, sourceToRun)) {
return evalTypeScriptModuleEntryPoint(source, print);
Expand Down Expand Up @@ -322,7 +324,7 @@ function evalTypeScriptModuleEntryPoint(source, print) {
moduleWrap = loader.createModuleWrap(source, url);
} catch (originalError) {
try {
const strippedSource = stripTypeScriptModuleTypes(source, url, false);
const strippedSource = stripTypeScriptModuleTypes(source, kEvalTag, false);
// If the moduleWrap was successfully created, execute the module job.
// outside the try-catch block to avoid catching runtime errors.
moduleWrap = loader.createModuleWrap(strippedSource, url);
Expand Down Expand Up @@ -355,7 +357,7 @@ function evalTypeScriptModuleEntryPoint(source, print) {
*/
function parseAndEvalModuleTypeScript(source, print) {
// We know its a TypeScript module, we can safely emit the experimental warning.
const strippedSource = stripTypeScriptModuleTypes(source, getEvalModuleUrl());
const strippedSource = stripTypeScriptModuleTypes(source, kEvalTag);
evalModuleEntryPoint(strippedSource, print);
}

Expand All @@ -370,7 +372,7 @@ function parseAndEvalModuleTypeScript(source, print) {
*/
function parseAndEvalCommonjsTypeScript(name, source, breakFirstLine, print, shouldLoadESM = false) {
// We know its a TypeScript module, we can safely emit the experimental warning.
const strippedSource = stripTypeScriptModuleTypes(source, getEvalModuleUrl());
const strippedSource = stripTypeScriptModuleTypes(source, kEvalTag);
evalScript(name, strippedSource, breakFirstLine, print, shouldLoadESM);
}

Expand Down
2 changes: 1 addition & 1 deletion src/amaro_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
// Refer to tools/dep_updaters/update-amaro.sh
#ifndef SRC_AMARO_VERSION_H_
#define SRC_AMARO_VERSION_H_
#define AMARO_VERSION "0.4.1"
#define AMARO_VERSION "0.5.0"
#endif // SRC_AMARO_VERSION_H_
20 changes: 20 additions & 0 deletions test/es-module/test-typescript-eval.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,23 @@ test('should not allow declare module keyword', async () => {
match(result.stderr, /ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX/);
strictEqual(result.code, 1);
});

// TODO (marco-ippolito) Remove the extra padding from the error message
// The padding comes from swc it will be removed in a future amaro release
test('the error message should not contain extra padding', async () => {
const result = await spawnPromisified(process.execPath, [
'--input-type=module-typescript',
'--eval',
'declare module F { export type x = number }']);
strictEqual(result.stdout, '');
// Windows uses \r\n as line endings
const lines = result.stderr.replace(/\r\n/g, '\n').split('\n');
// The extra padding at the end should not be present
strictEqual(lines[0], '[eval]:1 ');
// The extra padding at the beginning should not be present
strictEqual(lines[2], ' declare module F { export type x = number }');
strictEqual(lines[3], ' ^^^^^^^^');
strictEqual(lines[5], 'SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]:' +
' `module` keyword is not supported. Use `namespace` instead.');
strictEqual(result.code, 1);
});
6 changes: 1 addition & 5 deletions test/fixtures/eval/eval_messages.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
[eval]:1
with(this){__filename}
^^^^
x The 'with' statement is not supported. All symbols in a 'with' block will have type 'any'.
,----
1 | with(this){__filename}
: ^^^^
`----
The 'with' statement is not supported. All symbols in a 'with' block will have type 'any'.

SyntaxError: Strict mode code may not include a with statement

Expand Down
24 changes: 4 additions & 20 deletions test/fixtures/eval/eval_typescript.snapshot
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
[eval]:1
enum Foo{};
^^^^
x TypeScript enum is not supported in strip-only mode
,----
1 | enum Foo{};
: ^^^^^^^^^^
`----
TypeScript enum is not supported in strip-only mode

SyntaxError: Unexpected reserved word

Expand All @@ -20,11 +16,7 @@ Node.js *
[eval]:1
const foo;
^^^
x 'const' declarations must be initialized
,----
1 | const foo;
: ^^^
`----
'const' declarations must be initialized

SyntaxError: Missing initializer in const declaration

Expand All @@ -35,23 +27,15 @@ false
[eval]:1
interface Foo{};const foo;
^^^
x 'const' declarations must be initialized
,----
1 | interface Foo{};const foo;
: ^^^
`----
'const' declarations must be initialized

SyntaxError: Unexpected identifier 'Foo'

Node.js *
[eval]:1
function foo(){ await Promise.resolve(1)};
^^^^^
x await isn't allowed in non-async function
,----
1 | function foo(){ await Promise.resolve(1)};
: ^^^^^^^
`----
await isn't allowed in non-async function

SyntaxError: await is only valid in async functions and the top level bodies of modules

Expand Down
6 changes: 1 addition & 5 deletions test/fixtures/eval/stdin_messages.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@
[stdin]:1
with(this){__filename}
^^^^
x The 'with' statement is not supported. All symbols in a 'with' block will have type 'any'.
,----
1 | with(this){__filename}
: ^^^^
`----
The 'with' statement is not supported. All symbols in a 'with' block will have type 'any'.

SyntaxError: Strict mode code may not include a with statement

Expand Down
48 changes: 8 additions & 40 deletions test/fixtures/eval/stdin_typescript.snapshot
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
[stdin]:1
enum Foo{};
^^^^
x TypeScript enum is not supported in strip-only mode
,----
1 | enum Foo{};
: ^^^^^^^^^^
`----
TypeScript enum is not supported in strip-only mode

SyntaxError: Unexpected reserved word

Node.js *
[stdin]:1
enum Foo{};
^^^^
x TypeScript enum is not supported in strip-only mode
,----
1 | enum Foo{};
: ^^^^^^^^^^
`----
TypeScript enum is not supported in strip-only mode

SyntaxError: Unexpected reserved word

Expand All @@ -39,23 +31,15 @@ Node.js *
[stdin]:1
const foo;
^^^
x 'const' declarations must be initialized
,----
1 | const foo;
: ^^^
`----
'const' declarations must be initialized

SyntaxError: Missing initializer in const declaration

Node.js *
[stdin]:1
const foo;
^^^
x 'const' declarations must be initialized
,----
1 | const foo;
: ^^^
`----
'const' declarations must be initialized

SyntaxError: Missing initializer in const declaration

Expand All @@ -69,47 +53,31 @@ false
[stdin]:1
interface Foo{};const foo;
^^^
x 'const' declarations must be initialized
,----
1 | interface Foo{};const foo;
: ^^^
`----
'const' declarations must be initialized

SyntaxError: Unexpected identifier 'Foo'

Node.js *
[stdin]:1
interface Foo{};const foo;
^^^^^^^^^
x 'const' declarations must be initialized
,----
1 | interface Foo{};const foo;
: ^^^
`----
'const' declarations must be initialized

SyntaxError: Unexpected strict mode reserved word

Node.js *
[stdin]:1
function foo(){ await Promise.resolve(1)};
^^^^^
x await isn't allowed in non-async function
,----
1 | function foo(){ await Promise.resolve(1)};
: ^^^^^^^
`----
await isn't allowed in non-async function

SyntaxError: await is only valid in async functions and the top level bodies of modules

Node.js *
[stdin]:1
function foo(){ await Promise.resolve(1)};
^^^^^
x await isn't allowed in non-async function
,----
1 | function foo(){ await Promise.resolve(1)};
: ^^^^^^^
`----
await isn't allowed in non-async function

SyntaxError: await is only valid in async functions and the top level bodies of modules

Expand Down
Loading