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

fix: revert using acorn tokenizer #65

Closed
wants to merge 3 commits into from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
"test": "pnpm lint && vitest run"
},
"dependencies": {
"acorn": "^8.8.0",
"pathe": "^0.3.3",
"pkg-types": "^0.3.3"
},
Expand Down
5 changes: 2 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 0 additions & 45 deletions src/analyze.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { tokenizer } from 'acorn'
import { matchAll } from './_utils'
import { resolvePath, ResolveOptions } from './resolve'
import { loadURL } from './utils'
Expand Down Expand Up @@ -126,20 +125,7 @@ export function findExports (code: string): ESMExport[] {
}
}

// 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 false positive export matches
if (!_isExportStatement(exportLocations, 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
Expand All @@ -156,34 +142,3 @@ export async function resolveModuleExportNames (id: string, opts?: ResolveOption
const exports = findExports(code)
return exports.flatMap(exp => exp.names)
}

// --- Internal ---

interface TokenLocation {
start: number
end: number
}

function _isExportStatement (exportsLocation: TokenLocation[], exp: ESMExport) {
return exportsLocation.some(location => exp.start <= location.start && exp.end >= location.end)
}

function _getExportLocations (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
}
78 changes: 41 additions & 37 deletions test/exports.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ describe('findExports', () => {
'export { useA , useB , } from "./path"': { type: 'named', names: ['useA', 'useB'], specifier: './path' },
'export async function foo ()': { type: 'declaration', names: ['foo'] },
'export const $foo = () => {}': { type: 'declaration', names: ['$foo'] },
// eslint-disable-next-line
'const a = `<div${JSON.stringify({ class: 42 })}>`;\nexport const $foo = () => {}': { type: 'declaration', names: ['$foo'] },
'export { foo as default }': { type: 'default', name: 'default', names: ['default'] },
'export * from "./other"': { type: 'star', specifier: './other' },
'export * as foo from "./other"': { type: 'star', specifier: './other', name: 'foo' }
Expand All @@ -39,54 +41,56 @@ 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', () => {
// TODO: https://github.com/unjs/mlly/issues/64
it.todo('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', () => {
// TODO: https://github.com/unjs/mlly/issues/64
it.todo('export in string', () => {
const tests: string[] = [
'export function useA () { return \'a\' }',
'export const useD = () => { return \'d\' }',
Expand Down Expand Up @@ -119,9 +123,9 @@ describe('findExports', () => {
describe('fineExportNames', () => {
it('findExportNames', () => {
expect(findExportNames(`
export const foo = 'bar'
export { bar, baz }
export default something
export const foo = 'bar'
export { bar, baz }
export default something
`)).toMatchInlineSnapshot(`
[
"foo",
Expand Down