requirejs-esm 2.0.1 → 2.2.1

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.
@@ -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,367 @@
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
+ // Detects if a program contains import statements.
11
+ // Returns information about the import statemets [{ node, source, specifiers|local }, ...] or [].
12
+ export function detectImportsAndExports(program) {
13
+ const { body } = program
14
+ const { length } = body
15
+
16
+ const imports = []
17
+ const exports = []
18
+
19
+ for (let i = 0; i < length; ++i) {
20
+ const node = body[i]
21
+
22
+ // import
23
+ if (node.type === 'ImportDeclaration') {
24
+ const { source } = node
25
+
26
+ // import "some"
27
+ if (isAnonymousImport(node)) {
28
+ imports.push({ node, source })
29
+ }
30
+ // import some from "some"
31
+ // import * as some from "some"
32
+ else if (isImportDefault(node) || isImportAllAs(node)) {
33
+ const { local } = node.specifiers[0]
34
+ imports.push({ node, source, local })
35
+ }
36
+ // import {x, y, z} from "xyz"
37
+ else {
38
+ const specifiers = node.specifiers.map(({ imported, local }) => ({ imported, local }))
39
+ imports.push({ node, source, specifiers })
40
+ }
41
+ }
42
+
43
+ // export default
44
+ else if (node.type === 'ExportDefaultDeclaration') {
45
+ exports.push({ node, default: true })
46
+ }
47
+
48
+ // export {x as y}
49
+ // export var a = 1
50
+ // export function test() {}
51
+ // export class Test {}
52
+ else if (node.type === 'ExportNamedDeclaration') {
53
+ const { specifiers } = node
54
+
55
+ // export var a = 1
56
+ if (!specifiers.length) {
57
+ exports.push({ node })
58
+ } else { // export {x as y}
59
+ // export { ... } from "module"
60
+ const { source } = node
61
+ if (source) {
62
+ exports.push({ node, source, import: true })
63
+ const specifiers = node.specifiers.map(({ exported: imported, local }) => ({ imported, local }))
64
+ imports.push({ node, source, specifiers, export: true })
65
+ } else {
66
+ exports.push({ node })
67
+ }
68
+ }
69
+ }
70
+
71
+ // export * from "module"
72
+ if (node.type === 'ExportAllDeclaration') {
73
+ exports.push({ node, import: true })
74
+ const { source } = node
75
+ imports.push({ node, source, export: true })
76
+ }
77
+ }
78
+
79
+ return { imports, exports }
80
+ }
81
+
82
+ // Transforms the module format from ESM to AMD.
83
+ export function transformEsmToAmd(program, options) {
84
+ const { body } = program
85
+ let { length } = body
86
+
87
+ const importPaths = []
88
+ const importVars = []
89
+ const namedImports = []
90
+ const localImports = new Set()
91
+
92
+ const exportsVar = generateUidIdentifier('exports', program, program)
93
+ let hasExport = false
94
+ let needReturnExport = false
95
+ let isOnlyDefaultExport = true
96
+
97
+ for (let i = 0; i < length; ++i) {
98
+ const statement = body[i]
99
+
100
+ // import
101
+ if (statement.type === 'ImportDeclaration') {
102
+ // save import path
103
+ const exportSource = statement.source
104
+ importPaths.push(exportSource)
105
+
106
+ const importNode = statement
107
+ // import "some"
108
+ if (isAnonymousImport(importNode)) {
109
+ // importVars.length should be equal importPaths.length
110
+ const importVar = generateUidIdentifier(exportSource.value, program)
111
+ importVars.push(importVar)
112
+ }
113
+ // import some from "some"
114
+ // import * as some from "some"
115
+ else if (isImportDefault(importNode) || isImportAllAs(importNode)) {
116
+ const asName = importNode.specifiers[0].local
117
+ importVars.push(asName)
118
+ }
119
+ // import {x, y, z} from "xyz"
120
+ else {
121
+ // convert "/path/to/a" to _pathToA
122
+ const asName = generateUidIdentifier(exportSource.value, program)
123
+ importVars.push(asName)
124
+
125
+ for (const { imported, local } of importNode.specifiers) {
126
+ const { name } = local
127
+ localImports.add(name)
128
+ namedImports.push(declareImport(name, asName.name, imported.name))
129
+ }
130
+ }
131
+
132
+ body.splice(i--, 1)
133
+ --length
134
+ }
135
+
136
+ // export default
137
+ if (statement.type === 'ExportDefaultDeclaration') {
138
+ // need return at end file
139
+ hasExport = true
140
+ needReturnExport = true
141
+
142
+ // expression after keyword default
143
+ const { declaration } = statement
144
+ let exportValue = declaration
145
+ let needExportExpression = true
146
+
147
+ if (declaration.type === 'FunctionDeclaration') {
148
+ exportValue = toExpression(exportValue)
149
+ }
150
+ if (declaration.type === 'ClassDeclaration') {
151
+ exportValue = toExpression(exportValue)
152
+ // const classNode = exportValue
153
+
154
+ // if (classNode.id) {
155
+ // body[i] = classNode
156
+
157
+ // const className = identifier(classNode.id.name)
158
+ // let exportStat
159
+ // if (i + 1 === length && isOnlyDefaultExport) {
160
+ // exportStat = returnStatement(identifier(className))
161
+ // needReturnExport = false
162
+ // } else {
163
+ // exportStat = exportStatement(exportsVar, 'default', className)
164
+ // }
165
+
166
+ // program.pushContainer('body', [exportStat])
167
+ // needExportExpression = false
168
+ // } else {
169
+ // exportValue = toExpression(classNode)
170
+ // }
171
+ }
172
+
173
+ if (needExportExpression) {
174
+ let exportStat
175
+
176
+ if (i + 1 === length && isOnlyDefaultExport) {
177
+ exportStat = returnStatement(exportValue)
178
+ needReturnExport = false
179
+ } else {
180
+ exportStat = exportStatement(exportsVar, 'default', exportValue)
181
+ }
182
+
183
+ body[i] = exportStat
184
+ }
185
+ }
186
+
187
+ // export {x as y}
188
+ // export var a = 1
189
+ // export function test() {}
190
+ // export class Test {}
191
+ if (statement.type === 'ExportNamedDeclaration') {
192
+ hasExport = true
193
+ needReturnExport = true
194
+
195
+ const { specifiers, declaration } = statement
196
+
197
+ // export var a = 1
198
+ if (!specifiers.length) {
199
+ isOnlyDefaultExport = false
200
+
201
+ // replace "export <expression>"
202
+ // to "<expression>"
203
+ body[i] = declaration
204
+
205
+ // export var a = 1, b = 2
206
+ if (declaration.type === 'VariableDeclaration') {
207
+ for (const { id } of declaration.declarations) {
208
+ const { name } = id
209
+ const exportStat = exportStatement(exportsVar, name, identifier(name))
210
+ body.push(exportStat)
211
+ }
212
+ }
213
+
214
+ // export function x() {}
215
+ if (declaration.type === 'FunctionDeclaration') {
216
+ const asName = declaration.id.name
217
+
218
+ const exportStat = exportStatement(exportsVar, asName, identifier(asName))
219
+ body.push(exportStat)
220
+ }
221
+
222
+ // export class Test {}
223
+ if (declaration.type === 'ClassDeclaration') {
224
+ const asName = declaration.id.name
225
+
226
+ const exportStat = exportStatement(exportsVar, asName, identifier(asName))
227
+ body.push(exportStat)
228
+ }
229
+ } else { // export {x as y}
230
+ // export { ... } from "module"
231
+ const exportSource = statement.source
232
+ if (exportSource) {
233
+ // save import path
234
+ importPaths.push(exportSource)
235
+ // importVars.length should be equal importPaths.length
236
+ const importVar = generateUidIdentifier(exportSource.value, program)
237
+ importVars.push(importVar)
238
+
239
+ for (let specifier of specifiers) {
240
+ const { exported, local } = specifier
241
+ const { name } = local
242
+ let localName
243
+ // newly re-exporting earlier imported identifier
244
+ if (localImports.has(name)) {
245
+ localName = generateUid(name, program)
246
+ addExportStatement({ exported, local: identifier(localName) })
247
+ } else {
248
+ localName = name
249
+ addExportStatement(specifier)
250
+ }
251
+ namedImports.push(declareImport(localName, importVar.name, name))
252
+ }
253
+ } else {
254
+ for (const specifier of specifiers) {
255
+ addExportStatement(specifier)
256
+ }
257
+ }
258
+
259
+ body.splice(i--, 1)
260
+ --length
261
+ }
262
+ }
263
+
264
+ // export * from "module"
265
+ if (statement.type === 'ExportAllDeclaration') {
266
+ isOnlyDefaultExport = false
267
+ hasExport = true
268
+ needReturnExport = true
269
+
270
+ // save import path
271
+ const exportSource = statement.source
272
+ importPaths.push(exportSource)
273
+ // importVars.length should be equal importPaths.length
274
+ const importVar = generateUidIdentifier(exportSource.value, program)
275
+ importVars.push(importVar)
276
+
277
+ body[i] = exportCopyLoop(exportsVar, importVar)
278
+ }
279
+ }
280
+
281
+ // adding define wrapper
282
+ if (hasExport && needReturnExport) {
283
+ // var _exports = {}
284
+ body.unshift(
285
+ variableDeclaration('let', [
286
+ variableDeclarator(exportsVar, objectExpression([]))
287
+ ])
288
+ )
289
+
290
+ // return <expression>
291
+ let returnStat
292
+ if (isOnlyDefaultExport) {
293
+ // return _exports.default
294
+ returnStat = returnStatement(memberExpression(exportsVar, identifier('default')))
295
+ }
296
+ else {
297
+ // return _exports
298
+ returnStat = returnStatement(exportsVar)
299
+ }
300
+
301
+ body.push(returnStat)
302
+ }
303
+
304
+ buildAmdModule(program, options, importPaths, importVars, namedImports)
305
+
306
+ function addExportStatement({ exported, local }) {
307
+ const asName = exported.name
308
+ if (asName !== 'default') {
309
+ isOnlyDefaultExport = false
310
+ }
311
+ const exportStat = exportStatement(exportsVar, asName, local)
312
+ body.push(exportStat)
313
+ }
314
+ }
315
+
316
+ function declareImport(varName, object, property) {
317
+ return variableDeclaration('let', [
318
+ variableDeclarator(
319
+ identifier(varName),
320
+ memberExpression(identifier(object), identifier(property))
321
+ )
322
+ ])
323
+ }
324
+
325
+ function exportCopyLoop(exportsVar, importVar) {
326
+ const key = identifier('_key')
327
+ return forInStatement(
328
+ variableDeclaration('const', [variableDeclarator(key)]),
329
+ importVar,
330
+ blockStatement([
331
+ expressionStatement(
332
+ assignmentExpression('=',
333
+ memberExpression(exportsVar, key, true), memberExpression(importVar, key, true)))
334
+ ])
335
+ )
336
+ }
337
+
338
+ // Wraps a program body of statements into an AMD module.
339
+ function buildAmdModule(program, options, importPaths, importVars, namedImports) {
340
+ program.body = [
341
+ expressionStatement(callExpression(
342
+ identifier('define'), importPaths.length ? [
343
+ prepareImportPaths(importPaths, options),
344
+ functionExpression(importVars, blockStatement(namedImports.concat(program.body)))
345
+ ] : [
346
+ functionExpression([], blockStatement(program.body))
347
+ ]))
348
+ ]
349
+ }
350
+
351
+ // Update dependency paths to be prefixed by `esm!` or otherwise updated.
352
+ function prepareImportPaths(importPaths, options ) {
353
+ const { resolvePath } = options
354
+ if (resolvePath) {
355
+ const { sourceFileName: parentName } = options
356
+ for (const importPath of importPaths) {
357
+ if (importPath.type === 'Literal') {
358
+ const moduleName = importPath.value
359
+ const newModuleName = resolvePath(moduleName, parentName, options)
360
+ if (newModuleName && newModuleName !== moduleName) {
361
+ replaceLiteral(importPath, newModuleName)
362
+ }
363
+ }
364
+ }
365
+ }
366
+ return arrayExpression(importPaths)
367
+ }
@@ -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
+ }