requirejs-esm 4.2.0 → 4.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +14 -1
- package/bin/esm2requirejs.js +10 -4
- package/dist/api.js +212 -126
- package/dist/api.js.map +1 -1
- package/dist/plugin.js +215 -123
- package/dist/plugin.js.map +1 -1
- package/package.json +10 -12
- package/src/api.d.ts +3 -0
- package/src/api.js +6 -1
- package/src/fetch-text.js +1 -1
- package/src/plugin.js +8 -1
- package/src/resolve-path.js +1 -1
- package/src/transform.js +16 -2
- package/src/transformer/comments.js +16 -0
- package/src/transformer/converters.js +2 -4
- package/src/transformer/esm.js +56 -36
- package/src/transformer/index.js +3 -3
- package/src/write-text.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "requirejs-esm",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "A RequireJS plugin converting JavaScript modules from ESM to AMD.",
|
|
5
5
|
"author": "Ferdinand Prantl <prantlf@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"demo:local": "npm run optimize:local && npm run minify:local",
|
|
42
42
|
"optimize:local": "r.js -o demo-local/build.config.js",
|
|
43
43
|
"minify:local": "terser -cm --ecma 2018 --comments false --source-map content=demo-local/main-built.js.map --source-map includeSources --source-map url=main-built.min.js.map -o demo-local/main-built.min.js demo-local/main-built.js",
|
|
44
|
-
"lint": "
|
|
44
|
+
"lint": "biome lint src bin perf/*.js bin test/*.js",
|
|
45
45
|
"fix": "npm run lint -- --fix",
|
|
46
46
|
"check": "tehanu test/*.js",
|
|
47
47
|
"cover": "c8 node test && c8 --no-clean ./bin/esm2requirejs.js && c8 --no-clean ./bin/esm2requirejs.js test/input/esm-import-all.js && c8 --no-clean ./bin/esm2requirejs.js dummy || c8 report -r text -r lcov | grep -Ev '(\\.\\.\\.)|(index.mjs)|(source-map.js)|(base64-vlq.js)|(base64.js)|(binary-search.js)|(mapping-list.js)|(read-wasm-browser.js)|(url-browser.js)|(wasm.js)|(regexes.js)|(public-api.js)|(All files)' && c8 check-coverage",
|
|
@@ -71,27 +71,25 @@
|
|
|
71
71
|
"@prantlf/convert-source-map": "^3.0.2",
|
|
72
72
|
"astring": "^1.9.0",
|
|
73
73
|
"charcodes": "^0.2.1",
|
|
74
|
-
"commander": "^14.0.
|
|
75
|
-
"meriyah": "^7.
|
|
74
|
+
"commander": "^14.0.3",
|
|
75
|
+
"meriyah": "^7.1.0",
|
|
76
76
|
"punycode": "^2.3.1",
|
|
77
77
|
"source-map": "^0.8.0-beta.0",
|
|
78
78
|
"tiny-glob": "^0.2.9"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@
|
|
82
|
-
"@prantlf/requirejs": "^3.
|
|
83
|
-
"@rollup/plugin-commonjs": "^29.0.
|
|
81
|
+
"@biomejs/biome": "^2.4.16",
|
|
82
|
+
"@prantlf/requirejs": "^3.4.0",
|
|
83
|
+
"@rollup/plugin-commonjs": "^29.0.3",
|
|
84
84
|
"@rollup/plugin-json": "^6.1.0",
|
|
85
85
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
86
|
-
"c8": "^
|
|
87
|
-
"eslint": "^9.39.1",
|
|
88
|
-
"globals": "^16.5.0",
|
|
86
|
+
"c8": "^11.0.0",
|
|
89
87
|
"lit-html": "^1",
|
|
90
|
-
"rollup": "^4.
|
|
88
|
+
"rollup": "^4.61.1",
|
|
91
89
|
"tehanu": "^1.0.1",
|
|
92
90
|
"tehanu-repo-coco": "^1.0.1",
|
|
93
91
|
"tehanu-teru": "^1.0.1",
|
|
94
|
-
"terser": "^5.
|
|
92
|
+
"terser": "^5.48.0"
|
|
95
93
|
},
|
|
96
94
|
"keywords": [
|
|
97
95
|
"requirejs-plugin",
|
package/src/api.d.ts
CHANGED
|
@@ -26,7 +26,10 @@ type OnAfterUpdate = (options: AmdOptions) => boolean
|
|
|
26
26
|
interface TransformAstOptions {
|
|
27
27
|
pluginName?: string /*= 'esm'' */
|
|
28
28
|
resolvePath?: ResolvePath
|
|
29
|
+
skipIfNoImportExport?: boolean /*= false */
|
|
29
30
|
useStrict?: boolean /*= true */
|
|
31
|
+
splitDefaultNamedDeclarations?: boolean /*= false */
|
|
32
|
+
sourceMap?: boolean /*= false */
|
|
30
33
|
onBeforeTransform?: OnBeforeTransform
|
|
31
34
|
onAfterTransform?: OnAfterTransform
|
|
32
35
|
onBeforeUpdate?: OnBeforeUpdate
|
package/src/api.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
export { resolvePath } from './resolve-path'
|
|
2
2
|
export { default as transform } from './transform'
|
|
3
|
-
export {
|
|
3
|
+
export {
|
|
4
|
+
transformAst,
|
|
5
|
+
detectDefinesOrRequires,
|
|
6
|
+
detectImportsAndExports,
|
|
7
|
+
processOrSkipByComment
|
|
8
|
+
} from './transformer'
|
package/src/fetch-text.js
CHANGED
|
@@ -21,7 +21,7 @@ if (typeof window !== 'undefined' && window.navigator && window.document) {
|
|
|
21
21
|
xhr.send(null)
|
|
22
22
|
}
|
|
23
23
|
} else {
|
|
24
|
-
const { readFileSync } = require.nodeRequire ? require.nodeRequire('fs') : require('fs')
|
|
24
|
+
const { readFileSync } = require.nodeRequire ? require.nodeRequire('fs') : require('node:fs')
|
|
25
25
|
fetchText = (path, callback) => {
|
|
26
26
|
// Asynchronous reading is not possible during the build in the optimizer.
|
|
27
27
|
try {
|
package/src/plugin.js
CHANGED
|
@@ -16,6 +16,8 @@ const {
|
|
|
16
16
|
onlyAmd,
|
|
17
17
|
// List of module names not to check and transform.
|
|
18
18
|
skipModules = [],
|
|
19
|
+
// Assume AMD/UMD if there're no import or export statements.
|
|
20
|
+
skipIfNoImportExport,
|
|
19
21
|
// Method to update paths of module dependencies, to prefix JavaScript module
|
|
20
22
|
// name with `esm!`, above all.
|
|
21
23
|
resolvePath,
|
|
@@ -23,6 +25,9 @@ const {
|
|
|
23
25
|
// Do not insert `"use strict"` expression to the AMD modules. You'd set it
|
|
24
26
|
// to `false` if your bundler inserts `"use strict"` to the outer scope.
|
|
25
27
|
useStrict,
|
|
28
|
+
// Split `export default class A {}` to `class A {}; export default A`
|
|
29
|
+
// to trade easier AST manipulation for 100% code compatibility.
|
|
30
|
+
splitDefaultNamedDeclarations,
|
|
26
31
|
// Boolean or object with booleans { inline, content }.
|
|
27
32
|
sourceMap,
|
|
28
33
|
// Enable console logging.
|
|
@@ -112,6 +117,8 @@ export default {
|
|
|
112
117
|
resolvePath,
|
|
113
118
|
/*ecmaVersion,*/
|
|
114
119
|
useStrict,
|
|
120
|
+
skipIfNoImportExport,
|
|
121
|
+
splitDefaultNamedDeclarations,
|
|
115
122
|
// Always produce the source maps when transpiling in the browser, otherwise
|
|
116
123
|
// the debugging would me impossible. When building and bundling, check if
|
|
117
124
|
// the source maps were enabled for the output.
|
|
@@ -156,7 +163,7 @@ export default {
|
|
|
156
163
|
// compiled with esm refer it with that name and this stub will simplify
|
|
157
164
|
// the module loading by skipping the plugin evaluation.
|
|
158
165
|
write.asModule(`${pluginName}!${moduleName}`,
|
|
159
|
-
|
|
166
|
+
`\ndefine(['${moduleName}'], res => res);\n`)
|
|
160
167
|
}
|
|
161
168
|
//>>excludeEnd('excludeEsm')
|
|
162
169
|
}
|
package/src/resolve-path.js
CHANGED
|
@@ -71,7 +71,7 @@ export function resolvePath (sourcePath, currentFile, { pluginName, needsResolve
|
|
|
71
71
|
// mapped there using the `paths` of `map` configuration properties.
|
|
72
72
|
if ((sourcePath.charAt(0) === '.' && (sourcePath.charAt(1) === '/' ||
|
|
73
73
|
sourcePath.charAt(1) === '.' && sourcePath.charAt(2) === '/')) &&
|
|
74
|
-
!(needsResolve
|
|
74
|
+
!(needsResolve?.(sourcePath, currentFile))) {
|
|
75
75
|
sourcePath = joinPath(parentDir(currentFile), sourcePath)
|
|
76
76
|
if (sourcePath.endsWith('.js')) sourcePath = sourcePath.substring(0, sourcePath.length - 3)
|
|
77
77
|
}
|
package/src/transform.js
CHANGED
|
@@ -4,7 +4,7 @@ import { parseModule } from 'meriyah'
|
|
|
4
4
|
import { generate } from 'astring'
|
|
5
5
|
import { SourceMapGenerator } from 'source-map'
|
|
6
6
|
import convert from '@prantlf/convert-source-map'
|
|
7
|
-
import { transformAst } from './transformer'
|
|
7
|
+
import { transformAst, processOrSkipByComment } from './transformer'
|
|
8
8
|
|
|
9
9
|
export default function transform(text, file, {
|
|
10
10
|
// Allow using a different plugin alias than `esm` in the source code.
|
|
@@ -12,10 +12,15 @@ export default function transform(text, file, {
|
|
|
12
12
|
// Method to update paths of module dependencies, to prefix JavaScript module
|
|
13
13
|
// name with `esm!`, above all.
|
|
14
14
|
resolvePath = originalResolvePath,
|
|
15
|
+
// Assume AMD/UMD if there're no import or export statements.
|
|
16
|
+
skipIfNoImportExport,
|
|
15
17
|
// ecmaVersion = 2020,
|
|
16
18
|
// Do not insert `"use strict"` expression to the AMD modules. You'd set it
|
|
17
19
|
// to `false` if your bundler inserts `"use strict"` to the outer scope.
|
|
18
20
|
useStrict,
|
|
21
|
+
// Split `export default class A {}` to `class A {}; export default A`
|
|
22
|
+
// to trade easier AST manipulation for 100% code compatibility.
|
|
23
|
+
splitDefaultNamedDeclarations,
|
|
19
24
|
// Enable source maps, can be an object with booleans { inline, content }.
|
|
20
25
|
// If set to true, the object will be set to { inline: true, content: true }.
|
|
21
26
|
sourceMap,
|
|
@@ -26,8 +31,15 @@ export default function transform(text, file, {
|
|
|
26
31
|
onBeforeUpdate,
|
|
27
32
|
onAfterUpdate
|
|
28
33
|
} = {}) {
|
|
34
|
+
const processOrSkip = processOrSkipByComment(text)
|
|
35
|
+
if (processOrSkip === false) {
|
|
36
|
+
return { code: text, map: null, updated: false }
|
|
37
|
+
} else if (processOrSkip === true) {
|
|
38
|
+
skipIfNoImportExport = undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
29
41
|
// const ast = parse(text, { ecmaVersion, sourceType: 'module', locations: true })
|
|
30
|
-
|
|
42
|
+
const ast = parseModule(text, { next: true, loc: true })
|
|
31
43
|
|
|
32
44
|
const options = {
|
|
33
45
|
sourceFileName: file,
|
|
@@ -35,6 +47,8 @@ export default function transform(text, file, {
|
|
|
35
47
|
resolvePath,
|
|
36
48
|
originalResolvePath,
|
|
37
49
|
useStrict,
|
|
50
|
+
skipIfNoImportExport,
|
|
51
|
+
splitDefaultNamedDeclarations,
|
|
38
52
|
onBeforeTransform,
|
|
39
53
|
onAfterTransform,
|
|
40
54
|
onBeforeUpdate,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Check if one of the first 10 lines shorter than 100 characters contains
|
|
2
|
+
// "// requirejs-esm-skip-file" or // requirejs-esm-process-file".
|
|
3
|
+
export function processOrSkipByComment(text) {
|
|
4
|
+
for (let start = 0, i = 0; i < 10; ++i) {
|
|
5
|
+
const endLine = text.indexOf('\n', start)
|
|
6
|
+
if (endLine < 0 || endLine > 100) break
|
|
7
|
+
const line = text.substring(start, endLine)
|
|
8
|
+
const comment = /^\s*\/\//.test(line)
|
|
9
|
+
if (!comment) break
|
|
10
|
+
const directive = /^\s*\/\/\s*requirejs-esm-(skip|process)-file\s*$/.exec(line)
|
|
11
|
+
if (directive) {
|
|
12
|
+
return directive[1] === 'process'
|
|
13
|
+
}
|
|
14
|
+
start = endLine + 1
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -5,7 +5,7 @@ import { isValidIdentifier } from './validators'
|
|
|
5
5
|
import { isIdentifierChar } from './identifier'
|
|
6
6
|
|
|
7
7
|
export function toIdentifier(input) {
|
|
8
|
-
input = input
|
|
8
|
+
input = `${input}`
|
|
9
9
|
|
|
10
10
|
let name = ''
|
|
11
11
|
for (const c of input) {
|
|
@@ -14,9 +14,7 @@ export function toIdentifier(input) {
|
|
|
14
14
|
|
|
15
15
|
name = name.replace(/^[-0-9]+/, '')
|
|
16
16
|
|
|
17
|
-
name = name.replace(/[-\s]+(.)?/g,
|
|
18
|
-
return c ? c.toUpperCase() : ''
|
|
19
|
-
})
|
|
17
|
+
name = name.replace(/[-\s]+(.)?/g, (_match, c) => c ? c.toUpperCase() : '')
|
|
20
18
|
|
|
21
19
|
if (!isValidIdentifier(name)) {
|
|
22
20
|
name = `_${name}`
|
package/src/transformer/esm.js
CHANGED
|
@@ -87,6 +87,7 @@ export function transformEsmToAmd(program, options) {
|
|
|
87
87
|
program
|
|
88
88
|
})
|
|
89
89
|
|
|
90
|
+
const { splitDefaultNamedDeclarations } = options
|
|
90
91
|
const { body } = program
|
|
91
92
|
let { length } = body
|
|
92
93
|
|
|
@@ -148,47 +149,52 @@ export function transformEsmToAmd(program, options) {
|
|
|
148
149
|
|
|
149
150
|
// expression after keyword default
|
|
150
151
|
const { declaration } = statement
|
|
152
|
+
// export default X
|
|
151
153
|
let exportValue = declaration
|
|
152
|
-
let
|
|
153
|
-
|
|
154
|
-
if (declaration.type === 'FunctionDeclaration'
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
// exportStat = returnStatement(identifier(className))
|
|
168
|
-
// needReturnExport = false
|
|
169
|
-
// } else {
|
|
170
|
-
// exportStat = exportStatement(exportsVar, 'default', className)
|
|
171
|
-
// }
|
|
172
|
-
|
|
173
|
-
// program.pushContainer('body', [exportStat])
|
|
174
|
-
// needExportExpression = false
|
|
175
|
-
// } else {
|
|
176
|
-
// exportValue = toExpression(classNode)
|
|
177
|
-
// }
|
|
154
|
+
let keepDeclaration
|
|
155
|
+
|
|
156
|
+
if (declaration.type === 'FunctionDeclaration' ||
|
|
157
|
+
declaration.type === 'ClassDeclaration') {
|
|
158
|
+
const { id } = declaration
|
|
159
|
+
if (id && splitDefaultNamedDeclarations) {
|
|
160
|
+
// export default function X() {}
|
|
161
|
+
// export default class X {}
|
|
162
|
+
exportValue = identifier(declaration.id.name)
|
|
163
|
+
keepDeclaration = true
|
|
164
|
+
} else {
|
|
165
|
+
// export default function () {}
|
|
166
|
+
// export default class {}
|
|
167
|
+
exportValue = toExpression(declaration)
|
|
168
|
+
}
|
|
178
169
|
}
|
|
179
170
|
|
|
180
|
-
|
|
181
|
-
let exportStat
|
|
171
|
+
let exportStat
|
|
182
172
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
173
|
+
if (i + 1 === length && isOnlyDefaultExport) {
|
|
174
|
+
exportStat = returnStatement(exportValue)
|
|
175
|
+
needReturnExport = false
|
|
176
|
+
} else {
|
|
177
|
+
exportStat = exportStatement(exportsVar, 'default', exportValue)
|
|
178
|
+
}
|
|
189
179
|
|
|
190
|
-
|
|
180
|
+
// This changes the original code by putting the name of the exported
|
|
181
|
+
// function or class to the module scope. Being able to access the class
|
|
182
|
+
// by name simplifies other AST manipulations, which would have to be more
|
|
183
|
+
// complicated. Or the developer would have to help the manipulator
|
|
184
|
+
// by separating the export expression to a declaration and an export
|
|
185
|
+
// of an identifier. Use it if it doesn't break your code.
|
|
186
|
+
//
|
|
187
|
+
// // original, the name X is not in the module scope
|
|
188
|
+
// export default class X {}
|
|
189
|
+
//
|
|
190
|
+
// // converted, the name X is in the module scope
|
|
191
|
+
// class X {}
|
|
192
|
+
// export default X
|
|
193
|
+
if (keepDeclaration) {
|
|
194
|
+
body.splice(i++, 0, declaration)
|
|
195
|
+
++length
|
|
191
196
|
}
|
|
197
|
+
body[i] = exportStat
|
|
192
198
|
}
|
|
193
199
|
|
|
194
200
|
// export {x as y}
|
|
@@ -244,7 +250,7 @@ export function transformEsmToAmd(program, options) {
|
|
|
244
250
|
const importVar = generateUidIdentifier(exportSource.value, program)
|
|
245
251
|
importVars.push(importVar)
|
|
246
252
|
|
|
247
|
-
for (
|
|
253
|
+
for (const specifier of specifiers) {
|
|
248
254
|
const { exported, local } = specifier
|
|
249
255
|
const { name } = local
|
|
250
256
|
let localName
|
|
@@ -318,6 +324,17 @@ export function transformEsmToAmd(program, options) {
|
|
|
318
324
|
}
|
|
319
325
|
}
|
|
320
326
|
|
|
327
|
+
// no imports and exports, do not wrap to AMD module, if AMD/UMD should be assumed
|
|
328
|
+
if (options.skipIfNoImportExport && !(importPaths.length || hasExport)) {
|
|
329
|
+
options.onAfterTransform?.({
|
|
330
|
+
...options,
|
|
331
|
+
updated: false,
|
|
332
|
+
program,
|
|
333
|
+
callbackBody: body
|
|
334
|
+
})
|
|
335
|
+
return false
|
|
336
|
+
}
|
|
337
|
+
|
|
321
338
|
// adding define wrapper
|
|
322
339
|
if (hasExport && needReturnExport) {
|
|
323
340
|
let returnStat
|
|
@@ -350,10 +367,13 @@ export function transformEsmToAmd(program, options) {
|
|
|
350
367
|
|
|
351
368
|
options.onAfterTransform?.({
|
|
352
369
|
...options,
|
|
370
|
+
updated: true,
|
|
353
371
|
program,
|
|
354
372
|
callbackBody: body
|
|
355
373
|
})
|
|
356
374
|
|
|
375
|
+
return true
|
|
376
|
+
|
|
357
377
|
function addExportStatement({ exported, local }) {
|
|
358
378
|
const asName = exported.name
|
|
359
379
|
if (asName !== 'default') {
|
package/src/transformer/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { detectDefinesOrRequires, updateAmdDeps, callAmdUpdateHooks } from './amd'
|
|
2
2
|
import { detectImportsAndExports, transformEsmToAmd } from './esm'
|
|
3
|
+
import { processOrSkipByComment } from './comments'
|
|
3
4
|
|
|
4
5
|
export function transformAst(program, options = {}) {
|
|
5
6
|
const amds = detectDefinesOrRequires(program)
|
|
@@ -14,10 +15,9 @@ export function transformAst(program, options = {}) {
|
|
|
14
15
|
result.updated ||= updated
|
|
15
16
|
}
|
|
16
17
|
} else {
|
|
17
|
-
transformEsmToAmd(program, options)
|
|
18
|
-
result.updated = true
|
|
18
|
+
result.updated = transformEsmToAmd(program, options)
|
|
19
19
|
}
|
|
20
20
|
return result
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export { detectDefinesOrRequires, detectImportsAndExports }
|
|
23
|
+
export { detectDefinesOrRequires, detectImportsAndExports, processOrSkipByComment }
|
package/src/write-text.js
CHANGED
|
@@ -5,8 +5,8 @@ let writeText
|
|
|
5
5
|
// Initialise the writeText variable with a function to write to a file.
|
|
6
6
|
/* istanbul ignore if */
|
|
7
7
|
if (!(typeof window !== 'undefined' && window.navigator && window.document)) {
|
|
8
|
-
const { writeFileSync, mkdirSync } = require.nodeRequire ? require.nodeRequire('fs') : require('fs')
|
|
9
|
-
const { dirname } = require.nodeRequire ? require.nodeRequire('path') : require('path')
|
|
8
|
+
const { writeFileSync, mkdirSync } = require.nodeRequire ? require.nodeRequire('fs') : require('node:fs')
|
|
9
|
+
const { dirname } = require.nodeRequire ? require.nodeRequire('path') : require('node:path')
|
|
10
10
|
writeText = (path, content) => {
|
|
11
11
|
mkdirSync(dirname(path), { recursive: true })
|
|
12
12
|
writeFileSync(path, content)
|