From 346469cc01df0f7054123149800176583558fd3b Mon Sep 17 00:00:00 2001 From: Nikita Skovoroda Date: Wed, 31 Jul 2024 14:20:41 +0300 Subject: [PATCH 1/3] module: set swc transform mode explicitly to 'strip-only' --- lib/internal/modules/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/modules/helpers.js b/lib/internal/modules/helpers.js index 2eae0f6cd3f78f..d466cec51cfbf7 100644 --- a/lib/internal/modules/helpers.js +++ b/lib/internal/modules/helpers.js @@ -310,7 +310,7 @@ function lazyLoadTSParser() { function tsParse(source) { if (!source || typeof source !== 'string') { return; } const transformSync = lazyLoadTSParser(); - const { code } = transformSync(source); + const { code } = transformSync(source, { mode: 'strip-only' }); return code; } From ae2732871409b68bee012a4e282310a587246e0d Mon Sep 17 00:00:00 2001 From: Nikita Skovoroda Date: Wed, 31 Jul 2024 14:42:51 +0300 Subject: [PATCH 2/3] module: validate that strip-types does not insert any code --- lib/internal/modules/helpers.js | 49 +++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/lib/internal/modules/helpers.js b/lib/internal/modules/helpers.js index d466cec51cfbf7..7831f80f2a876b 100644 --- a/lib/internal/modules/helpers.js +++ b/lib/internal/modules/helpers.js @@ -24,6 +24,7 @@ const internalFS = require('internal/fs/utils'); const path = require('path'); const { pathToFileURL, fileURLToPath } = require('internal/url'); const assert = require('internal/assert'); +const { Buffer: { from: BufferFrom } } = require('buffer'); const { getOptionValue } = require('internal/options'); const { setOwnProperty } = require('internal/util'); @@ -307,10 +308,58 @@ function lazyLoadTSParser() { return parseTS; } +function doesTSStripTypesResultMatchSource(code, source) { + const sourceBuf = BufferFrom(source); + const codeBuf = BufferFrom(code); + if (sourceBuf.length !== codeBuf.length) { return false; } + for (let i = 0; i < codeBuf.length; i++) { + // Should match either the source buffer or spaces (sometimes multi-byte) or semicolon + const val = codeBuf[i]; + if (val === sourceBuf[i]) { + // Source match + continue; + } + // https://github.com/nodejs/amaro/blob/e533394f576f946add41dd8816816435e8100c3b/deps/swc/crates/swc_fast_ts_strip/src/lib.rs#L400-L414 + if (val === 0x3b) { + // Semicolon 3b + continue; + } + // https://github.com/nodejs/amaro/blob/e533394f576f946add41dd8816816435e8100c3b/deps/swc/crates/swc_fast_ts_strip/src/lib.rs#L200-L226 + if (val === 0x20) { + // Space 20 + continue; + } + if (val === 0xc2) { + // No-Break Space 00A0 + if (i + 1 >= codeBuf.length) { return false; } + if (codeBuf[++i] !== 0xa0) { return false; } + continue; + } + if (val === 0xe2) { + // En Space 2002 + if (i + 2 >= codeBuf.length) { return false; } + if (codeBuf[++i] !== 0x80) { return false; } + if (codeBuf[++i] !== 0x82) { return false; } + continue; + } + if (val === 0xef) { + // ZWNBSP FEFF + if (i < 1 || codeBuf[i - 1] !== 0x20) { return false; } // Only can get insterted after a space + if (i + 2 >= codeBuf.length) { return false; } + if (codeBuf[++i] !== 0xbb) { return false; } + if (codeBuf[++i] !== 0xbf) { return false; } + continue; + } + return false; + } + return true; +} + function tsParse(source) { if (!source || typeof source !== 'string') { return; } const transformSync = lazyLoadTSParser(); const { code } = transformSync(source, { mode: 'strip-only' }); + assert(doesTSStripTypesResultMatchSource(code, source), 'Unexpected strip-types result'); return code; } From 1e8101db5b07997ab33a468516d8a540c03b643b Mon Sep 17 00:00:00 2001 From: Nikita Skovoroda Date: Wed, 31 Jul 2024 16:07:17 +0300 Subject: [PATCH 3/3] Update lib/internal/modules/helpers.js Co-authored-by: Antoine du Hamel --- lib/internal/modules/helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/modules/helpers.js b/lib/internal/modules/helpers.js index 7831f80f2a876b..0de60cbd0d174b 100644 --- a/lib/internal/modules/helpers.js +++ b/lib/internal/modules/helpers.js @@ -358,7 +358,7 @@ function doesTSStripTypesResultMatchSource(code, source) { function tsParse(source) { if (!source || typeof source !== 'string') { return; } const transformSync = lazyLoadTSParser(); - const { code } = transformSync(source, { mode: 'strip-only' }); + const { code } = transformSync(source, { __proto__: null, mode: 'strip-only' }); assert(doesTSStripTypesResultMatchSource(code, source), 'Unexpected strip-types result'); return code; }