Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to oxc parser #181

Merged
merged 1 commit into from
Mar 8, 2024
Merged
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
46 changes: 46 additions & 0 deletions .changeset/kind-sloths-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
"@chialab/esbuild-plugin-require-resolve": minor
"@chialab/esbuild-plugin-unwebpack": minor
"@chialab/esbuild-plugin-meta-url": minor
"@chialab/esbuild-plugin-worker": minor
"@chialab/esbuild-plugin-html": minor
"@chialab/wtr-mocha-reporter": minor
"@chialab/es-test-runner": minor
"@chialab/rna-dev-server": minor
"@chialab/wds-plugin-hmr": minor
"@chialab/es-dev-server": minor
"@chialab/estransform": minor
"@chialab/cjs-to-esm": minor
"@chialab/rna-logger": minor
"@chialab/rna": minor
"@chialab/esbuild-plugin-any-file": minor
"@chialab/esbuild-plugin-babel": minor
"@chialab/esbuild-plugin-commonjs": minor
"@chialab/esbuild-plugin-css-import": minor
"@chialab/esbuild-plugin-env": minor
"@chialab/esbuild-plugin-lightningcss": minor
"@chialab/esbuild-plugin-metadata": minor
"@chialab/esbuild-plugin-postcss": minor
"@chialab/esbuild-plugin-virtual": minor
"@chialab/esbuild-rna": minor
"@chialab/node-resolve": minor
"@chialab/postcss-dart-sass": minor
"@chialab/postcss-preset-chialab": minor
"@chialab/postcss-url-rebase": minor
"@chialab/rna-browser-test-runner": minor
"@chialab/rna-bundler": minor
"@chialab/rna-config-loader": minor
"@chialab/rna-node-test-runner": minor
"@chialab/rna-saucelabs-test-runner": minor
"@chialab/vite-plugin-commonjs": minor
"@chialab/vite-plugin-worker-proxy": minor
"@chialab/vitest-axe": minor
"@chialab/vitest-provider-browserstack": minor
"@chialab/wds-plugin-legacy": minor
"@chialab/wds-plugin-node-resolve": minor
"@chialab/wds-plugin-polyfill": minor
"@chialab/wds-plugin-rna": minor
"@chialab/wtr-coverage-reporter": minor
---

Migrate from sucrase to oxc parser.
170 changes: 74 additions & 96 deletions packages/cjs-to-esm/lib/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
import {
createEmptySourcemapComment,
getBlock,
getStatement,
parse,
parseCommonjs,
parseEsm,
TokenType,
walk,
} from '@chialab/estransform';
import { createEmptySourcemapComment, parse, parseCommonjs, parseEsm, walk } from '@chialab/estransform';

