forked from rollup/plugins
/
dynamic-import-to-glob.js
107 lines (90 loc) 路 3.14 KB
/
dynamic-import-to-glob.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import path from 'path';
export class VariableDynamicImportError extends Error {}
/* eslint-disable-next-line no-template-curly-in-string */
const example = 'For example: import(`./foo/${bar}.js`).';
function sanitizeString(str) {
if (str.includes('*')) {
throw new VariableDynamicImportError('A dynamic import cannot contain * characters.');
}
return str;
}
function templateLiteralToGlob(node) {
let glob = '';
for (let i = 0; i < node.quasis.length; i += 1) {
glob += sanitizeString(node.quasis[i].value.raw);
if (node.expressions[i]) {
glob += expressionToGlob(node.expressions[i]);
}
}
return glob;
}
function callExpressionToGlob(node) {
const { callee } = node;
if (
callee.type === 'MemberExpression' &&
callee.property.type === 'Identifier' &&
callee.property.name === 'concat'
) {
return `${expressionToGlob(callee.object)}${node.arguments.map(expressionToGlob).join('')}`;
}
return '*';
}
function binaryExpressionToGlob(node) {
if (node.operator !== '+') {
throw new VariableDynamicImportError(`${node.operator} operator is not supported.`);
}
return `${expressionToGlob(node.left)}${expressionToGlob(node.right)}`;
}
function expressionToGlob(node) {
switch (node.type) {
case 'TemplateLiteral':
return templateLiteralToGlob(node);
case 'CallExpression':
return callExpressionToGlob(node);
case 'BinaryExpression':
return binaryExpressionToGlob(node);
case 'Literal': {
return sanitizeString(node.value);
}
default:
return '*';
}
}
export function dynamicImportToGlob(node, sourceString) {
let glob = expressionToGlob(node);
if (!glob.includes('*') || glob.startsWith('data:') || glob.startsWith('https')) {
return null;
}
glob = glob.replace(/\*\*/g, '*');
if (glob.startsWith('*')) {
throw new VariableDynamicImportError(
`invalid import "${sourceString}". It cannot be statically analyzed. Variable dynamic imports must start with ./ and be limited to a specific directory. ${example}`
);
}
if (glob.startsWith('/')) {
throw new VariableDynamicImportError(
`invalid import "${sourceString}". Variable absolute imports are not supported, imports must start with ./ in the static part of the import. ${example}`
);
}
if (!glob.startsWith('./') && !glob.startsWith('../')) {
throw new VariableDynamicImportError(
`invalid import "${sourceString}". Variable bare imports are not supported, imports must start with ./ in the static part of the import. ${example}`
);
}
// Disallow ./*.ext
const ownDirectoryStarExtension = /^\.\/\*\.[\w]+$/;
if (ownDirectoryStarExtension.test(glob)) {
throw new VariableDynamicImportError(
`${
`invalid import "${sourceString}". Variable imports cannot import their own directory, ` +
'place imports in a separate directory or make the import filename more specific. '
}${example}`
);
}
if (path.extname(glob) === '') {
throw new VariableDynamicImportError(
`invalid import "${sourceString}". A file extension must be included in the static part of the import. ${example}`
);
}
return glob;
}