From 7e7624da584f99c0582a4569f18ffc56c4b43ba2 Mon Sep 17 00:00:00 2001 From: hubvue Date: Wed, 29 Jun 2022 19:43:13 +0800 Subject: [PATCH 01/12] fix: filter out commented code to eliminate the effect of regular match export --- src/analyze.ts | 11 +++++++++++ test/exports.test.ts | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/analyze.ts b/src/analyze.ts index 2172a57..dda7dbf 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -59,6 +59,7 @@ export const EXPORT_DECAL_RE = /\bexport\s+(?(async function|functi const EXPORT_NAMED_RE = /\bexport\s+{(?[^}]+)}(\s*from\s*["']\s*(?(?<="\s*)[^"]*[^"\s](?=\s*")|(?<='\s*)[^']*[^'\s](?=\s*'))\s*["'][^\n]*)?/g const EXPORT_STAR_RE = /\bexport\s*(\*)(\s*as\s+(?[\w$_]+)\s+)?\s*(\s*from\s*["']\s*(?(?<="\s*)[^"]*[^"\s](?=\s*")|(?<='\s*)[^']*[^'\s](?=\s*'))\s*["'][^\n]*)?/g const EXPORT_DEFAULT_RE = /\bexport\s+default\s+/g +const COMMENT_RE = /(\/\*[\s\S]*\*\/)|(\/\/.*)/g export function findStaticImports (code: string): StaticImport[] { return matchAll(ESM_STATIC_IMPORT_RE, code, { type: 'static' }) @@ -93,6 +94,8 @@ export function parseStaticImport (matched: StaticImport): ParsedStaticImport { } export function findExports (code: string): ESMExport[] { + // Filter out commented code to eliminate the effect of regular match export + code = filterCommentCode(code) // Find declarations like export const foo = 'bar' const declaredExports = matchAll(EXPORT_DECAL_RE, code, { type: 'declaration' }) @@ -130,3 +133,11 @@ export function findExports (code: string): ESMExport[] { return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name }) } + +function filterCommentCode (code: string) { + const matchedComments = matchAll(COMMENT_RE, code, { type: 'comments' }) + for (const matched of matchedComments) { + code = code.replace(matched.code, '') + } + return code +} diff --git a/test/exports.test.ts b/test/exports.test.ts index c74a21d..9b63ba9 100644 --- a/test/exports.test.ts +++ b/test/exports.test.ts @@ -52,4 +52,39 @@ export { foobar } from 'foo2'; const matches = findExports(code) expect(matches).to.have.lengthOf(3) }) + + it('test', () => { + const code = ` + // export { foo } from 'foo1'; + // exports default 'foo'; + // export { useB, _useC as useC }; + // export function useA () { return 'a' } + // export { default } from "./other" + // export async function foo () {} + // export { foo as default } + //export * from "./other" + //export * as foo from "./other" + + /** + * export const a = 123 + * export { foo } from 'foo1'; + * exports default 'foo' + * export function useA () { return 'a' } + * export { useB, _useC as useC }; + *export { default } from "./other" + *export async function foo () {} + * export { foo as default } + * export * from "./other" + export * as foo from "./other" + */ + + export { bar } from 'foo2'; + export { foobar } from 'foo2'; + ` + /** + * export const a = 123 + */ + const matches = findExports(code) + expect(matches).to.have.lengthOf(2) + }) }) From ec5496ed47cf876fe238dcf8b1763b3cfbb2b567 Mon Sep 17 00:00:00 2001 From: hubvue Date: Wed, 29 Jun 2022 19:53:08 +0800 Subject: [PATCH 02/12] test: update test case name --- test/exports.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/exports.test.ts b/test/exports.test.ts index 9b63ba9..969d761 100644 --- a/test/exports.test.ts +++ b/test/exports.test.ts @@ -53,7 +53,7 @@ export { foobar } from 'foo2'; expect(matches).to.have.lengthOf(3) }) - it('test', () => { + it('the commented out export should be filtered out', () => { const code = ` // export { foo } from 'foo1'; // exports default 'foo'; From 79af763aea2bcaa1161e9bffaaf871b799e18e6c Mon Sep 17 00:00:00 2001 From: hubvue Date: Wed, 29 Jun 2022 20:04:14 +0800 Subject: [PATCH 03/12] test: delete comment --- test/exports.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/exports.test.ts b/test/exports.test.ts index 969d761..e9e48bb 100644 --- a/test/exports.test.ts +++ b/test/exports.test.ts @@ -81,9 +81,6 @@ export { foobar } from 'foo2'; export { bar } from 'foo2'; export { foobar } from 'foo2'; ` - /** - * export const a = 123 - */ const matches = findExports(code) expect(matches).to.have.lengthOf(2) }) From 3d365cbd48f28aa944792540a49b32e8f208417e Mon Sep 17 00:00:00 2001 From: hubvue Date: Wed, 29 Jun 2022 20:16:15 +0800 Subject: [PATCH 04/12] fix: update match type --- src/analyze.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyze.ts b/src/analyze.ts index dda7dbf..0040926 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -135,7 +135,7 @@ export function findExports (code: string): ESMExport[] { } function filterCommentCode (code: string) { - const matchedComments = matchAll(COMMENT_RE, code, { type: 'comments' }) + const matchedComments = matchAll(COMMENT_RE, code, { type: 'comment' }) for (const matched of matchedComments) { code = code.replace(matched.code, '') } From b620f3c777a68f051526c706445328fd408ece2d Mon Sep 17 00:00:00 2001 From: hubvue Date: Thu, 30 Jun 2022 00:40:52 +0800 Subject: [PATCH 05/12] feat: use replace + reg filter comments --- src/analyze.ts | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/analyze.ts b/src/analyze.ts index 0040926..5814f56 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -95,7 +95,7 @@ export function parseStaticImport (matched: StaticImport): ParsedStaticImport { export function findExports (code: string): ESMExport[] { // Filter out commented code to eliminate the effect of regular match export - code = filterCommentCode(code) + code = code.replace(COMMENT_RE, '').trim() // Find declarations like export const foo = 'bar' const declaredExports = matchAll(EXPORT_DECAL_RE, code, { type: 'declaration' }) @@ -133,11 +133,3 @@ export function findExports (code: string): ESMExport[] { return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name }) } - -function filterCommentCode (code: string) { - const matchedComments = matchAll(COMMENT_RE, code, { type: 'comment' }) - for (const matched of matchedComments) { - code = code.replace(matched.code, '') - } - return code -} From 95934c68da08b68185b25956869c20b64e4526b1 Mon Sep 17 00:00:00 2001 From: hubvue Date: Thu, 30 Jun 2022 11:20:58 +0800 Subject: [PATCH 06/12] feat: update match comments regexp --- src/analyze.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/analyze.ts b/src/analyze.ts index 5814f56..8b334d0 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -59,7 +59,9 @@ export const EXPORT_DECAL_RE = /\bexport\s+(?(async function|functi const EXPORT_NAMED_RE = /\bexport\s+{(?[^}]+)}(\s*from\s*["']\s*(?(?<="\s*)[^"]*[^"\s](?=\s*")|(?<='\s*)[^']*[^'\s](?=\s*'))\s*["'][^\n]*)?/g const EXPORT_STAR_RE = /\bexport\s*(\*)(\s*as\s+(?[\w$_]+)\s+)?\s*(\s*from\s*["']\s*(?(?<="\s*)[^"]*[^"\s](?=\s*")|(?<='\s*)[^']*[^'\s](?=\s*'))\s*["'][^\n]*)?/g const EXPORT_DEFAULT_RE = /\bexport\s+default\s+/g -const COMMENT_RE = /(\/\*[\s\S]*\*\/)|(\/\/.*)/g +// const COMMENT_RE = /(\/\*[\s\S]*\*\/)|(\/\/.*)/g +const MULTI_LINE_COMMENTS_RE = /\/\*.*?\*\//gms +const SINGLE_LINE_COMMENTS_RE = /\/\/.*$/gm export function findStaticImports (code: string): StaticImport[] { return matchAll(ESM_STATIC_IMPORT_RE, code, { type: 'static' }) @@ -95,7 +97,7 @@ export function parseStaticImport (matched: StaticImport): ParsedStaticImport { export function findExports (code: string): ESMExport[] { // Filter out commented code to eliminate the effect of regular match export - code = code.replace(COMMENT_RE, '').trim() + code = stripComments(code) // Find declarations like export const foo = 'bar' const declaredExports = matchAll(EXPORT_DECAL_RE, code, { type: 'declaration' }) @@ -133,3 +135,9 @@ export function findExports (code: string): ESMExport[] { return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name }) } + +function stripComments (code: string) { + return code + .replace(MULTI_LINE_COMMENTS_RE, '') + .replace(SINGLE_LINE_COMMENTS_RE, '') +} From bbfc0ceafc78cc6ccf66401cb6f2f04e4dc488ca Mon Sep 17 00:00:00 2001 From: hubvue Date: Fri, 1 Jul 2022 11:38:45 +0800 Subject: [PATCH 07/12] feat: filtering export statements in strings --- src/analyze.ts | 7 ++++++- test/exports.test.ts | 19 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/analyze.ts b/src/analyze.ts index 8b334d0..7407718 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -59,9 +59,12 @@ export const EXPORT_DECAL_RE = /\bexport\s+(?(async function|functi const EXPORT_NAMED_RE = /\bexport\s+{(?[^}]+)}(\s*from\s*["']\s*(?(?<="\s*)[^"]*[^"\s](?=\s*")|(?<='\s*)[^']*[^'\s](?=\s*'))\s*["'][^\n]*)?/g const EXPORT_STAR_RE = /\bexport\s*(\*)(\s*as\s+(?[\w$_]+)\s+)?\s*(\s*from\s*["']\s*(?(?<="\s*)[^"]*[^"\s](?=\s*")|(?<='\s*)[^']*[^'\s](?=\s*'))\s*["'][^\n]*)?/g const EXPORT_DEFAULT_RE = /\bexport\s+default\s+/g -// const COMMENT_RE = /(\/\*[\s\S]*\*\/)|(\/\/.*)/g const MULTI_LINE_COMMENTS_RE = /\/\*.*?\*\//gms const SINGLE_LINE_COMMENTS_RE = /\/\/.*$/gm +const QUOTES_RE = [ + /['"](.*)export(.*)from(.*)['"]/gm, + /[`](.*)export(.*)from(.*)[`]/gms +] export function findStaticImports (code: string): StaticImport[] { return matchAll(ESM_STATIC_IMPORT_RE, code, { type: 'static' }) @@ -140,4 +143,6 @@ function stripComments (code: string) { return code .replace(MULTI_LINE_COMMENTS_RE, '') .replace(SINGLE_LINE_COMMENTS_RE, '') + .replace(QUOTES_RE[0], '""') + .replace(QUOTES_RE[1], '``') } diff --git a/test/exports.test.ts b/test/exports.test.ts index e9e48bb..48727c7 100644 --- a/test/exports.test.ts +++ b/test/exports.test.ts @@ -77,7 +77,24 @@ export { foobar } from 'foo2'; * export * from "./other" export * as foo from "./other" */ - + export { bar } from 'foo2'; + export { foobar } from 'foo2'; + ` + const matches = findExports(code) + expect(matches).to.have.lengthOf(2) + }) + it('export in string', () => { + const code = ` + const test = "Hello world" + const test1 = "export { ba1 } from 'foo2'" + const test2 = "testexport { bar2 } from 'foo2'" + const test3 = "test export { bar3 } from 'foo2'" + const test4 = "export { bar4 } from 'foo2' test" + const test5 = \` + test1 + export { bar4 } from 'foo2' test + test2 + \` export { bar } from 'foo2'; export { foobar } from 'foo2'; ` From 33365b0fa28614621ebef4922515e92bd45a8411 Mon Sep 17 00:00:00 2001 From: hubvue Date: Fri, 1 Jul 2022 17:34:00 +0800 Subject: [PATCH 08/12] feat: use the tokenizer to analyse the code and filter out unsyntactic exports --- package.json | 1 + pnpm-lock.yaml | 65 +++++---------------------- src/analyze.ts | 50 +++++++++++++-------- test/exports.test.ts | 102 ++++++++++++++++++++++++------------------- 4 files changed, 101 insertions(+), 117 deletions(-) diff --git a/package.json b/package.json index 6b4c82e..80af951 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "test": "pnpm lint && vitest run" }, "dependencies": { + "acorn": "^8.7.1", "pathe": "^0.3.1", "pkg-types": "^0.3.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b977ace..1bf3ca8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,6 +3,7 @@ lockfileVersion: 5.3 specifiers: '@nuxtjs/eslint-config-typescript': latest '@types/node': latest + acorn: ^8.7.1 c8: latest eslint: latest jiti: latest @@ -13,6 +14,7 @@ specifiers: vitest: latest dependencies: + acorn: 8.7.1 pathe: 0.3.1 pkg-types: 0.3.3 @@ -325,35 +327,31 @@ packages: peerDependencies: eslint: ^8.14.0 dependencies: - '@nuxtjs/eslint-config': 10.0.0_ffe31d4b33f195ddab7fc0ad3f59d4f8 + '@nuxtjs/eslint-config': 10.0.0_eslint@8.18.0 '@typescript-eslint/eslint-plugin': 5.28.0_f2f0a89a495fa3aab44c48904aa546c6 '@typescript-eslint/parser': 5.28.0_eslint@8.18.0 eslint: 8.18.0 eslint-import-resolver-typescript: 2.7.1_9462c2f560e8d8d9149a63cde905d125 - eslint-plugin-import: 2.26.0_ffe31d4b33f195ddab7fc0ad3f59d4f8 + eslint-plugin-import: 2.26.0_eslint@8.18.0 transitivePeerDependencies: - - eslint-import-resolver-webpack - supports-color - typescript dev: true - /@nuxtjs/eslint-config/10.0.0_ffe31d4b33f195ddab7fc0ad3f59d4f8: + /@nuxtjs/eslint-config/10.0.0_eslint@8.18.0: resolution: {integrity: sha512-5umb4Nyd/D9azWyFPGe3ru0E5v8SSVzgtZeJwTaCpqjsQDrr51P7QPtBTVdJXIbhdY1lws67x9Emkb7oKwh4zw==} peerDependencies: eslint: ^8.14.0 dependencies: eslint: 8.18.0 eslint-config-standard: 17.0.0_fef3071837bd83b424879c2d7400dcfe - eslint-plugin-import: 2.26.0_ffe31d4b33f195ddab7fc0ad3f59d4f8 + eslint-plugin-import: 2.26.0_eslint@8.18.0 eslint-plugin-n: 15.2.3_eslint@8.18.0 eslint-plugin-node: 11.1.0_eslint@8.18.0 eslint-plugin-promise: 6.0.0_eslint@8.18.0 eslint-plugin-unicorn: 42.0.0_eslint@8.18.0 eslint-plugin-vue: 8.7.1_eslint@8.18.0 transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - supports-color dev: true @@ -627,7 +625,6 @@ packages: resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==} engines: {node: '>=0.4.0'} hasBin: true - dev: true /add-stream/1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} @@ -1110,22 +1107,12 @@ packages: /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true dependencies: ms: 2.0.0 dev: true /debug/3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true dependencies: ms: 2.1.3 dev: true @@ -1677,7 +1664,7 @@ packages: eslint-plugin-promise: ^6.0.0 dependencies: eslint: 8.18.0 - eslint-plugin-import: 2.26.0_ffe31d4b33f195ddab7fc0ad3f59d4f8 + eslint-plugin-import: 2.26.0_eslint@8.18.0 eslint-plugin-n: 15.2.3_eslint@8.18.0 eslint-plugin-promise: 6.0.0_eslint@8.18.0 dev: true @@ -1687,8 +1674,6 @@ packages: dependencies: debug: 3.2.7 resolve: 1.22.0 - transitivePeerDependencies: - - supports-color dev: true /eslint-import-resolver-typescript/2.7.1_9462c2f560e8d8d9149a63cde905d125: @@ -1700,7 +1685,7 @@ packages: dependencies: debug: 4.3.4 eslint: 8.18.0 - eslint-plugin-import: 2.26.0_ffe31d4b33f195ddab7fc0ad3f59d4f8 + eslint-plugin-import: 2.26.0_eslint@8.18.0 glob: 7.2.0 is-glob: 4.0.3 resolve: 1.22.0 @@ -1709,31 +1694,12 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.3_7858816440dc1f0ab5451450e5fe50fd: + /eslint-module-utils/2.7.3: resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==} engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true dependencies: - '@typescript-eslint/parser': 5.28.0_eslint@8.18.0 debug: 3.2.7 - eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1_9462c2f560e8d8d9149a63cde905d125 find-up: 2.1.0 - transitivePeerDependencies: - - supports-color dev: true /eslint-plugin-es/3.0.1_eslint@8.18.0: @@ -1758,24 +1724,19 @@ packages: regexpp: 3.2.0 dev: true - /eslint-plugin-import/2.26.0_ffe31d4b33f195ddab7fc0ad3f59d4f8: + /eslint-plugin-import/2.26.0_eslint@8.18.0: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: - '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true dependencies: - '@typescript-eslint/parser': 5.28.0_eslint@8.18.0 array-includes: 3.1.4 array.prototype.flat: 1.2.5 debug: 2.6.9 doctrine: 2.1.0 eslint: 8.18.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.3_7858816440dc1f0ab5451450e5fe50fd + eslint-module-utils: 2.7.3 has: 1.0.3 is-core-module: 2.9.0 is-glob: 4.0.3 @@ -1783,10 +1744,6 @@ packages: object.values: 1.1.5 resolve: 1.22.0 tsconfig-paths: 3.14.1 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color dev: true /eslint-plugin-n/15.2.3_eslint@8.18.0: diff --git a/src/analyze.ts b/src/analyze.ts index 7407718..19fe8de 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -1,3 +1,4 @@ +import { tokenizer } from 'acorn' import { matchAll } from './_utils' export interface ESMImport { @@ -59,12 +60,6 @@ export const EXPORT_DECAL_RE = /\bexport\s+(?(async function|functi const EXPORT_NAMED_RE = /\bexport\s+{(?[^}]+)}(\s*from\s*["']\s*(?(?<="\s*)[^"]*[^"\s](?=\s*")|(?<='\s*)[^']*[^'\s](?=\s*'))\s*["'][^\n]*)?/g const EXPORT_STAR_RE = /\bexport\s*(\*)(\s*as\s+(?[\w$_]+)\s+)?\s*(\s*from\s*["']\s*(?(?<="\s*)[^"]*[^"\s](?=\s*")|(?<='\s*)[^']*[^'\s](?=\s*'))\s*["'][^\n]*)?/g const EXPORT_DEFAULT_RE = /\bexport\s+default\s+/g -const MULTI_LINE_COMMENTS_RE = /\/\*.*?\*\//gms -const SINGLE_LINE_COMMENTS_RE = /\/\/.*$/gm -const QUOTES_RE = [ - /['"](.*)export(.*)from(.*)['"]/gm, - /[`](.*)export(.*)from(.*)[`]/gms -] export function findStaticImports (code: string): StaticImport[] { return matchAll(ESM_STATIC_IMPORT_RE, code, { type: 'static' }) @@ -99,8 +94,6 @@ export function parseStaticImport (matched: StaticImport): ParsedStaticImport { } export function findExports (code: string): ESMExport[] { - // Filter out commented code to eliminate the effect of regular match export - code = stripComments(code) // Find declarations like export const foo = 'bar' const declaredExports = matchAll(EXPORT_DECAL_RE, code, { type: 'declaration' }) @@ -118,7 +111,6 @@ export function findExports (code: string): ESMExport[] { // Merge and normalize exports const exports = [].concat(declaredExports, namedExports, defaultExport, starExports) - for (const exp of exports) { if (!exp.name && exp.names && exp.names.length === 1) { exp.name = exp.names[0] @@ -131,18 +123,42 @@ export function findExports (code: string): ESMExport[] { exp.names = [exp.name] } } - + const exportsLocation = getExportTokenLocation(code) return exports.filter((exp, index, exports) => { + // Filter out noise that does not match the semantics of export + if (!isExportStatement(exportsLocation, exp)) { + return false + } // Prevent multiple exports of same function, only keep latest iteration of signatures const nextExport = exports[index + 1] - return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name + return isExportStatement(exportsLocation, exp) || !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name }) } -function stripComments (code: string) { - return code - .replace(MULTI_LINE_COMMENTS_RE, '') - .replace(SINGLE_LINE_COMMENTS_RE, '') - .replace(QUOTES_RE[0], '""') - .replace(QUOTES_RE[1], '``') +interface TokenLocation { + start: number + end: number +} +function isExportStatement (exportsLcation: TokenLocation[], exp) { + return exportsLcation.some(location => exp.start <= location.start && exp.end >= location.end) +} + +function getExportTokenLocation (code: string) { + const tokens = tokenizer(code, { + ecmaVersion: 'latest', + sourceType: 'module', + allowHashBang: true, + allowAwaitOutsideFunction: true, + allowImportExportEverywhere: true + }) + const locations: TokenLocation[] = [] + for (const token of tokens) { + if (token.type.label === 'export') { + locations.push({ + start: token.start, + end: token.end + }) + } + } + return locations } diff --git a/test/exports.test.ts b/test/exports.test.ts index 48727c7..8f2c0ed 100644 --- a/test/exports.test.ts +++ b/test/exports.test.ts @@ -36,68 +36,78 @@ describe('findExports', () => { } it('handles multiple exports', () => { const matches = findExports(` - export { useTestMe1 } from "@/test/foo1"; - export { useTestMe2 } from "@/test/foo2"; - export { useTestMe3 } from "@/test/foo3"; - `) + export { useTestMe1 } from "@/test/foo1"; + export { useTestMe2 } from "@/test/foo2"; + export { useTestMe3 } from "@/test/foo3"; + `) expect(matches.length).to.eql(3) }) it('works with multiple named exports', () => { const code = ` -export { foo } from 'foo1'; -export { bar } from 'foo2'; -export { foobar } from 'foo2'; -` + export { foo } from 'foo1'; + export { bar } from 'foo2'; + export { foobar } from 'foo2'; + ` const matches = findExports(code) expect(matches).to.have.lengthOf(3) }) it('the commented out export should be filtered out', () => { const code = ` - // export { foo } from 'foo1'; - // exports default 'foo'; - // export { useB, _useC as useC }; - // export function useA () { return 'a' } - // export { default } from "./other" - // export async function foo () {} - // export { foo as default } - //export * from "./other" - //export * as foo from "./other" + // export { foo } from 'foo1'; + // exports default 'foo'; + // export { useB, _useC as useC }; + // export function useA () { return 'a' } + // export { default } from "./other" + // export async function foo () {} + // export { foo as default } + //export * from "./other" + //export * as foo from "./other" - /** - * export const a = 123 - * export { foo } from 'foo1'; - * exports default 'foo' - * export function useA () { return 'a' } - * export { useB, _useC as useC }; - *export { default } from "./other" - *export async function foo () {} - * export { foo as default } - * export * from "./other" - export * as foo from "./other" - */ - export { bar } from 'foo2'; - export { foobar } from 'foo2'; - ` + /** + * export const a = 123 + * export { foo } from 'foo1'; + * exports default 'foo' + * export function useA () { return 'a' } + * export { useB, _useC as useC }; + *export { default } from "./other" + *export async function foo () {} + * export { foo as default } + * export * from "./other" + export * as foo from "./other" + */ + export { bar } from 'foo2'; + export { foobar } from 'foo2'; + ` const matches = findExports(code) expect(matches).to.have.lengthOf(2) }) it('export in string', () => { - const code = ` - const test = "Hello world" - const test1 = "export { ba1 } from 'foo2'" - const test2 = "testexport { bar2 } from 'foo2'" - const test3 = "test export { bar3 } from 'foo2'" - const test4 = "export { bar4 } from 'foo2' test" - const test5 = \` - test1 - export { bar4 } from 'foo2' test - test2 - \` - export { bar } from 'foo2'; - export { foobar } from 'foo2'; - ` + const tests: string[] = [ + 'export function useA () { return \'a\' }', + 'export const useD = () => { return \'d\' }', + 'export { useB, _useC as useC }', + 'export default foo', + 'export { default } from "./other"', + 'export async function foo ()', + 'export const $foo = () => {}', + 'export { foo as default }', + 'export * from "./other"', + 'export * as foo from "./other"' + ] + const code = tests.reduce((codeStr, statement, idx) => { + codeStr = ` + ${codeStr} + const test${idx}0 = "${statement}" + const test${idx}1 = \` + test1 + ${statement} + test2 + \` + ` + return codeStr + }, 'export { bar } from \'foo2\'; \n export { foobar } from \'foo2\';') const matches = findExports(code) expect(matches).to.have.lengthOf(2) }) From 9ab5734e41559bbd18fae770e3c768f7ded566a7 Mon Sep 17 00:00:00 2001 From: hubvue Date: Fri, 1 Jul 2022 22:48:05 +0800 Subject: [PATCH 09/12] feat: rename & supplementary types --- src/analyze.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/analyze.ts b/src/analyze.ts index 19fe8de..53a25e4 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -94,23 +94,28 @@ export function parseStaticImport (matched: StaticImport): ParsedStaticImport { } export function findExports (code: string): ESMExport[] { + // Return early when there is no legal export statement + const exportsLocation = getExportTokenLocation(code) + if (!exportsLocation.length) { + return [] + } // Find declarations like export const foo = 'bar' - const declaredExports = matchAll(EXPORT_DECAL_RE, code, { type: 'declaration' }) + const declaredExports: DeclarationExport[] = matchAll(EXPORT_DECAL_RE, code, { type: 'declaration' }) // Find named exports - const namedExports = matchAll(EXPORT_NAMED_RE, code, { type: 'named' }) + const namedExports: NamedExport[] = matchAll(EXPORT_NAMED_RE, code, { type: 'named' }) for (const namedExport of namedExports) { namedExport.names = namedExport.exports.split(/\s*,\s*/g).map(name => name.replace(/^.*?\sas\s/, '').trim()) } // Find export default - const defaultExport = matchAll(EXPORT_DEFAULT_RE, code, { type: 'default', name: 'default' }) + const defaultExport: DefaultExport[] = matchAll(EXPORT_DEFAULT_RE, code, { type: 'default', name: 'default' }) // Find export star - const starExports = matchAll(EXPORT_STAR_RE, code, { type: 'star' }) + const starExports: ESMExport[] = matchAll(EXPORT_STAR_RE, code, { type: 'star' }) // Merge and normalize exports - const exports = [].concat(declaredExports, namedExports, defaultExport, starExports) + const exports: ESMExport[] = [].concat(declaredExports, namedExports, defaultExport, starExports) for (const exp of exports) { if (!exp.name && exp.names && exp.names.length === 1) { exp.name = exp.names[0] @@ -123,7 +128,6 @@ export function findExports (code: string): ESMExport[] { exp.names = [exp.name] } } - const exportsLocation = getExportTokenLocation(code) return exports.filter((exp, index, exports) => { // Filter out noise that does not match the semantics of export if (!isExportStatement(exportsLocation, exp)) { @@ -131,7 +135,7 @@ export function findExports (code: string): ESMExport[] { } // Prevent multiple exports of same function, only keep latest iteration of signatures const nextExport = exports[index + 1] - return isExportStatement(exportsLocation, exp) || !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name + return !nextExport || exp.type !== nextExport.type || !exp.name || exp.name !== nextExport.name }) } @@ -139,8 +143,8 @@ interface TokenLocation { start: number end: number } -function isExportStatement (exportsLcation: TokenLocation[], exp) { - return exportsLcation.some(location => exp.start <= location.start && exp.end >= location.end) +function isExportStatement (exportsLocation: TokenLocation[], exp: ESMExport) { + return exportsLocation.some(location => exp.start <= location.start && exp.end >= location.end) } function getExportTokenLocation (code: string) { From a1b5113db1652a6804543c1998c5aa6a90f72bfc Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 3 Aug 2022 11:43:04 +0200 Subject: [PATCH 10/12] update lockfile --- pnpm-lock.yaml | 262 ++++++++----------------------------------------- 1 file changed, 43 insertions(+), 219 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62ea727..61a36bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,7 +3,6 @@ lockfileVersion: 5.4 specifiers: '@nuxtjs/eslint-config-typescript': latest '@types/node': latest - acorn: ^8.7.1 c8: latest eslint: latest jiti: latest @@ -346,6 +345,7 @@ packages: eslint-import-resolver-typescript: 2.7.1_jatgrcxl4x7ywe7ak6cnjca2ae eslint-plugin-import: 2.26.0_dz7i2j5664xvifouca6ivxrh7a transitivePeerDependencies: + - eslint-import-resolver-webpack - supports-color - typescript dev: true @@ -364,6 +364,9 @@ packages: eslint-plugin-unicorn: 42.0.0_eslint@8.21.0 eslint-plugin-vue: 8.7.1_eslint@8.21.0 transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack - supports-color dev: true @@ -637,6 +640,7 @@ packages: resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /add-stream/1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} @@ -1119,12 +1123,22 @@ packages: /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.0.0 dev: true /debug/3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true dependencies: ms: 2.1.3 dev: true @@ -1280,15 +1294,6 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild-android-64/0.14.44: - resolution: {integrity: sha512-dFPHBXmx385zuJULAD/Cmq/LyPRXiAWbf9ylZtY0wJ8iVyWfKYaCYxeJx8OAZUuj46ZwNa7MzW2GBAQLOeiemg==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true - optional: true - /esbuild-android-64/0.14.53: resolution: {integrity: sha512-fIL93sOTnEU+NrTAVMIKiAw0YH22HWCAgg4N4Z6zov2t0kY9RAJ50zY9ZMCQ+RT6bnOfDt8gCTnt/RaSNA2yRA==} engines: {node: '>=12'} @@ -1298,15 +1303,6 @@ packages: dev: true optional: true - /esbuild-android-arm64/0.14.44: - resolution: {integrity: sha512-qqaqqyxHXjZ/0ddKU3I3Nb7lAvVM69ELMhb8+91FyomAUmQPlHtxe+TTiWxXGHE72XEzcgTEGq4VauqLNkN22g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true - optional: true - /esbuild-android-arm64/0.14.53: resolution: {integrity: sha512-PC7KaF1v0h/nWpvlU1UMN7dzB54cBH8qSsm7S9mkwFA1BXpaEOufCg8hdoEI1jep0KeO/rjZVWrsH8+q28T77A==} engines: {node: '>=12'} @@ -1316,15 +1312,6 @@ packages: dev: true optional: true - /esbuild-darwin-64/0.14.44: - resolution: {integrity: sha512-RBmtGKGY06+AW6IOJ1LE/dEeF7HH34C1/Ces9FSitU4bIbIpL4KEuQpTFoxwb4ry5s2hyw7vbPhhtyOd18FH9g==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /esbuild-darwin-64/0.14.53: resolution: {integrity: sha512-gE7P5wlnkX4d4PKvLBUgmhZXvL7lzGRLri17/+CmmCzfncIgq8lOBvxGMiQ4xazplhxq+72TEohyFMZLFxuWvg==} engines: {node: '>=12'} @@ -1334,15 +1321,6 @@ packages: dev: true optional: true - /esbuild-darwin-arm64/0.14.44: - resolution: {integrity: sha512-Bmhx5Cfo4Hdb7WyyyDupTB8HPmnFZ8baLfPlzLdYvF6OzsIbV+CY+m/AWf0OQvY40BlkzCLJ/7Lfwbb71Tngmg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /esbuild-darwin-arm64/0.14.53: resolution: {integrity: sha512-otJwDU3hnI15Q98PX4MJbknSZ/WSR1I45il7gcxcECXzfN4Mrpft5hBDHXNRnCh+5858uPXBXA1Vaz2jVWLaIA==} engines: {node: '>=12'} @@ -1352,15 +1330,6 @@ packages: dev: true optional: true - /esbuild-freebsd-64/0.14.44: - resolution: {integrity: sha512-O4HpWa5ZgxbNPQTF7URicLzYa+TidGlmGT/RAC3GjbGEQQYkd0R1Slyh69Yrmb2qmcOcPAgWHbNo1UhK4WmZ4w==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - /esbuild-freebsd-64/0.14.53: resolution: {integrity: sha512-WkdJa8iyrGHyKiPF4lk0MiOF87Q2SkE+i+8D4Cazq3/iqmGPJ6u49je300MFi5I2eUsQCkaOWhpCVQMTKGww2w==} engines: {node: '>=12'} @@ -1370,15 +1339,6 @@ packages: dev: true optional: true - /esbuild-freebsd-arm64/0.14.44: - resolution: {integrity: sha512-f0/jkAKccnDY7mg1F9l/AMzEm+VXWXK6c3IrOEmd13jyKfpTZKTIlt+yI04THPDCDZTzXHTRUBLozqp+m8Mg5Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true - optional: true - /esbuild-freebsd-arm64/0.14.53: resolution: {integrity: sha512-9T7WwCuV30NAx0SyQpw8edbKvbKELnnm1FHg7gbSYaatH+c8WJW10g/OdM7JYnv7qkimw2ZTtSA+NokOLd2ydQ==} engines: {node: '>=12'} @@ -1388,15 +1348,6 @@ packages: dev: true optional: true - /esbuild-linux-32/0.14.44: - resolution: {integrity: sha512-WSIhzLldMR7YUoEL7Ix319tC+NFmW9Pu7NgFWxUfOXeWsT0Wg484hm6bNgs7+oY2pGzg715y/Wrqi1uNOMmZJw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-32/0.14.53: resolution: {integrity: sha512-VGanLBg5en2LfGDgLEUxQko2lqsOS7MTEWUi8x91YmsHNyzJVT/WApbFFx3MQGhkf+XdimVhpyo5/G0PBY91zg==} engines: {node: '>=12'} @@ -1406,15 +1357,6 @@ packages: dev: true optional: true - /esbuild-linux-64/0.14.44: - resolution: {integrity: sha512-zgscTrCMcRZRIsVugqBTP/B5lPLNchBlWjQ8sQq2Epnv+UDtYKgXEq1ctWAmibZNy2E9QRCItKMeIEqeTUT5kA==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-64/0.14.53: resolution: {integrity: sha512-pP/FA55j/fzAV7N9DF31meAyjOH6Bjuo3aSKPh26+RW85ZEtbJv9nhoxmGTd9FOqjx59Tc1ZbrJabuiXlMwuZQ==} engines: {node: '>=12'} @@ -1424,15 +1366,6 @@ packages: dev: true optional: true - /esbuild-linux-arm/0.14.44: - resolution: {integrity: sha512-laPBPwGfsbBxGw6F6jnqic2CPXLyC1bPrmnSOeJ9oEnx1rcKkizd4HWCRUc0xv+l4z/USRfx/sEfYlWSLeqoJQ==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-arm/0.14.53: resolution: {integrity: sha512-/u81NGAVZMopbmzd21Nu/wvnKQK3pT4CrvQ8BTje1STXcQAGnfyKgQlj3m0j2BzYbvQxSy+TMck4TNV2onvoPA==} engines: {node: '>=12'} @@ -1442,15 +1375,6 @@ packages: dev: true optional: true - /esbuild-linux-arm64/0.14.44: - resolution: {integrity: sha512-H0H/2/wgiScTwBve/JR8/o+Zhabx5KPk8T2mkYZFKQGl1hpUgC+AOmRyqy/Js3p66Wim4F4Akv3I3sJA1sKg0w==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-arm64/0.14.53: resolution: {integrity: sha512-GDmWITT+PMsjCA6/lByYk7NyFssW4Q6in32iPkpjZ/ytSyH+xeEx8q7HG3AhWH6heemEYEWpTll/eui3jwlSnw==} engines: {node: '>=12'} @@ -1460,15 +1384,6 @@ packages: dev: true optional: true - /esbuild-linux-mips64le/0.14.44: - resolution: {integrity: sha512-ri3Okw0aleYy7o5n9zlIq+FCtq3tcMlctN6X1H1ucILjBJuH8pan2trJPKWeb8ppntFvE28I9eEXhwkWh6wYKg==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-mips64le/0.14.53: resolution: {integrity: sha512-d6/XHIQW714gSSp6tOOX2UscedVobELvQlPMkInhx1NPz4ThZI9uNLQ4qQJHGBGKGfu+rtJsxM4NVHLhnNRdWQ==} engines: {node: '>=12'} @@ -1478,15 +1393,6 @@ packages: dev: true optional: true - /esbuild-linux-ppc64le/0.14.44: - resolution: {integrity: sha512-96TqL/MvFRuIVXz+GtCIXzRQ43ZwEk4XTn0RWUNJduXXMDQ/V1iOV28U6x6Oe3NesK4xkoKSaK2+F3VHcU8ZrA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-ppc64le/0.14.53: resolution: {integrity: sha512-ndnJmniKPCB52m+r6BtHHLAOXw+xBCWIxNnedbIpuREOcbSU/AlyM/2dA3BmUQhsHdb4w3amD5U2s91TJ3MzzA==} engines: {node: '>=12'} @@ -1496,15 +1402,6 @@ packages: dev: true optional: true - /esbuild-linux-riscv64/0.14.44: - resolution: {integrity: sha512-rrK9qEp2M8dhilsPn4T9gxUsAumkITc1kqYbpyNMr9EWo+J5ZBj04n3GYldULrcCw4ZCHAJ+qPjqr8b6kG2inA==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-riscv64/0.14.53: resolution: {integrity: sha512-yG2sVH+QSix6ct4lIzJj329iJF3MhloLE6/vKMQAAd26UVPVkhMFqFopY+9kCgYsdeWvXdPgmyOuKa48Y7+/EQ==} engines: {node: '>=12'} @@ -1514,15 +1411,6 @@ packages: dev: true optional: true - /esbuild-linux-s390x/0.14.44: - resolution: {integrity: sha512-2YmTm9BrW5aUwBSe8wIEARd9EcnOQmkHp4+IVaO09Ez/C5T866x+ABzhG0bwx0b+QRo9q97CRMaQx2Ngb6/hfw==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true - optional: true - /esbuild-linux-s390x/0.14.53: resolution: {integrity: sha512-OCJlgdkB+XPYndHmw6uZT7jcYgzmx9K+28PVdOa/eLjdoYkeAFvH5hTwX4AXGLZLH09tpl4bVsEtvuyUldaNCg==} engines: {node: '>=12'} @@ -1532,15 +1420,6 @@ packages: dev: true optional: true - /esbuild-netbsd-64/0.14.44: - resolution: {integrity: sha512-zypdzPmZTCqYS30WHxbcvtC0E6e/ECvl4WueUdbdWhs2dfWJt5RtCBME664EpTznixR3lSN1MQ2NhwQF8MQryw==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true - optional: true - /esbuild-netbsd-64/0.14.53: resolution: {integrity: sha512-gp2SB+Efc7MhMdWV2+pmIs/Ja/Mi5rjw+wlDmmbIn68VGXBleNgiEZG+eV2SRS0kJEUyHNedDtwRIMzaohWedQ==} engines: {node: '>=12'} @@ -1550,15 +1429,6 @@ packages: dev: true optional: true - /esbuild-openbsd-64/0.14.44: - resolution: {integrity: sha512-8J43ab9ByYl7KteC03HGQjr2HY1ge7sN04lFnwMFWYk2NCn8IuaeeThvLeNjzOYhyT3I6K8puJP0uVXUu+D1xw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true - /esbuild-openbsd-64/0.14.53: resolution: {integrity: sha512-eKQ30ZWe+WTZmteDYg8S+YjHV5s4iTxeSGhJKJajFfQx9TLZJvsJX0/paqwP51GicOUruFpSUAs2NCc0a4ivQQ==} engines: {node: '>=12'} @@ -1568,15 +1438,6 @@ packages: dev: true optional: true - /esbuild-sunos-64/0.14.44: - resolution: {integrity: sha512-OH1/09CGUJwffA+HNM6mqPkSIyHVC3ZnURU/4CCIx7IqWUBn1Sh1HRLQC8/TWNgcs0/1u7ygnc2pgf/AHZJ/Ow==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true - /esbuild-sunos-64/0.14.53: resolution: {integrity: sha512-OWLpS7a2FrIRukQqcgQqR1XKn0jSJoOdT+RlhAxUoEQM/IpytS3FXzCJM6xjUYtpO5GMY0EdZJp+ur2pYdm39g==} engines: {node: '>=12'} @@ -1586,15 +1447,6 @@ packages: dev: true optional: true - /esbuild-windows-32/0.14.44: - resolution: {integrity: sha512-mCAOL9/rRqwfOfxTu2sjq/eAIs7eAXGiU6sPBnowggI7QS953Iq6o3/uDu010LwfN7zr18c/lEj6/PTwwTB3AA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - /esbuild-windows-32/0.14.53: resolution: {integrity: sha512-m14XyWQP5rwGW0tbEfp95U6A0wY0DYPInWBB7D69FAXUpBpBObRoGTKRv36lf2RWOdE4YO3TNvj37zhXjVL5xg==} engines: {node: '>=12'} @@ -1604,15 +1456,6 @@ packages: dev: true optional: true - /esbuild-windows-64/0.14.44: - resolution: {integrity: sha512-AG6BH3+YG0s2Q/IfB1cm68FdyFnoE1P+GFbmgFO3tA4UIP8+BKsmKGGZ5I3+ZjcnzOwvT74bQRVrfnQow2KO5Q==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /esbuild-windows-64/0.14.53: resolution: {integrity: sha512-s9skQFF0I7zqnQ2K8S1xdLSfZFsPLuOGmSx57h2btSEswv0N0YodYvqLcJMrNMXh6EynOmWD7rz+0rWWbFpIHQ==} engines: {node: '>=12'} @@ -1622,15 +1465,6 @@ packages: dev: true optional: true - /esbuild-windows-arm64/0.14.44: - resolution: {integrity: sha512-ygYPfYE5By4Sd6szsNr10B0RtWVNOSGmZABSaj4YQBLqh9b9i45VAjVWa8tyIy+UAbKF7WGwybi2wTbSVliO8A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /esbuild-windows-arm64/0.14.53: resolution: {integrity: sha512-E+5Gvb+ZWts+00T9II6wp2L3KG2r3iGxByqd/a1RmLmYWVsSVUjkvIxZuJ3hYTIbhLkH5PRwpldGTKYqVz0nzQ==} engines: {node: '>=12'} @@ -1640,34 +1474,6 @@ packages: dev: true optional: true - /esbuild/0.14.44: - resolution: {integrity: sha512-Rn+lRRfj60r/3svI6NgAVnetzp3vMOj17BThuhshSj/gS1LR03xrjkDYyfPmrYG/0c3D68rC6FNYMQ3yRbiXeQ==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - esbuild-android-64: 0.14.44 - esbuild-android-arm64: 0.14.44 - esbuild-darwin-64: 0.14.44 - esbuild-darwin-arm64: 0.14.44 - esbuild-freebsd-64: 0.14.44 - esbuild-freebsd-arm64: 0.14.44 - esbuild-linux-32: 0.14.44 - esbuild-linux-64: 0.14.44 - esbuild-linux-arm: 0.14.44 - esbuild-linux-arm64: 0.14.44 - esbuild-linux-mips64le: 0.14.44 - esbuild-linux-ppc64le: 0.14.44 - esbuild-linux-riscv64: 0.14.44 - esbuild-linux-s390x: 0.14.44 - esbuild-netbsd-64: 0.14.44 - esbuild-openbsd-64: 0.14.44 - esbuild-sunos-64: 0.14.44 - esbuild-windows-32: 0.14.44 - esbuild-windows-64: 0.14.44 - esbuild-windows-arm64: 0.14.44 - dev: true - /esbuild/0.14.53: resolution: {integrity: sha512-ohO33pUBQ64q6mmheX1mZ8mIXj8ivQY/L4oVuAshr+aJI+zLl+amrp3EodrUNDNYVrKJXGPfIHFGhO8slGRjuw==} engines: {node: '>=12'} @@ -1731,6 +1537,8 @@ packages: dependencies: debug: 3.2.7 resolve: 1.22.0 + transitivePeerDependencies: + - supports-color dev: true /eslint-import-resolver-typescript/2.7.1_jatgrcxl4x7ywe7ak6cnjca2ae: @@ -1754,12 +1562,28 @@ packages: /eslint-module-utils/2.7.3_pbmiczca3qpqvnkfcriol7sq7u: resolution: {integrity: sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==} engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true dependencies: '@typescript-eslint/parser': 5.28.0_eslint@8.21.0 debug: 3.2.7 eslint-import-resolver-node: 0.3.6 eslint-import-resolver-typescript: 2.7.1_jatgrcxl4x7ywe7ak6cnjca2ae find-up: 2.1.0 + transitivePeerDependencies: + - supports-color dev: true /eslint-plugin-es/3.0.1_eslint@8.21.0: @@ -1788,7 +1612,11 @@ packages: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: + '@typescript-eslint/parser': '*' eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true dependencies: '@typescript-eslint/parser': 5.28.0_eslint@8.21.0 array-includes: 3.1.4 @@ -1805,6 +1633,10 @@ packages: object.values: 1.1.5 resolve: 1.22.0 tsconfig-paths: 3.14.1 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color dev: true /eslint-plugin-n/15.2.3_eslint@8.21.0: @@ -3320,14 +3152,6 @@ packages: - supports-color dev: true - /rollup/2.70.1: - resolution: {integrity: sha512-CRYsI5EuzLbXdxC6RnYhOuRdtz4bhejPMSWjsFLfVM/7w/85n2szZv6yExqUXsBdz5KT8eoubeyDUDjhLHEslA==} - engines: {node: '>=10.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.2 - dev: true - /rollup/2.77.2: resolution: {integrity: sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==} engines: {node: '>=10.0.0'} @@ -3803,10 +3627,10 @@ packages: stylus: optional: true dependencies: - esbuild: 0.14.44 + esbuild: 0.14.53 postcss: 8.4.14 resolve: 1.22.0 - rollup: 2.70.1 + rollup: 2.77.2 optionalDependencies: fsevents: 2.3.2 dev: true From f1bd6727a7e1d95d12d4d5d92fb02565c61cb589 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 3 Aug 2022 11:45:09 +0200 Subject: [PATCH 11/12] add back acorn dep --- package.json | 1 + pnpm-lock.yaml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index e7451db..f8291d7 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "test": "pnpm lint && vitest run" }, "dependencies": { + "acorn": "^8.8.0", "pathe": "^0.3.3", "pkg-types": "^0.3.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61a36bb..47d7375 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,6 +3,7 @@ lockfileVersion: 5.4 specifiers: '@nuxtjs/eslint-config-typescript': latest '@types/node': latest + acorn: ^8.8.0 c8: latest eslint: latest jiti: latest @@ -13,6 +14,7 @@ specifiers: vitest: latest dependencies: + acorn: 8.8.0 pathe: 0.3.3 pkg-types: 0.3.3 @@ -640,7 +642,6 @@ packages: resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} engines: {node: '>=0.4.0'} hasBin: true - dev: true /add-stream/1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} From 0a6161731569d6a33b9892484a535f2739910646 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Wed, 3 Aug 2022 11:51:22 +0200 Subject: [PATCH 12/12] perf: tokenize if there are export matches --- src/analyze.ts | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/analyze.ts b/src/analyze.ts index 22d493e..ce5fbf6 100644 --- a/src/analyze.ts +++ b/src/analyze.ts @@ -94,11 +94,6 @@ export function parseStaticImport (matched: StaticImport): ParsedStaticImport { } export function findExports (code: string): ESMExport[] { - // Return early when there is no legal export statement - const exportsLocation = getExportTokenLocation(code) - if (!exportsLocation.length) { - return [] - } // Find declarations like export const foo = 'bar' const declaredExports: DeclarationExport[] = matchAll(EXPORT_DECAL_RE, code, { type: 'declaration' }) @@ -128,9 +123,19 @@ export function findExports (code: string): ESMExport[] { exp.names = [exp.name] } } + + // Return early when there is no export statement + if (!exports.length) { + return [] + } + const exportLocations = _getExportLocations(code) + if (!exportLocations.length) { + return [] + } + return exports.filter((exp, index, exports) => { - // Filter out noise that does not match the semantics of export - if (!isExportStatement(exportsLocation, exp)) { + // Filter false positive export matches + if (!_isExportStatement(exportLocations, exp)) { return false } // Prevent multiple exports of same function, only keep latest iteration of signatures @@ -139,15 +144,18 @@ export function findExports (code: string): ESMExport[] { }) } +// --- Internal --- + interface TokenLocation { start: number end: number } -function isExportStatement (exportsLocation: TokenLocation[], exp: ESMExport) { + +function _isExportStatement (exportsLocation: TokenLocation[], exp: ESMExport) { return exportsLocation.some(location => exp.start <= location.start && exp.end >= location.end) } -function getExportTokenLocation (code: string) { +function _getExportLocations (code: string) { const tokens = tokenizer(code, { ecmaVersion: 'latest', sourceType: 'module',