export const REQUIRE_REGEX = /([^.\w$]|^)require\s*\((['"])(.*?)\2\)/g;
export const UMD_REGEXES = [
Expand All @@ -21,7 +12,6 @@
/((?:^\s*|;\s*)(\bimport\s*(\{.*?\}\s*from|\s[\w$]+\s+from|\*\s*as\s+[^\s]+\s+from)?\s*['"])|((?:^\s*|;\s*)export(\s+(default|const|var|let|function|class)[^\w$]|\s*\{)))/m;
export const EXPORTS_KEYWORDS = /\b(module\.exports\b|exports\b)/;
export const CJS_KEYWORDS = /\b(module\.exports\b|exports\b|require[.(])/;
export const THIS_PARAM = /(}\s*\()this(,|\))/g;

export const REQUIRE_FUNCTION = '__cjs_default__';
export const HELPER_MODULE = '__cjs_helper__.js';
Expand Down Expand Up @@ -156,17 +146,6 @@
return false;
}

/**
* Check if an expression is a require call.
* @param {import('@chialab/estransform').TokenProcessor} processor
*/
function isRequireCallExpression(processor) {
return (
processor.matches4(TokenType.name, TokenType.parenL, TokenType.string, TokenType.parenR) &&
processor.identifierNameAtIndex(processor.currentIndex()) === 'require'
);
}

/**
* @typedef {(specifier: string) => boolean|Promise<boolean>} IgnoreCallback
*/
Expand Down Expand Up @@ -202,74 +181,79 @@

const specs = new Map();
const ns = new Map();
const { helpers, processor } = await parse(code, source);
const { ast, helpers } = await parse(code, source);
const isUmd = UMD_REGEXES.some((regex) => regex.test(code));

let insertHelper = false;
if (!isUmd) {
/**
* @type {*[]}
* @type {import('@chialab/estransform').Node[]}
*/
const ignoredExpressions = [];

if (ignoreTryCatch) {
let openBlocks = 0;
await walk(processor, (token) => {
if (token.type === TokenType._try) {
openBlocks++;
walk(ast, {
TryStatement(node) {
walk(node.block, {
CallExpression(node) {
if (node.callee.type !== 'Identifier' || node.callee.name !== 'require') {
return;
}
ignoredExpressions.push(node);
},
});
},
});
}

/**
* @type {import('@chialab/estransform').Node[]}
*/
const callExpressions = [];
walk(ast, {
CallExpression(node) {
if (node.callee.type !== 'Identifier' || node.callee.name !== 'require') {
return;
}

if (token.type === TokenType._catch) {
openBlocks--;
if (ignoredExpressions.includes(node)) {
return;
}

if (openBlocks && isRequireCallExpression(processor)) {
ignoredExpressions.push(processor.currentIndex());
const specifier = node.arguments[0];
if (specifier.type === 'StringLiteral') {
callExpressions.push(node);
}
});
}

await walk(processor, (token, index) => {
if (!isRequireCallExpression(processor) || ignoredExpressions.includes(index)) {
return;
}

const specifierToken = processor.tokens[index + 2];
const specifier = processor.stringValueAtIndex(index + 2);
},
});

return (async () => {
let spec = specs.get(specifier);
await Promise.all(
callExpressions.map(async (callExp) => {
const specifier = callExp.arguments[0];
let spec = specs.get(specifier.value);
if (!spec) {
let id = `$cjs$${specifier.replace(/[^\w_$]+/g, '_')}`;
let id = `$cjs$${specifier.value.replace(/[^\w_$]+/g, '_')}`;
const count = (ns.get(id) || 0) + 1;
ns.set(id, count);
if (count > 1) {
id += count;
}

if (await ignore(specifier)) {
if (await ignore(specifier.value)) {
return;
}

spec = { id, specifier };
spec = { id, specifier: specifier.value };
specs.set(specifier, spec);
}

insertHelper = true;

helpers.overwrite(token.start, token.end, REQUIRE_FUNCTION);
processor.nextToken();
processor.nextToken();
helpers.overwrite(callExp.callee.start, callExp.callee.end, REQUIRE_FUNCTION);
helpers.overwrite(
specifierToken.start,
specifierToken.end,
specifier.start,
specifier.end,
`typeof ${spec.id} !== 'undefined' ? ${spec.id} : {}`
);
processor.nextToken();
})();
});
})
);
}

const { exports, reexports } = await parseCommonjs(code);
Expand Down Expand Up @@ -314,17 +298,6 @@
}).call(__umdRoot, __umdRoot, __umdRoot, __umdRoot, __umdRoot, undefined, undefined, __umdFunction);

export default (__umdExports.length !== 1 && __umdRoot[__umdExports[0]] !== __umdRoot[__umdExports[1]] ? __umdRoot : __umdRoot[__umdExports[0]]);`);

// replace the usage of `this` as global object because is not supported in esm
let thisMatch = THIS_PARAM.exec(code);
while (thisMatch) {
helpers.overwrite(
thisMatch.index,
thisMatch.index + thisMatch[0].length,
`${thisMatch[1]}this || __umdGlobal${thisMatch[2]}`
);
thisMatch = THIS_PARAM.exec(code);
}
} else if (exports.length > 0 || reexports.length > 0) {
helpers.prepend(`var global = ${GLOBAL_HELPER};
var exports = {};
Expand Down Expand Up @@ -409,34 +382,39 @@
* @param {{ sourcemap?: boolean, source?: string; sourcesContent?: boolean }} options
*/
export async function wrapDynamicRequire(code, { sourcemap = true, source, sourcesContent = false } = {}) {
const { helpers, processor } = await parse(code, source);
await walk(processor, (token, index) => {
if (
!processor.matches5(TokenType._if, TokenType.parenL, TokenType._typeof, TokenType.name, TokenType.equality)
) {
return;
}

const identifier = processor.identifierNameAtIndex(index + 3);
if (identifier !== 'require') {
return;
}

getBlock(processor, TokenType.parenL, TokenType.parenR);
processor.nextToken();

const tokens = [];
if (processor.currentToken() && processor.currentToken().type === TokenType.braceL) {
tokens.push(...getBlock(processor).slice(1, -1));
} else {
tokens.push(...getStatement(processor));
}

const startToken = tokens[0];
const endToken = tokens[tokens.length - 1];
const { ast, helpers } = await parse(code, source);
walk(ast, {
IfStatement(node) {
if (node.test.type !== 'BinaryExpression') {
return;
}

Check warning on line 390 in packages/cjs-to-esm/lib/index.js

View check run for this annotation

Codecov / codecov/patch

packages/cjs-to-esm/lib/index.js#L389-L390

Added lines #L389 - L390 were not covered by tests
if (node.test.left.type !== 'UnaryExpression') {
return;
}

Check warning on line 393 in packages/cjs-to-esm/lib/index.js

View check run for this annotation

Codecov / codecov/patch

packages/cjs-to-esm/lib/index.js#L392-L393

Added lines #L392 - L393 were not covered by tests
if (node.test.left.operator !== 'typeof') {
return;
}

Check warning on line 396 in packages/cjs-to-esm/lib/index.js

View check run for this annotation

Codecov / codecov/patch

packages/cjs-to-esm/lib/index.js#L395-L396

Added lines #L395 - L396 were not covered by tests
if (node.test.left.argument.type !== 'Identifier') {
return;
}

Check warning on line 399 in packages/cjs-to-esm/lib/index.js

View check run for this annotation

Codecov / codecov/patch

packages/cjs-to-esm/lib/index.js#L398-L399

Added lines #L398 - L399 were not covered by tests
if (node.test.left.argument.name !== 'require') {
return;
}

Check warning on line 402 in packages/cjs-to-esm/lib/index.js

View check run for this annotation

Codecov / codecov/patch

packages/cjs-to-esm/lib/index.js#L401-L402

Added lines #L401 - L402 were not covered by tests
if (!['===', '==', '!==', '!='].includes(node.test.operator)) {
return;
}

Check warning on line 405 in packages/cjs-to-esm/lib/index.js

View check run for this annotation

Codecov / codecov/patch

packages/cjs-to-esm/lib/index.js#L404-L405

Added lines #L404 - L405 were not covered by tests

helpers.prepend('(() => { try { return (() => {', startToken.start);
helpers.append('})(); } catch(err) {} })();', endToken.end);
if (node.consequent.type === 'BlockStatement') {
helpers.prepend('(() => { try { return (() => {', node.consequent.body[0].start);
helpers.append(
'})(); } catch(err) {} })();',
node.consequent.body[node.consequent.body.length - 1].end
);
} else {
helpers.prepend('(() => { try { return (() => {', node.consequent.start);
helpers.append('})(); } catch(err) {} })();', node.consequent.end);
}
},
});

if (!helpers.isDirty()) {
Expand Down
2 changes: 1 addition & 1 deletion packages/es-dev-server/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ esbuild.build({
banner: {
js: `import { dirname as __pathDirname } from 'path';
import { createRequire as __moduleCreateRequire } from 'module';
import { fileURLToPath as __fileURLToPath } from 'url';
import { fileURLToPath as __fileURLToPath } from 'url';

const require = __moduleCreateRequire(import.meta.url);
const __filename = __fileURLToPath(import.meta.url);
Expand Down
2 changes: 1 addition & 1 deletion packages/es-test-runner/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ esbuild.build({
banner: {
js: `import { dirname as __pathDirname } from 'path';
import { createRequire as __moduleCreateRequire } from 'module';
import { fileURLToPath as __fileURLToPath } from 'url';
import { fileURLToPath as __fileURLToPath } from 'url';

const require = __moduleCreateRequire(import.meta.url);
const __filename = __fileURLToPath(import.meta.url);
Expand Down
2 changes: 1 addition & 1 deletion packages/esbuild-plugin-html/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ esbuild.build({
banner: {
js: `import { dirname as __pathDirname } from 'path';
import { createRequire as __moduleCreateRequire } from 'module';
import { fileURLToPath as __fileURLToPath } from 'url';
import { fileURLToPath as __fileURLToPath } from 'url';

const require = __moduleCreateRequire(import.meta.url);
const __filename = __fileURLToPath(import.meta.url);
Expand Down
Loading
Loading