requirejs-esm 2.0.1 → 2.1.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/package.json +21 -26
- package/src/api.d.ts +14 -0
- package/src/api.js +2 -0
- package/src/fetch-text.js +35 -0
- package/src/plugin.js +147 -0
- package/src/resolve-path.js +80 -0
- package/src/skip-module.js +18 -0
- package/src/transform.js +47 -0
- package/src/transformer/amd.js +98 -0
- package/src/transformer/converters.js +102 -0
- package/src/transformer/esm.js +295 -0
- package/src/transformer/factories.js +55 -0
- package/src/transformer/generate-id.js +96 -0
- package/src/transformer/identifier.js +75 -0
- package/src/transformer/index.js +18 -0
- package/src/transformer/keywords.js +74 -0
- package/src/transformer/validators.js +29 -0
- package/src/write-text.js +16 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "requirejs-esm",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.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",
|
|
@@ -22,12 +22,15 @@
|
|
|
22
22
|
"node": ">=14"
|
|
23
23
|
},
|
|
24
24
|
"main": "dist/api.js",
|
|
25
|
+
"module": "src/api.js",
|
|
26
|
+
"types": "src/api.d.ts",
|
|
25
27
|
"bin": {
|
|
26
28
|
"esm2requirejs": "bin/esm2requirejs.js"
|
|
27
29
|
},
|
|
28
30
|
"files": [
|
|
29
31
|
"bin",
|
|
30
|
-
"dist"
|
|
32
|
+
"dist",
|
|
33
|
+
"src"
|
|
31
34
|
],
|
|
32
35
|
"scripts": {
|
|
33
36
|
"prepare": "npm run build && npm run demo",
|
|
@@ -39,10 +42,11 @@
|
|
|
39
42
|
"demo:local": "npm run optimize:local && npm run minify:local",
|
|
40
43
|
"optimize:local": "r.js -o demo-local/build.config.js",
|
|
41
44
|
"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",
|
|
42
|
-
"lint": "eslint -c .eslintrc.browser.yml src && eslint -c .eslintrc.node.yml
|
|
45
|
+
"lint": "eslint -c .eslintrc.browser.yml src && eslint -c .eslintrc.node.yml perf/*.js bin 'test/*.js'",
|
|
43
46
|
"check": "tehanu test/*.js",
|
|
44
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",
|
|
45
|
-
"test": "npm run lint && npm run cover"
|
|
48
|
+
"test": "npm run lint && npm run cover",
|
|
49
|
+
"start": "python3 -m http.server"
|
|
46
50
|
},
|
|
47
51
|
"tehanu": {
|
|
48
52
|
"autostart": false
|
|
@@ -78,29 +82,27 @@
|
|
|
78
82
|
"@semantic-release/git"
|
|
79
83
|
]
|
|
80
84
|
},
|
|
81
|
-
"
|
|
85
|
+
"dependencies": {
|
|
82
86
|
"@prantlf/convert-source-map": "^2.0.0",
|
|
83
|
-
"
|
|
87
|
+
"astring": "^1.8.1",
|
|
88
|
+
"charcodes": "^0.2.0",
|
|
89
|
+
"commander": "^9.1.0",
|
|
90
|
+
"meriyah": "^4.2.1",
|
|
91
|
+
"punycode": "^2.1.1",
|
|
92
|
+
"source-map": "^0.8.0-beta.0",
|
|
93
|
+
"tiny-glob": "^0.2.9"
|
|
94
|
+
},
|
|
95
|
+
"devDependencies": {
|
|
96
|
+
"@prantlf/requirejs": "^3.0.0",
|
|
84
97
|
"@rollup/plugin-commonjs": "^21.0.3",
|
|
85
98
|
"@rollup/plugin-json": "^4.1.0",
|
|
86
99
|
"@rollup/plugin-node-resolve": "^13.1.3",
|
|
87
100
|
"@semantic-release/changelog": "^6.0.1",
|
|
88
101
|
"@semantic-release/git": "^10.0.1",
|
|
89
|
-
"astring": "^1.8.1",
|
|
90
102
|
"c8": "^7.11.0",
|
|
91
|
-
"
|
|
92
|
-
"connect": "^3.7.0",
|
|
93
|
-
"connect-block-favicon": "^1.0.4",
|
|
94
|
-
"escodegen": "^2.0.0",
|
|
95
|
-
"eslint": "^8.12.0",
|
|
103
|
+
"eslint": "^8.13.0",
|
|
96
104
|
"lit-html": "^1",
|
|
97
|
-
"meriyah": "^4.2.1",
|
|
98
|
-
"morgan": "^1.10.0",
|
|
99
|
-
"punycode": "^2.1.1",
|
|
100
105
|
"rollup": "^2.70.1",
|
|
101
|
-
"serve-index": "^1.9.1",
|
|
102
|
-
"serve-static": "^1.15.0",
|
|
103
|
-
"source-map": "^0.8.0-beta.0",
|
|
104
106
|
"tehanu": "^0.2.2",
|
|
105
107
|
"tehanu-repo-coco": "^0.0.2",
|
|
106
108
|
"tehanu-teru": "^0.2.2",
|
|
@@ -113,12 +115,5 @@
|
|
|
113
115
|
"amd",
|
|
114
116
|
"esm",
|
|
115
117
|
"es6"
|
|
116
|
-
]
|
|
117
|
-
"dependencies": {
|
|
118
|
-
"commander": "^9.1.0",
|
|
119
|
-
"cors": "^2.8.5",
|
|
120
|
-
"mime": "^3.0.0",
|
|
121
|
-
"polka": "^0.5.2",
|
|
122
|
-
"tiny-glob": "^0.2.9"
|
|
123
|
-
}
|
|
118
|
+
]
|
|
124
119
|
}
|
package/src/api.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type NeedsResolve = (sourcePath: string, currentFile: string) => boolean
|
|
2
|
+
|
|
3
|
+
interface ResolveOptions {
|
|
4
|
+
pluginName?: string
|
|
5
|
+
needsResolve?: NeedsResolve
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
declare function resolvePath(sourcePath: string, currentFile: string, options?: ResolveOptions): string
|
|
9
|
+
|
|
10
|
+
type ResolvePath = ((sourcePath: string, currentFile: string, options?: ResolveOptions) => string) | false
|
|
11
|
+
|
|
12
|
+
declare function transform(contents: string, path: string, options?: {
|
|
13
|
+
pluginName?: string /*= 'esm'' */, resolvePath?: ResolvePath,
|
|
14
|
+
sourceMap?: boolean /*= true */ }): string
|
package/src/api.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* global require */
|
|
2
|
+
|
|
3
|
+
let fetchText
|
|
4
|
+
|
|
5
|
+
// Initialise the fetchText variable with a function to download
|
|
6
|
+
// from a URL or to read from the file system.
|
|
7
|
+
/* istanbul ignore if */
|
|
8
|
+
if (typeof window !== 'undefined' && window.navigator && window.document) {
|
|
9
|
+
fetchText = (url, callback) => {
|
|
10
|
+
const xhr = new XMLHttpRequest()
|
|
11
|
+
xhr.open('GET', url, true)
|
|
12
|
+
xhr.onreadystatechange = () => {
|
|
13
|
+
if (xhr.readyState === 4) {
|
|
14
|
+
if (xhr.status === 200) {
|
|
15
|
+
callback(null, xhr.responseText)
|
|
16
|
+
} else {
|
|
17
|
+
callback(new Error(xhr.statusText))
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
xhr.send(null)
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
const { readFileSync } = require.nodeRequire ? require.nodeRequire('fs') : require('fs')
|
|
25
|
+
fetchText = (path, callback) => {
|
|
26
|
+
// Asynchronous reading is not possible during the build in the optimizer.
|
|
27
|
+
try {
|
|
28
|
+
callback(null, readFileSync(path, 'utf8'))
|
|
29
|
+
} catch (error) {
|
|
30
|
+
callback(error)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default fetchText
|
package/src/plugin.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/* global module */
|
|
2
|
+
|
|
3
|
+
import fetchText from './fetch-text'
|
|
4
|
+
import writeText from './write-text'
|
|
5
|
+
import { childFile } from './resolve-path'
|
|
6
|
+
import { setSkipModules, skipModule } from './skip-module'
|
|
7
|
+
import transformSource from './transform'
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
// Allow using a different plugin alias than `esm` in the source code.
|
|
11
|
+
pluginName,
|
|
12
|
+
// Assume that the original sources are JavaScript files by default.
|
|
13
|
+
fileExtension = '.js',
|
|
14
|
+
// Flags to enforce or suppress the transpilation of not yet defined modules.
|
|
15
|
+
mixedAmdAndEsm,
|
|
16
|
+
onlyAmd,
|
|
17
|
+
// List of module names not to check and transform.
|
|
18
|
+
skipModules = [],
|
|
19
|
+
// Method to update paths of module dependencies, to prefix JavaScript module
|
|
20
|
+
// name with `esm!`, above all.
|
|
21
|
+
resolvePath,
|
|
22
|
+
// ecmaVersion,
|
|
23
|
+
// Boolean or object with booleans { inline, content }.
|
|
24
|
+
sourceMap,
|
|
25
|
+
// Enable console logging.
|
|
26
|
+
verbose,
|
|
27
|
+
// Directory to save a copy of the transformed modules.
|
|
28
|
+
debugDir
|
|
29
|
+
} = typeof module !== 'undefined' && module.config && module.config() || {}
|
|
30
|
+
|
|
31
|
+
const buildMap = {}
|
|
32
|
+
|
|
33
|
+
setSkipModules(skipModules)
|
|
34
|
+
|
|
35
|
+
//>>excludeEnd('excludeEsm')
|
|
36
|
+
export default {
|
|
37
|
+
load(name, req, onload, reqConfig) {
|
|
38
|
+
//>>excludeStart('excludeEsm', pragmas.excludeEsm)
|
|
39
|
+
const { isBuild } = reqConfig
|
|
40
|
+
// if (!bundledModules) {
|
|
41
|
+
// bundledModules = new Set()
|
|
42
|
+
// const { bundles } = reqConfig
|
|
43
|
+
// if (bundles) {
|
|
44
|
+
// verbose && console.log('esm: initialising bundles', name)
|
|
45
|
+
// for (const bundle in bundles) {
|
|
46
|
+
// for (const module of bundles[bundle]) {
|
|
47
|
+
// bundledModules.add(module)
|
|
48
|
+
// }
|
|
49
|
+
// }
|
|
50
|
+
// }
|
|
51
|
+
// }
|
|
52
|
+
|
|
53
|
+
// Paths relative to the current directory include the file extension.
|
|
54
|
+
// Otherwise the file extension must not be used for JavaScript modules.
|
|
55
|
+
// The file name should include the orioginal extension in the source maps.
|
|
56
|
+
const file = name.endsWith(fileExtension) ? name : name + fileExtension
|
|
57
|
+
// Compilation and bundling of module sub-trees can be skipped, if those
|
|
58
|
+
// are mapped to the pseudo-path `empty:`, meaning that those modules
|
|
59
|
+
// are external and will be loaded during the runtime.
|
|
60
|
+
const url = req.toUrl(file)
|
|
61
|
+
if (url.startsWith('empty:')) {
|
|
62
|
+
verbose && console.log('esm: skipping', name, 'mapped to', url)
|
|
63
|
+
return onload()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
verbose && console.log('esm: loading', name)
|
|
67
|
+
// If the module has been already defined from a module bundle, it was
|
|
68
|
+
// already transpiled, when the output bundle was written. No need to
|
|
69
|
+
// re-transpile it. This can happen only during the runtime.
|
|
70
|
+
//
|
|
71
|
+
// The re-transpilation is however necessary, if a testing page or a unit
|
|
72
|
+
// test loads source ESM modules with extensions, which are going to be
|
|
73
|
+
// consumed by a bundled module. Then the bundled module has to prefix
|
|
74
|
+
// each of its dependencies with `esm!` to ensure their transpilation.
|
|
75
|
+
// This mixed mode can to be enabled by the flag `mixedAmdAndEsm`, if needed.
|
|
76
|
+
//
|
|
77
|
+
// If the whole application is transpiled, there is no need to transpile
|
|
78
|
+
// ESM modules or prefix dependencies of AMD modules. Even not yet defined
|
|
79
|
+
// modules can be loaded just by `require` to get better performance.
|
|
80
|
+
if (!mixedAmdAndEsm && !isBuild && req.specified(name) ||
|
|
81
|
+
/*bundledModules.has(name) ||*/ onlyAmd || skipModule(name) ||
|
|
82
|
+
// If the module was bundled, it had to be already transpiled.
|
|
83
|
+
!isBuild && childFile(url) !== childFile(file)) {
|
|
84
|
+
verbose && console.log('esm: delegating', name)
|
|
85
|
+
//>>excludeEnd('excludeEsm')
|
|
86
|
+
return req([name], onload, onload.error)
|
|
87
|
+
//>>excludeStart('excludeEsm', pragmas.excludeEsm)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Fetch the text of the source module by AJAX and transpile it.
|
|
91
|
+
verbose && console.log('esm: fetching', name, 'mapped to', url)
|
|
92
|
+
fetchText(url, async (error, text) => {
|
|
93
|
+
if (error) {
|
|
94
|
+
verbose && console.log('esm: missing', name)
|
|
95
|
+
return onload.error(error)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let code, updated
|
|
99
|
+
try {
|
|
100
|
+
verbose && console.log('esm: transforming', name);
|
|
101
|
+
({ code, updated } = transformSource(text, file, {
|
|
102
|
+
pluginName,
|
|
103
|
+
resolvePath,
|
|
104
|
+
/*ecmaVersion,*/
|
|
105
|
+
// Always produce the source maps when transpiling in the browser, otherwise
|
|
106
|
+
// the debugging would me impossible. When building and bundling, check if
|
|
107
|
+
// the source maps were enabled for the output.
|
|
108
|
+
sourceMap: sourceMap || !isBuild
|
|
109
|
+
}))
|
|
110
|
+
if (!updated) {
|
|
111
|
+
verbose && console.log('esm: retaining', name)
|
|
112
|
+
// return req([name], onload, onload.error)
|
|
113
|
+
} else if (isBuild && debugDir) {
|
|
114
|
+
writeText(`${debugDir}/${file}`, code)
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
// RequireJS did not always log this error.
|
|
118
|
+
console.error(`Transforming "${name}" (resolved to "${url}") failed:`)
|
|
119
|
+
console.error(error)
|
|
120
|
+
return onload.error(error)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Remember the transpiled content for the writing phase during the build.
|
|
124
|
+
if (isBuild) {
|
|
125
|
+
buildMap[name] = code
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
verbose && console.log('esm: returning', name)
|
|
129
|
+
onload.fromText(code)
|
|
130
|
+
})
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
write(pluginName, moduleName, write) {
|
|
134
|
+
const code = buildMap[moduleName]
|
|
135
|
+
if (code) {
|
|
136
|
+
// Add the transpiled module under the original name. Earlier modules
|
|
137
|
+
// refer it with that name, before the module was converted to ESM.
|
|
138
|
+
write.asModule(moduleName, code)
|
|
139
|
+
// Add a stub of the module with the name prefixed by `esm!`. Modules
|
|
140
|
+
// compiled with esm refer it with that name and this stub will simplify
|
|
141
|
+
// the module loading by skipping the plugin evaluation.
|
|
142
|
+
write.asModule(`${pluginName}!${moduleName}`,
|
|
143
|
+
'\ndefine([\'' + moduleName + '\'], res => res);\n')
|
|
144
|
+
}
|
|
145
|
+
//>>excludeEnd('excludeEsm')
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Returns the child file name by cutting the directoris before the last slash,
|
|
2
|
+
// including the slash. If there is no slash in the path - the path is just
|
|
3
|
+
// a file name, it will return the file name. If the path includes a URL
|
|
4
|
+
// query starting with the question mark, it will cut it away including the
|
|
5
|
+
// question mark.
|
|
6
|
+
export function childFile (path) {
|
|
7
|
+
const lastSlash = path.lastIndexOf('/')
|
|
8
|
+
if (lastSlash > 0) {
|
|
9
|
+
path = path.substring(lastSlash + 1)
|
|
10
|
+
}
|
|
11
|
+
const questionMark = path.lastIndexOf('?')
|
|
12
|
+
return questionMark > 0 ? path.substring(0, questionMark) : path
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Returns the parent directory by cutting the file name after the last slash,
|
|
16
|
+
// leaving the slash in the result. If there is no slash in the path - the path
|
|
17
|
+
// is just a file name, it will return `undefined`.
|
|
18
|
+
function parentDir (path) {
|
|
19
|
+
const lastSlash = path.lastIndexOf('/')
|
|
20
|
+
return lastSlash > 0 ? path.substring(0, lastSlash + 1) : undefined
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Trims the leading "./" off the path.
|
|
24
|
+
function shortenPath(path) {
|
|
25
|
+
while (path.charAt(0) === '.' && path.charAt(1) === '/') {
|
|
26
|
+
path = path.substring(2)
|
|
27
|
+
}
|
|
28
|
+
return path
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Checks if the path starts with "../".
|
|
32
|
+
function pointsToParent(path) {
|
|
33
|
+
return path.charAt(0) === '.' && path.charAt(1) === '.' && path.charAt(2) === '/'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Joins two paths together and avoids leaving "/./" or "/../" in the middle.
|
|
37
|
+
function joinPath (first, second) {
|
|
38
|
+
// If the second part starts with "./", it can be safely removed.
|
|
39
|
+
second = shortenPath(second)
|
|
40
|
+
// The parent path can be undefined, if the file is located in the current directory.
|
|
41
|
+
if (first !== undefined) {
|
|
42
|
+
// As long as "../" can be removed from the second path, shorten the first one.
|
|
43
|
+
while (pointsToParent(second)) {
|
|
44
|
+
// Remove the leading "../" and trim futher all leading "./".
|
|
45
|
+
second = shortenPath(second.substring(3))
|
|
46
|
+
// Cut the last directory from the first path.
|
|
47
|
+
first = parentDir(first)
|
|
48
|
+
// If the last part of the first path was removed and there is no parent
|
|
49
|
+
// directory to go further, return the rest of the second path.
|
|
50
|
+
if (first === undefined) {
|
|
51
|
+
return second
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Return what remains from the first path concatenated with the second one.
|
|
55
|
+
second = first + second
|
|
56
|
+
}
|
|
57
|
+
return second
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Ensures that every JavaScript dependency will be prefixed by `esm!`.
|
|
61
|
+
// Relative paths will be converted to be relative to the parent module.
|
|
62
|
+
export function resolvePath (sourcePath, currentFile, { pluginName, needsResolve } = {}) {
|
|
63
|
+
// Ignore paths with other plugins applied and the three built-in
|
|
64
|
+
// pseudo-modules of RequireJS.
|
|
65
|
+
if (sourcePath.includes('!') || sourcePath === 'require' ||
|
|
66
|
+
sourcePath === 'module' || sourcePath === 'exports') return
|
|
67
|
+
|
|
68
|
+
// If `sourcePath` is relative to `currentFile` - starts with ./ or ../ -
|
|
69
|
+
// prepend the parent directory of `currentFile` to it. This was needed
|
|
70
|
+
// for modules located outside the source root (`baseUrl`), which were
|
|
71
|
+
// mapped there using the `paths` of `map` configuration properties.
|
|
72
|
+
if ((sourcePath.charAt(0) === '.' && (sourcePath.charAt(1) === '/' ||
|
|
73
|
+
sourcePath.charAt(1) === '.' && sourcePath.charAt(2) === '/')) &&
|
|
74
|
+
!(needsResolve && needsResolve(sourcePath, currentFile))) {
|
|
75
|
+
sourcePath = joinPath(parentDir(currentFile), sourcePath)
|
|
76
|
+
if (sourcePath.endsWith('.js')) sourcePath = sourcePath.substring(0, sourcePath.length - 3)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return pluginName ? `${pluginName}!${sourcePath}` : sourcePath
|
|
80
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
let skipModules = []
|
|
2
|
+
|
|
3
|
+
export function setSkipModules(names) {
|
|
4
|
+
skipModules = names
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// Checks if a module name is included in the list of modules to skip
|
|
8
|
+
// the transformation.
|
|
9
|
+
export function skipModule(name) {
|
|
10
|
+
for (const skipModule of skipModules) {
|
|
11
|
+
// Recognise an asterisk at the beginning
|
|
12
|
+
if (skipModule.startsWith('*')) {
|
|
13
|
+
if (name.indexOf(skipModule.substring(1)) >= 0) return true
|
|
14
|
+
}
|
|
15
|
+
// Accept a path prefix as well.
|
|
16
|
+
else if (name.startsWith(skipModule)) return true
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/transform.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { resolvePath as originalResolvePath } from './resolve-path'
|
|
2
|
+
// import { parse } from 'acorn'
|
|
3
|
+
import { parseModule } from 'meriyah'
|
|
4
|
+
import { generate } from 'astring'
|
|
5
|
+
import { SourceMapGenerator } from 'source-map'
|
|
6
|
+
import convert from '@prantlf/convert-source-map'
|
|
7
|
+
import transformModules from './transformer'
|
|
8
|
+
|
|
9
|
+
export default function transform(text, file, {
|
|
10
|
+
// Allow using a different plugin alias than `esm` in the source code.
|
|
11
|
+
pluginName = 'esm',
|
|
12
|
+
// Method to update paths of module dependencies, to prefix JavaScript module
|
|
13
|
+
// name with `esm!`, above all.
|
|
14
|
+
resolvePath = originalResolvePath,
|
|
15
|
+
// ecmaVersion = 2020,
|
|
16
|
+
sourceMap
|
|
17
|
+
} = {}) {
|
|
18
|
+
// const ast = parse(text, { ecmaVersion, sourceType: 'module', locations: true })
|
|
19
|
+
let ast = parseModule(text, { next: true, loc: true })
|
|
20
|
+
|
|
21
|
+
const options = { sourceFileName: file, pluginName, resolvePath, originalResolvePath }
|
|
22
|
+
transformModules(ast, options)
|
|
23
|
+
|
|
24
|
+
const { updated } = options
|
|
25
|
+
let code, map
|
|
26
|
+
if (updated) {
|
|
27
|
+
if (sourceMap === true) {
|
|
28
|
+
sourceMap = { inline: true, content: true }
|
|
29
|
+
}
|
|
30
|
+
const mapGenerator = sourceMap ? new SourceMapGenerator({ file }) : undefined
|
|
31
|
+
code = generate(ast, { sourceMap: mapGenerator })
|
|
32
|
+
if (sourceMap) {
|
|
33
|
+
if (sourceMap.content) {
|
|
34
|
+
mapGenerator.setSourceContent(file, text)
|
|
35
|
+
}
|
|
36
|
+
if (sourceMap.inline) {
|
|
37
|
+
code += convert.fromObject(mapGenerator.toJSON()).toComment()
|
|
38
|
+
} else {
|
|
39
|
+
map = mapGenerator.toJSON()
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
code = text
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return { code, map, updated }
|
|
47
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { replaceLiteral } from './converters'
|
|
2
|
+
|
|
3
|
+
// Detects if an expression calls define or require function.
|
|
4
|
+
// Returns information about an AMD module false, { deps } or [{ deps }, ...].
|
|
5
|
+
function detectDefineOrRequireCall(expr) {
|
|
6
|
+
if (expr.type !== 'CallExpression') return false
|
|
7
|
+
|
|
8
|
+
const args = expr.arguments
|
|
9
|
+
const { length } = args
|
|
10
|
+
if (length === 0) return false
|
|
11
|
+
|
|
12
|
+
const { callee } = expr
|
|
13
|
+
let func
|
|
14
|
+
// namespace.define(...)
|
|
15
|
+
if (callee.type === 'MemberExpression') {
|
|
16
|
+
const { object } = callee
|
|
17
|
+
if (object.type !== 'Identifier') return false
|
|
18
|
+
func = callee.property
|
|
19
|
+
} else {
|
|
20
|
+
func = callee
|
|
21
|
+
}
|
|
22
|
+
if (func.type !== 'Identifier') return false
|
|
23
|
+
|
|
24
|
+
// define('name', [deps], factory)
|
|
25
|
+
if (func.name === 'define') {
|
|
26
|
+
let index = 0
|
|
27
|
+
let arg = args[index]
|
|
28
|
+
let deps
|
|
29
|
+
if (arg.type === 'Literal') {
|
|
30
|
+
if (length <= ++index || typeof arg.value !== 'string') return false
|
|
31
|
+
arg = args[index]
|
|
32
|
+
}
|
|
33
|
+
if (arg.type === 'ArrayExpression') {
|
|
34
|
+
deps = arg
|
|
35
|
+
if (length <= ++index) return false
|
|
36
|
+
arg = args[index]
|
|
37
|
+
}
|
|
38
|
+
return (arg.type === 'FunctionExpression' || arg.type === 'ObjectExpression') &&
|
|
39
|
+
{ deps: deps }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// require([deps], success, error)
|
|
43
|
+
if (func.name === 'require') {
|
|
44
|
+
const deps = args[0]
|
|
45
|
+
return deps.type === 'ArrayExpression' && length >= 2 &&
|
|
46
|
+
args[1].type === 'FunctionExpression' && { deps: deps }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Detects if a program contains statements calling define or require function.
|
|
51
|
+
// Returns information about AMD modules false, { deps } or [{ deps }, ...].
|
|
52
|
+
function detectDefineOrRequire(stat) {
|
|
53
|
+
if (stat.type !== 'ExpressionStatement') return false
|
|
54
|
+
const { expression } = stat
|
|
55
|
+
|
|
56
|
+
// multiple define/require statements in one file
|
|
57
|
+
if (expression.type === 'SequenceExpression') {
|
|
58
|
+
return expression
|
|
59
|
+
.expressions
|
|
60
|
+
.map(detectDefineOrRequireCall)
|
|
61
|
+
.reduce((all, one) => one ? all.concat(one) : all, [])
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return detectDefineOrRequireCall(expression)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Detects if a program contains statements calling define or require function.
|
|
68
|
+
// Returns information about the AMD modules [{ deps }, ...] or [].
|
|
69
|
+
export function detectDefinesOrRequires(program) {
|
|
70
|
+
const { body } = program
|
|
71
|
+
return body
|
|
72
|
+
.map(detectDefineOrRequire)
|
|
73
|
+
.reduce((all, one) => one ? all.concat(one) : all, [])
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Updates dependency paths to be prefixed by `esm!` or otherwise updated.
|
|
77
|
+
export function updateAmdDeps(amd, options) {
|
|
78
|
+
const { deps } = amd
|
|
79
|
+
if (!deps) return
|
|
80
|
+
|
|
81
|
+
const { sourceFileName: parentName } = options
|
|
82
|
+
const { elements } = deps
|
|
83
|
+
if (!elements.length) return
|
|
84
|
+
|
|
85
|
+
const { resolvePath } = options
|
|
86
|
+
let updated
|
|
87
|
+
for (const element of elements) {
|
|
88
|
+
if (element.type === 'Literal') {
|
|
89
|
+
const moduleName = element.value
|
|
90
|
+
const newModuleName = resolvePath(moduleName, parentName, options)
|
|
91
|
+
if (newModuleName && newModuleName !== moduleName) {
|
|
92
|
+
replaceLiteral(element, newModuleName)
|
|
93
|
+
updated = true
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return updated
|
|
98
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
identifier, memberExpression, assignmentExpression, expressionStatement
|
|
3
|
+
} from './factories'
|
|
4
|
+
import { isValidIdentifier } from './validators'
|
|
5
|
+
import { isIdentifierChar } from './identifier'
|
|
6
|
+
|
|
7
|
+
export function toIdentifier(input) {
|
|
8
|
+
input = input + ''
|
|
9
|
+
|
|
10
|
+
let name = ''
|
|
11
|
+
for (const c of input) {
|
|
12
|
+
name += isIdentifierChar(c.codePointAt(0)) ? c : '-'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
name = name.replace(/^[-0-9]+/, '')
|
|
16
|
+
|
|
17
|
+
name = name.replace(/[-\s]+(.)?/g, function (match, c) {
|
|
18
|
+
return c ? c.toUpperCase() : ''
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
if (!isValidIdentifier(name)) {
|
|
22
|
+
name = `_${name}`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return name || '_'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function toExpression(node) {
|
|
29
|
+
if (node.type === 'ExpressionStatement') {
|
|
30
|
+
node = node.expression
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const { type } = node
|
|
34
|
+
|
|
35
|
+
if (type.endsWith('Expression')) return node
|
|
36
|
+
|
|
37
|
+
if (type === 'ClassDeclaration') {
|
|
38
|
+
node.type = 'ClassExpression'
|
|
39
|
+
} else if (type === 'FunctionDeclaration') {
|
|
40
|
+
node.type = 'FunctionExpression'
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!node.type.endsWith('Expression')) {
|
|
44
|
+
throw new Error(`cannot turn ${node.type} to an expression`)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return node
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function toStatement(node, ignore) {
|
|
51
|
+
const { type } = node
|
|
52
|
+
|
|
53
|
+
if (type.endsWith('Statement')) return node
|
|
54
|
+
|
|
55
|
+
let mustHaveId = false
|
|
56
|
+
let newType
|
|
57
|
+
|
|
58
|
+
if (type === 'ClassDeclaration' || type === 'ClassExpression') {
|
|
59
|
+
mustHaveId = true
|
|
60
|
+
newType = 'ClassDeclaration'
|
|
61
|
+
} else if (type === 'FunctionDeclaration' || type === 'FunctionExpression' ||
|
|
62
|
+
type === 'ArrowFunctionExpression') {
|
|
63
|
+
mustHaveId = true
|
|
64
|
+
newType = 'FunctionDeclaration'
|
|
65
|
+
} else if (type === 'AssignmentExpression') {
|
|
66
|
+
return expressionStatement(node)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (mustHaveId && !node.id) {
|
|
70
|
+
newType = false
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!newType) {
|
|
74
|
+
if (ignore) {
|
|
75
|
+
return false
|
|
76
|
+
} else {
|
|
77
|
+
throw new Error(`cannot turn ${node.type} to a statement`)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
node.type = newType
|
|
82
|
+
|
|
83
|
+
return node
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function replaceLiteral(literal, value) {
|
|
87
|
+
literal.value = value
|
|
88
|
+
const { raw } = literal
|
|
89
|
+
if (raw === undefined) return
|
|
90
|
+
if (typeof value === 'string') {
|
|
91
|
+
literal.raw = String(raw).charAt(0) === "'" ?
|
|
92
|
+
`'${value.replaceAll("'", "\\'")}'` : `"${value.replaceAll('"', '\\"')}"`
|
|
93
|
+
} else {
|
|
94
|
+
literal.raw = String(value)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Returns a statement assigning a property value to the exports object.
|
|
99
|
+
export function exportStatement(exportsVar, key, value) {
|
|
100
|
+
return toStatement(assignmentExpression('=',
|
|
101
|
+
memberExpression(exportsVar, identifier(key)), value))
|
|
102
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { isAnonymousImport, isImportDefault, isImportAllAs } from './validators'
|
|
2
|
+
import {
|
|
3
|
+
identifier, memberExpression, objectExpression, arrayExpression, blockStatement,
|
|
4
|
+
variableDeclaration, variableDeclarator, returnStatement, expressionStatement,
|
|
5
|
+
forInStatement, assignmentExpression, callExpression, functionExpression
|
|
6
|
+
} from './factories'
|
|
7
|
+
import { toExpression, replaceLiteral, exportStatement } from './converters'
|
|
8
|
+
import { generateUid, generateUidIdentifier } from './generate-id'
|
|
9
|
+
|
|
10
|
+
// Transforms the module format from ESM to AMD.
|
|
11
|
+
export function transformEsmToAmd(program, options) {
|
|
12
|
+
const { body } = program
|
|
13
|
+
let { length } = body
|
|
14
|
+
|
|
15
|
+
const importPaths = []
|
|
16
|
+
const importVars = []
|
|
17
|
+
const namedImports = []
|
|
18
|
+
const localImports = new Set()
|
|
19
|
+
|
|
20
|
+
const exportsVar = generateUidIdentifier('exports', program, program)
|
|
21
|
+
let hasExport = false
|
|
22
|
+
let needReturnExport = false
|
|
23
|
+
let isOnlyDefaultExport = true
|
|
24
|
+
|
|
25
|
+
for (let i = 0; i < length; ++i) {
|
|
26
|
+
const statement = body[i]
|
|
27
|
+
|
|
28
|
+
// import
|
|
29
|
+
if (statement.type === 'ImportDeclaration') {
|
|
30
|
+
// save import path
|
|
31
|
+
const exportSource = statement.source
|
|
32
|
+
importPaths.push(exportSource)
|
|
33
|
+
|
|
34
|
+
const importNode = statement
|
|
35
|
+
// import "some"
|
|
36
|
+
if (isAnonymousImport(importNode)) {
|
|
37
|
+
// importVars.length should be equal importPaths.length
|
|
38
|
+
const importVar = generateUidIdentifier(exportSource.value, program)
|
|
39
|
+
importVars.push(importVar)
|
|
40
|
+
}
|
|
41
|
+
// import some from "some"
|
|
42
|
+
// import * as some from "some"
|
|
43
|
+
else if (isImportDefault(importNode) || isImportAllAs(importNode)) {
|
|
44
|
+
const asName = importNode.specifiers[0].local
|
|
45
|
+
importVars.push(asName)
|
|
46
|
+
}
|
|
47
|
+
// import {x, y, z} from "xyz"
|
|
48
|
+
else {
|
|
49
|
+
// convert "/path/to/a" to _pathToA
|
|
50
|
+
const asName = generateUidIdentifier(exportSource.value, program)
|
|
51
|
+
importVars.push(asName)
|
|
52
|
+
|
|
53
|
+
for (const { imported, local } of importNode.specifiers) {
|
|
54
|
+
const { name } = local
|
|
55
|
+
localImports.add(name)
|
|
56
|
+
namedImports.push(declareImport(name, asName.name, imported.name))
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
body.splice(i--, 1)
|
|
61
|
+
--length
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// export default
|
|
65
|
+
if (statement.type === 'ExportDefaultDeclaration') {
|
|
66
|
+
// need return at end file
|
|
67
|
+
hasExport = true
|
|
68
|
+
needReturnExport = true
|
|
69
|
+
|
|
70
|
+
// expression after keyword default
|
|
71
|
+
const { declaration } = statement
|
|
72
|
+
let exportValue = declaration
|
|
73
|
+
let needExportExpression = true
|
|
74
|
+
|
|
75
|
+
if (declaration.type === 'FunctionDeclaration') {
|
|
76
|
+
exportValue = toExpression(exportValue)
|
|
77
|
+
}
|
|
78
|
+
if (declaration.type === 'ClassDeclaration') {
|
|
79
|
+
exportValue = toExpression(exportValue)
|
|
80
|
+
// const classNode = exportValue
|
|
81
|
+
|
|
82
|
+
// if (classNode.id) {
|
|
83
|
+
// body[i] = classNode
|
|
84
|
+
|
|
85
|
+
// const className = identifier(classNode.id.name)
|
|
86
|
+
// let exportStat
|
|
87
|
+
// if (i + 1 === length && isOnlyDefaultExport) {
|
|
88
|
+
// exportStat = returnStatement(identifier(className))
|
|
89
|
+
// needReturnExport = false
|
|
90
|
+
// } else {
|
|
91
|
+
// exportStat = exportStatement(exportsVar, 'default', className)
|
|
92
|
+
// }
|
|
93
|
+
|
|
94
|
+
// program.pushContainer('body', [exportStat])
|
|
95
|
+
// needExportExpression = false
|
|
96
|
+
// } else {
|
|
97
|
+
// exportValue = toExpression(classNode)
|
|
98
|
+
// }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (needExportExpression) {
|
|
102
|
+
let exportStat
|
|
103
|
+
|
|
104
|
+
if (i + 1 === length && isOnlyDefaultExport) {
|
|
105
|
+
exportStat = returnStatement(exportValue)
|
|
106
|
+
needReturnExport = false
|
|
107
|
+
} else {
|
|
108
|
+
exportStat = exportStatement(exportsVar, 'default', exportValue)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
body[i] = exportStat
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// export {x as y}
|
|
116
|
+
// export var a = 1
|
|
117
|
+
// export function test() {}
|
|
118
|
+
// export class Test {}
|
|
119
|
+
if (statement.type === 'ExportNamedDeclaration') {
|
|
120
|
+
hasExport = true
|
|
121
|
+
needReturnExport = true
|
|
122
|
+
|
|
123
|
+
const { specifiers, declaration } = statement
|
|
124
|
+
|
|
125
|
+
// export var a = 1
|
|
126
|
+
if (!specifiers.length) {
|
|
127
|
+
isOnlyDefaultExport = false
|
|
128
|
+
|
|
129
|
+
// replace "export <expression>"
|
|
130
|
+
// to "<expression>"
|
|
131
|
+
body[i] = declaration
|
|
132
|
+
|
|
133
|
+
// export var a = 1, b = 2
|
|
134
|
+
if (declaration.type === 'VariableDeclaration') {
|
|
135
|
+
for (const { id } of declaration.declarations) {
|
|
136
|
+
const { name } = id
|
|
137
|
+
const exportStat = exportStatement(exportsVar, name, identifier(name))
|
|
138
|
+
body.push(exportStat)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// export function x() {}
|
|
143
|
+
if (declaration.type === 'FunctionDeclaration') {
|
|
144
|
+
const asName = declaration.id.name
|
|
145
|
+
|
|
146
|
+
const exportStat = exportStatement(exportsVar, asName, identifier(asName))
|
|
147
|
+
body.push(exportStat)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// export class Test {}
|
|
151
|
+
if (declaration.type === 'ClassDeclaration') {
|
|
152
|
+
const asName = declaration.id.name
|
|
153
|
+
|
|
154
|
+
const exportStat = exportStatement(exportsVar, asName, identifier(asName))
|
|
155
|
+
body.push(exportStat)
|
|
156
|
+
}
|
|
157
|
+
} else { // export {x as y}
|
|
158
|
+
// export { ... } from "module"
|
|
159
|
+
const exportSource = statement.source
|
|
160
|
+
if (exportSource) {
|
|
161
|
+
// save import path
|
|
162
|
+
importPaths.push(exportSource)
|
|
163
|
+
// importVars.length should be equal importPaths.length
|
|
164
|
+
const importVar = generateUidIdentifier(exportSource.value, program)
|
|
165
|
+
importVars.push(importVar)
|
|
166
|
+
|
|
167
|
+
for (let specifier of specifiers) {
|
|
168
|
+
const { exported, local } = specifier
|
|
169
|
+
const { name } = local
|
|
170
|
+
let localName
|
|
171
|
+
// newly re-exporting earlier imported identifier
|
|
172
|
+
if (localImports.has(name)) {
|
|
173
|
+
localName = generateUid(name, program)
|
|
174
|
+
addExportStatement({ exported, local: identifier(localName) })
|
|
175
|
+
} else {
|
|
176
|
+
localName = name
|
|
177
|
+
addExportStatement(specifier)
|
|
178
|
+
}
|
|
179
|
+
namedImports.push(declareImport(localName, importVar.name, name))
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
for (const specifier of specifiers) {
|
|
183
|
+
addExportStatement(specifier)
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
body.splice(i--, 1)
|
|
188
|
+
--length
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// export * from "module"
|
|
193
|
+
if (statement.type === 'ExportAllDeclaration') {
|
|
194
|
+
isOnlyDefaultExport = false
|
|
195
|
+
hasExport = true
|
|
196
|
+
needReturnExport = true
|
|
197
|
+
|
|
198
|
+
// save import path
|
|
199
|
+
const exportSource = statement.source
|
|
200
|
+
importPaths.push(exportSource)
|
|
201
|
+
// importVars.length should be equal importPaths.length
|
|
202
|
+
const importVar = generateUidIdentifier(exportSource.value, program)
|
|
203
|
+
importVars.push(importVar)
|
|
204
|
+
|
|
205
|
+
body[i] = exportCopyLoop(exportsVar, importVar)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// adding define wrapper
|
|
210
|
+
if (hasExport && needReturnExport) {
|
|
211
|
+
// var _exports = {}
|
|
212
|
+
body.unshift(
|
|
213
|
+
variableDeclaration('let', [
|
|
214
|
+
variableDeclarator(exportsVar, objectExpression([]))
|
|
215
|
+
])
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
// return <expression>
|
|
219
|
+
let returnStat
|
|
220
|
+
if (isOnlyDefaultExport) {
|
|
221
|
+
// return _exports.default
|
|
222
|
+
returnStat = returnStatement(memberExpression(exportsVar, identifier('default')))
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// return _exports
|
|
226
|
+
returnStat = returnStatement(exportsVar)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
body.push(returnStat)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
buildAmdModule(program, options, importPaths, importVars, namedImports)
|
|
233
|
+
|
|
234
|
+
function addExportStatement({ exported, local }) {
|
|
235
|
+
const asName = exported.name
|
|
236
|
+
if (asName !== 'default') {
|
|
237
|
+
isOnlyDefaultExport = false
|
|
238
|
+
}
|
|
239
|
+
const exportStat = exportStatement(exportsVar, asName, local)
|
|
240
|
+
body.push(exportStat)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function declareImport(varName, object, property) {
|
|
245
|
+
return variableDeclaration('let', [
|
|
246
|
+
variableDeclarator(
|
|
247
|
+
identifier(varName),
|
|
248
|
+
memberExpression(identifier(object), identifier(property))
|
|
249
|
+
)
|
|
250
|
+
])
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function exportCopyLoop(exportsVar, importVar) {
|
|
254
|
+
const key = identifier('_key')
|
|
255
|
+
return forInStatement(
|
|
256
|
+
variableDeclaration('const', [variableDeclarator(key)]),
|
|
257
|
+
importVar,
|
|
258
|
+
blockStatement([
|
|
259
|
+
expressionStatement(
|
|
260
|
+
assignmentExpression('=',
|
|
261
|
+
memberExpression(exportsVar, key, true), memberExpression(importVar, key, true)))
|
|
262
|
+
])
|
|
263
|
+
)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Wraps a program body of statements into an AMD module.
|
|
267
|
+
function buildAmdModule(program, options, importPaths, importVars, namedImports) {
|
|
268
|
+
program.body = [
|
|
269
|
+
expressionStatement(callExpression(
|
|
270
|
+
identifier('define'), importPaths.length ? [
|
|
271
|
+
prepareImportPaths(importPaths, options),
|
|
272
|
+
functionExpression(importVars, blockStatement(namedImports.concat(program.body)))
|
|
273
|
+
] : [
|
|
274
|
+
functionExpression([], blockStatement(program.body))
|
|
275
|
+
]))
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Update dependency paths to be prefixed by `esm!` or otherwise updated.
|
|
280
|
+
function prepareImportPaths(importPaths, options ) {
|
|
281
|
+
const { resolvePath } = options
|
|
282
|
+
if (resolvePath) {
|
|
283
|
+
const { sourceFileName: parentName } = options
|
|
284
|
+
for (const importPath of importPaths) {
|
|
285
|
+
if (importPath.type === 'Literal') {
|
|
286
|
+
const moduleName = importPath.value
|
|
287
|
+
const newModuleName = resolvePath(moduleName, parentName, options)
|
|
288
|
+
if (newModuleName && newModuleName !== moduleName) {
|
|
289
|
+
replaceLiteral(importPath, newModuleName)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return arrayExpression(importPaths)
|
|
295
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export function literal(value) {
|
|
2
|
+
return { type: 'Literal', value }
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function identifier(name) {
|
|
6
|
+
return { type: 'Identifier', name }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function memberExpression(object, property, computed) {
|
|
10
|
+
return { type: 'MemberExpression', object, property, computed }
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function objectExpression(properties) {
|
|
14
|
+
return { type: 'ObjectExpression', properties }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function arrayExpression(elements) {
|
|
18
|
+
return { type: 'ArrayExpression', elements }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function assignmentExpression(operator, left, right) {
|
|
22
|
+
return { type: 'AssignmentExpression', operator, left, right }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function variableDeclaration(kind, declarations) {
|
|
26
|
+
return { type: 'VariableDeclaration', kind, declarations }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function variableDeclarator(id, init) {
|
|
30
|
+
return { type: 'VariableDeclarator', id, init }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function expressionStatement(expression) {
|
|
34
|
+
return { type: 'ExpressionStatement', expression }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function returnStatement(argument) {
|
|
38
|
+
return { type: 'ReturnStatement', argument }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function forInStatement(left, right, body) {
|
|
42
|
+
return { type: 'ForInStatement', left, right, body }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function blockStatement(body) {
|
|
46
|
+
return { type: 'BlockStatement', body }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function callExpression(callee, args) {
|
|
50
|
+
return { type: 'CallExpression', callee, arguments: args }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function functionExpression(params, body) {
|
|
54
|
+
return { type: 'FunctionExpression', params, body }
|
|
55
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { isAnonymousImport, isImportDefault, isImportAllAs } from './validators'
|
|
2
|
+
import { identifier } from './factories'
|
|
3
|
+
import { toIdentifier } from './converters'
|
|
4
|
+
|
|
5
|
+
function _generateUid(name, i) {
|
|
6
|
+
let id = name
|
|
7
|
+
if (i > 1) id += i
|
|
8
|
+
return `_${id}`
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getUids(program) {
|
|
12
|
+
const uids = new Set()
|
|
13
|
+
for (const statement of program.body) {
|
|
14
|
+
const { type } = statement
|
|
15
|
+
if (type === 'LabeledStatement') {
|
|
16
|
+
const { label } = statement
|
|
17
|
+
if (label) {
|
|
18
|
+
uids.add(label.name)
|
|
19
|
+
}
|
|
20
|
+
} else if (type === 'ImportDeclaration') {
|
|
21
|
+
// import some from "some"
|
|
22
|
+
// import * as some from "some"
|
|
23
|
+
if (isImportDefault(statement) || isImportAllAs(statement)) {
|
|
24
|
+
uids.add(statement.specifiers[0].local.name)
|
|
25
|
+
}
|
|
26
|
+
// import {x, y, z} from "xyz"
|
|
27
|
+
else if (!isAnonymousImport(statement)) {
|
|
28
|
+
for (const { local } of statement.specifiers) {
|
|
29
|
+
uids.add(local.name)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
} else if (type === 'ExportNamedDeclaration') {
|
|
33
|
+
const { declaration } = statement
|
|
34
|
+
if (declaration) {
|
|
35
|
+
const { type } = declaration
|
|
36
|
+
// export var a = 1
|
|
37
|
+
if (type === 'VariableDeclaration') {
|
|
38
|
+
for (const { id } of declaration.declarations) {
|
|
39
|
+
uids.add(id.name)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// export function test() {}
|
|
43
|
+
// export class Test {}
|
|
44
|
+
else if (type === 'FunctionDeclaration' || type === 'ClassDeclaration') {
|
|
45
|
+
uids.add(declaration.id.name)
|
|
46
|
+
}
|
|
47
|
+
// export {x as y}
|
|
48
|
+
else {
|
|
49
|
+
for (const { local } of statement.specifiers) {
|
|
50
|
+
uids.add(local.name)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
} else if (type === 'VariableDeclaration') {
|
|
55
|
+
for (const { id } of statement.declarations) {
|
|
56
|
+
if (id.type === 'Identifier') {
|
|
57
|
+
uids.add(id.name)
|
|
58
|
+
} else {
|
|
59
|
+
for (const { value } of id.properties) {
|
|
60
|
+
uids.add(value.name)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} else if (type === 'FunctionDeclaration' || type === 'ClassDeclaration') {
|
|
65
|
+
uids.add(statement.id.name)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return uids
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function tryAddUid(uid, program) {
|
|
72
|
+
let { _uids } = program
|
|
73
|
+
if (!_uids) {
|
|
74
|
+
_uids = program._uids = getUids(program)
|
|
75
|
+
}
|
|
76
|
+
if (_uids.has(uid)) return true
|
|
77
|
+
_uids.add(uid)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function generateUid(name, program) {
|
|
81
|
+
name = toIdentifier(name)
|
|
82
|
+
.replace(/^_+/, '')
|
|
83
|
+
.replace(/[0-9]+$/g, '')
|
|
84
|
+
|
|
85
|
+
let uid
|
|
86
|
+
let i = 1
|
|
87
|
+
do {
|
|
88
|
+
uid = _generateUid(name, i++)
|
|
89
|
+
} while (tryAddUid(uid, program))
|
|
90
|
+
|
|
91
|
+
return uid
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function generateUidIdentifier(name, program) {
|
|
95
|
+
return identifier(generateUid(name, program))
|
|
96
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as charCodes from 'charcodes'
|
|
2
|
+
|
|
3
|
+
let nonASCIIidentifierStartChars = '\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088e\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c88\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7ca\ua7d0\ua7d1\ua7d3\ua7d5-\ua7d9\ua7f2-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc'
|
|
4
|
+
let nonASCIIidentifierChars = '\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0898-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1ace\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f'
|
|
5
|
+
|
|
6
|
+
const nonASCIIidentifierStart = new RegExp(`[${nonASCIIidentifierStartChars}]`)
|
|
7
|
+
const nonASCIIidentifier = new RegExp(`[${nonASCIIidentifierStartChars}${nonASCIIidentifierChars}]`)
|
|
8
|
+
|
|
9
|
+
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null
|
|
10
|
+
|
|
11
|
+
const astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,13,10,2,14,2,6,2,1,2,10,2,14,2,6,2,1,68,310,10,21,11,7,25,5,2,41,2,8,70,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,349,41,7,1,79,28,11,0,9,21,43,17,47,20,28,22,13,52,58,1,3,0,14,44,33,24,27,35,30,0,3,0,9,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,21,2,31,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,14,0,72,26,38,6,186,43,117,63,32,7,3,0,3,7,2,1,2,23,16,0,2,0,95,7,3,38,17,0,2,0,29,0,11,39,8,0,22,0,12,45,20,0,19,72,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,190,0,80,921,103,110,18,195,2637,96,16,1070,4050,582,8634,568,8,30,18,78,18,29,19,47,17,3,32,20,6,18,689,63,129,74,6,0,67,12,65,1,2,0,29,6135,9,1237,43,8,8936,3,2,6,2,1,2,290,46,2,18,3,9,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,1845,30,482,44,11,6,17,0,322,29,19,43,1269,6,2,3,2,1,2,14,2,196,60,67,8,0,1205,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42719,33,4152,8,221,3,5761,15,7472,3104,541,1507,4938]
|
|
12
|
+
const astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,370,1,154,10,50,3,123,2,54,14,32,10,3,1,11,3,46,10,8,0,46,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,2,11,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,71,5,2,1,3,3,2,0,2,1,13,9,120,6,3,6,4,0,29,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,87,9,39,4,60,6,26,9,1014,0,2,54,8,3,82,0,12,1,19628,1,4706,45,3,22,543,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,262,6,10,9,357,0,62,13,1495,6,110,6,6,9,4759,9,787719,239]
|
|
13
|
+
|
|
14
|
+
function isInAstralSet(code, set) {
|
|
15
|
+
let pos = 0x10000
|
|
16
|
+
for (let i = 0, length = set.length; i < length; i += 2) {
|
|
17
|
+
pos += set[i]
|
|
18
|
+
if (pos > code) return false
|
|
19
|
+
|
|
20
|
+
pos += set[i + 1]
|
|
21
|
+
if (pos >= code) return true
|
|
22
|
+
}
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isIdentifierStart(code) {
|
|
27
|
+
if (code < charCodes.uppercaseA) return code === charCodes.dollarSign
|
|
28
|
+
if (code <= charCodes.uppercaseZ) return true
|
|
29
|
+
if (code < charCodes.lowercaseA) return code === charCodes.underscore
|
|
30
|
+
if (code <= charCodes.lowercaseZ) return true
|
|
31
|
+
if (code <= 0xffff) {
|
|
32
|
+
return (
|
|
33
|
+
code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code))
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
return isInAstralSet(code, astralIdentifierStartCodes)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isIdentifierChar(code) {
|
|
40
|
+
if (code < charCodes.digit0) return code === charCodes.dollarSign
|
|
41
|
+
if (code < charCodes.colon) return true
|
|
42
|
+
if (code < charCodes.uppercaseA) return false
|
|
43
|
+
if (code <= charCodes.uppercaseZ) return true
|
|
44
|
+
if (code < charCodes.lowercaseA) return code === charCodes.underscore
|
|
45
|
+
if (code <= charCodes.lowercaseZ) return true
|
|
46
|
+
if (code <= 0xffff) {
|
|
47
|
+
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code))
|
|
48
|
+
}
|
|
49
|
+
return (
|
|
50
|
+
isInAstralSet(code, astralIdentifierStartCodes) ||
|
|
51
|
+
isInAstralSet(code, astralIdentifierCodes)
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isIdentifierName(name) {
|
|
56
|
+
let isFirst = true
|
|
57
|
+
for (let i = 0, len = name.length; i < len; ++i) {
|
|
58
|
+
let cp = name.charCodeAt(i)
|
|
59
|
+
if ((cp & 0xfc00) === 0xd800 && i + 1 < len) {
|
|
60
|
+
const trail = name.charCodeAt(++i)
|
|
61
|
+
if ((trail & 0xfc00) === 0xdc00) {
|
|
62
|
+
cp = 0x10000 + ((cp & 0x3ff) << 10) + (trail & 0x3ff)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (isFirst) {
|
|
66
|
+
isFirst = false
|
|
67
|
+
if (!isIdentifierStart(cp)) {
|
|
68
|
+
return false
|
|
69
|
+
}
|
|
70
|
+
} else if (!isIdentifierChar(cp)) {
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return !isFirst
|
|
75
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { detectDefinesOrRequires, updateAmdDeps } from './amd'
|
|
2
|
+
import { transformEsmToAmd } from './esm'
|
|
3
|
+
|
|
4
|
+
export default function transformModules(program, options) {
|
|
5
|
+
const amds = detectDefinesOrRequires(program)
|
|
6
|
+
const { length } = amds
|
|
7
|
+
if (length) {
|
|
8
|
+
options.amd = true
|
|
9
|
+
if (options.resolvePath) {
|
|
10
|
+
for (const amd of amds) {
|
|
11
|
+
options.updated |= updateAmdDeps(amd, options)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
} else {
|
|
15
|
+
transformEsmToAmd(program, options)
|
|
16
|
+
options.updated = true
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const reservedWords = {
|
|
2
|
+
keyword: [
|
|
3
|
+
'break',
|
|
4
|
+
'case',
|
|
5
|
+
'catch',
|
|
6
|
+
'continue',
|
|
7
|
+
'debugger',
|
|
8
|
+
'default',
|
|
9
|
+
'do',
|
|
10
|
+
'else',
|
|
11
|
+
'finally',
|
|
12
|
+
'for',
|
|
13
|
+
'function',
|
|
14
|
+
'if',
|
|
15
|
+
'return',
|
|
16
|
+
'switch',
|
|
17
|
+
'throw',
|
|
18
|
+
'try',
|
|
19
|
+
'var',
|
|
20
|
+
'const',
|
|
21
|
+
'while',
|
|
22
|
+
'with',
|
|
23
|
+
'new',
|
|
24
|
+
'this',
|
|
25
|
+
'super',
|
|
26
|
+
'class',
|
|
27
|
+
'extends',
|
|
28
|
+
'export',
|
|
29
|
+
'import',
|
|
30
|
+
'null',
|
|
31
|
+
'true',
|
|
32
|
+
'false',
|
|
33
|
+
'in',
|
|
34
|
+
'instanceof',
|
|
35
|
+
'typeof',
|
|
36
|
+
'void',
|
|
37
|
+
'delete'
|
|
38
|
+
],
|
|
39
|
+
strict: [
|
|
40
|
+
'implements',
|
|
41
|
+
'interface',
|
|
42
|
+
'let',
|
|
43
|
+
'package',
|
|
44
|
+
'private',
|
|
45
|
+
'protected',
|
|
46
|
+
'public',
|
|
47
|
+
'static',
|
|
48
|
+
'yield'
|
|
49
|
+
],
|
|
50
|
+
strictBind: ['eval', 'arguments']
|
|
51
|
+
}
|
|
52
|
+
const keywords = new Set(reservedWords.keyword)
|
|
53
|
+
const reservedWordsStrictSet = new Set(reservedWords.strict)
|
|
54
|
+
const reservedWordsStrictBindSet = new Set(reservedWords.strictBind)
|
|
55
|
+
|
|
56
|
+
export function isReservedWord(word, inModule) {
|
|
57
|
+
return inModule && word === 'await' || word === 'enum';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function isStrictReservedWord(word, inModule) {
|
|
61
|
+
return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function isStrictBindOnlyReservedWord(word) {
|
|
65
|
+
return reservedWordsStrictBindSet.has(word)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function isStrictBindReservedWord(word, inModule) {
|
|
69
|
+
return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function isKeyword(word) {
|
|
73
|
+
return keywords.has(word)
|
|
74
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isIdentifierName } from './identifier'
|
|
2
|
+
import { isKeyword, isStrictReservedWord } from './keywords'
|
|
3
|
+
|
|
4
|
+
export function isValidIdentifier(name, reserved = true) {
|
|
5
|
+
if (typeof name !== 'string') return false
|
|
6
|
+
if (reserved && (isKeyword(name) || isStrictReservedWord(name, true))) return false
|
|
7
|
+
return isIdentifierName(name)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Checks an anonymous import.
|
|
11
|
+
export function isAnonymousImport(importNode) {
|
|
12
|
+
// import "some"
|
|
13
|
+
return importNode.specifiers.length === 0
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Checks a default import.
|
|
17
|
+
export function isImportDefault(importNode) {
|
|
18
|
+
// import some from "some"
|
|
19
|
+
return importNode.specifiers.length === 1 &&
|
|
20
|
+
importNode.specifiers[0].type === 'ImportDefaultSpecifier'
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Checks importing all named exports to an object.
|
|
24
|
+
export function isImportAllAs(importNode) {
|
|
25
|
+
// import * as some from "some"
|
|
26
|
+
return importNode.specifiers.length === 1 &&
|
|
27
|
+
importNode.specifiers[0].type !== 'ImportDefaultSpecifier' &&
|
|
28
|
+
!importNode.specifiers[0].imported
|
|
29
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* global require */
|
|
2
|
+
|
|
3
|
+
let writeText
|
|
4
|
+
|
|
5
|
+
// Initialise the writeText variable with a function to write to a file.
|
|
6
|
+
/* istanbul ignore if */
|
|
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')
|
|
10
|
+
writeText = (path, content) => {
|
|
11
|
+
mkdirSync(dirname(path), { recursive: true })
|
|
12
|
+
writeFileSync(path, content)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default writeText
|