diff --git a/doc/api/errors.md b/doc/api/errors.md
index 0298c2b1e22163..127872221c0f72 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -2094,6 +2094,18 @@ An element in the `iterable` provided to the [WHATWG][WHATWG URL API]
represent a `[name, value]` tuple – that is, if an element is not iterable, or
does not consist of exactly two elements.
+
+
+### `ERR_INVALID_TYPESCRIPT_SYNTAX`
+
+
+
+The provided TypeScript syntax is not valid or unsupported.
+This could happen when using TypeScript syntax that requires
+transformation with [type-stripping][].
+
### `ERR_INVALID_URI`
@@ -4203,4 +4215,5 @@ An error occurred trying to allocate memory. This should never happen.
[stream-based]: stream.md
[syscall]: https://man7.org/linux/man-pages/man2/syscalls.2.html
[try-catch]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch
+[type-stripping]: typescript.md#type-stripping
[vm]: vm.md
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index e1228176a2d101..29c0b607746023 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1524,6 +1524,7 @@ E('ERR_INVALID_SYNC_FORK_INPUT',
TypeError);
E('ERR_INVALID_THIS', 'Value of "this" must be of type %s', TypeError);
E('ERR_INVALID_TUPLE', '%s must be an iterable %s tuple', TypeError);
+E('ERR_INVALID_TYPESCRIPT_SYNTAX', '%s', SyntaxError);
E('ERR_INVALID_URI', 'URI malformed', URIError);
E('ERR_INVALID_URL', function(input, base = null) {
this.input = input;
diff --git a/lib/internal/modules/helpers.js b/lib/internal/modules/helpers.js
index feec9f4957e7ab..6c13ed3ff5fdd0 100644
--- a/lib/internal/modules/helpers.js
+++ b/lib/internal/modules/helpers.js
@@ -15,6 +15,7 @@ const {
const {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_RETURN_PROPERTY_VALUE,
+ ERR_INVALID_TYPESCRIPT_SYNTAX,
} = require('internal/errors').codes;
const { BuiltinModule } = require('internal/bootstrap/realm');
@@ -312,44 +313,37 @@ function getBuiltinModule(id) {
return normalizedId ? require(normalizedId) : undefined;
}
-/**
- * TypeScript parsing function, by default Amaro.transformSync.
- * @type {Function}
- */
-let typeScriptParser;
/**
* The TypeScript parsing mode, either 'strip-only' or 'transform'.
* @type {string}
*/
-let typeScriptParsingMode;
-/**
- * Whether source maps are enabled for TypeScript parsing.
- * @type {boolean}
- */
-let sourceMapEnabled;
+const getTypeScriptParsingMode = getLazy(() =>
+ (getOptionValue('--experimental-transform-types') ? 'transform' : 'strip-only'),
+);
/**
* Load the TypeScript parser.
- * @param {Function} parser - A function that takes a string of TypeScript code
* and returns an object with a `code` property.
* @returns {Function} The TypeScript parser function.
*/
-function loadTypeScriptParser(parser) {
- if (typeScriptParser) {
- return typeScriptParser;
- }
+const loadTypeScriptParser = getLazy(() => {
+ const amaro = require('internal/deps/amaro/dist/index');
+ return amaro.transformSync;
+});
- if (parser) {
- typeScriptParser = parser;
- } else {
- const amaro = require('internal/deps/amaro/dist/index');
- // Default option for Amaro is to perform Type Stripping only.
- typeScriptParsingMode = getOptionValue('--experimental-transform-types') ? 'transform' : 'strip-only';
- sourceMapEnabled = getOptionValue('--enable-source-maps');
- // Curry the transformSync function with the default options.
- typeScriptParser = amaro.transformSync;
+/**
+ *
+ * @param {string} source the source code
+ * @param {object} options the options to pass to the parser
+ * @returns {TransformOutput} an object with a `code` property.
+ */
+function parseTypeScript(source, options) {
+ const parse = loadTypeScriptParser();
+ try {
+ return parse(source, options);
+ } catch (error) {
+ throw new ERR_INVALID_TYPESCRIPT_SYNTAX(error);
}
- return typeScriptParser;
}
/**
@@ -364,14 +358,13 @@ function loadTypeScriptParser(parser) {
*/
function stripTypeScriptTypes(source, filename) {
assert(typeof source === 'string');
- const parse = loadTypeScriptParser();
const options = {
__proto__: null,
- mode: typeScriptParsingMode,
- sourceMap: sourceMapEnabled,
+ mode: getTypeScriptParsingMode(),
+ sourceMap: getOptionValue('--enable-source-maps'),
filename,
};
- const { code, map } = parse(source, options);
+ const { code, map } = parseTypeScript(source, options);
if (map) {
// TODO(@marco-ippolito) When Buffer.transcode supports utf8 to
// base64 transformation, we should change this line.
diff --git a/test/es-module/test-typescript-eval.mjs b/test/es-module/test-typescript-eval.mjs
index be467721577826..e6d841ffa07f7e 100644
--- a/test/es-module/test-typescript-eval.mjs
+++ b/test/es-module/test-typescript-eval.mjs
@@ -110,3 +110,13 @@ test('expect fail eval TypeScript ESM syntax with input-type commonjs', async ()
match(result.stderr, /Cannot use import statement outside a module/);
strictEqual(result.code, 1);
});
+
+test('check syntax error is thrown when passing invalid syntax', async () => {
+ const result = await spawnPromisified(process.execPath, [
+ '--experimental-strip-types',
+ '--eval',
+ 'enum Foo { A, B, C }']);
+ strictEqual(result.stdout, '');
+ match(result.stderr, /ERR_INVALID_TYPESCRIPT_SYNTAX/);
+ strictEqual(result.code, 1);
+});