diff --git a/src/index.ts b/src/index.ts index b0b6e23..7c2e547 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,4 +2,5 @@ export * from './analyze' export * from './cjs' export * from './eval' export * from './resolve' +export * from './syntax' export * from './utils' diff --git a/src/syntax.ts b/src/syntax.ts new file mode 100644 index 0000000..206b491 --- /dev/null +++ b/src/syntax.ts @@ -0,0 +1,21 @@ +const ESM_RE = /([\s;]|^)(import[\s'"*{]|export\b|import\.meta\b)/m + +export function hasESMSyntax (code: string): boolean { + return ESM_RE.test(code) +} + +const CJS_RE = /([\s;]|^)(module.exports\b|exports\.|require\s*\(|global\b)/m +export function hasCJSSyntax (code: string): boolean { + return CJS_RE.test(code) +} + +export function detectSyntax (code: string) { + const hasESM = hasESMSyntax(code) + const hasCJS = hasCJSSyntax(code) + + return { + hasESM, + hasCJS, + isMixed: hasESM && hasCJS + } +} diff --git a/test/syntax.test.mjs b/test/syntax.test.mjs new file mode 100644 index 0000000..65d5aa3 --- /dev/null +++ b/test/syntax.test.mjs @@ -0,0 +1,37 @@ +import { expect } from 'chai' +import { detectSyntax } from 'mlly' + +const staticTests = { + // ESM + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#syntax + 'import defaultExport from "module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import * as name from "module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import { export1 } from "module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import { export1 as alias1 } from "module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import { export1, export2 } from "module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import { export1, export2 as alias2, export3 } from "module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import defaultExport, { export1, export2 } from "module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import defaultExport, * as name from"module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import"module-name"': { hasESM: true, hasCJS: false, isMixed: false }, + // + 'import defaultMember from "module-name";': { hasESM: true, hasCJS: false, isMixed: false }, + 'import "./file.mjs"': { hasESM: true, hasCJS: false, isMixed: false }, + 'export default b=""': { hasESM: true, hasCJS: false, isMixed: false }, + // CJS + 'exports.c={}': { hasESM: false, hasCJS: true, isMixed: false }, + 'const b=true;module.exports={b};': { hasESM: false, hasCJS: true, isMixed: false }, + // Mixed + 'import"module-name";module.exports={};': { hasESM: true, hasCJS: true, isMixed: true }, + // No clues + 'import("./file.mjs")': { hasESM: false, hasCJS: false, isMixed: false }, + 'console.log(process.version)': { hasESM: false, hasCJS: false, isMixed: false }, + 'const a={};': { hasESM: false, hasCJS: false, isMixed: false } +} + +describe('detectSyntax', () => { + for (const [input, result] of Object.entries(staticTests)) { + it(input, () => { + expect(detectSyntax(input)).to.deep.equal(result) + }) + } +})