Repository navigation
Expand file tree
/
Copy pathModuleSpecifierConverter.js
More file actions
126 lines (108 loc) · 4.81 KB
/
Copy pathModuleSpecifierConverter.js
File metadata and controls
126 lines (108 loc) · 4.81 KB
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
"use strict";
const path = require("path");
const assert = require("assert");
const fs = require("fs");
const DEFAULT_OPTIONS = {
variables: {},
moduleSpecifiers: {},
}
const IMPORT_REGEX = /\bimport\s+([\w\s{},*]*\s+from\s+)?['"`]([^'"`\r\n]+)['"`]/g
const EXPORT_REGEX = /\bexport\s+[\w\s{},*]+\s+from\s+['"`]([^'"`\r\n]+)['"`]/g
const DYNAMIC_IMPORT_REGEX = /\bimport\s*\(\s*['"`]([^'"`\r\n]+)['"`]\s*\)/g
function getSpecifierReplacements(replacementFunction, variables) {
let replacements;
if (typeof replacementFunction === "function") {
replacements = replacementFunction(variables);
} else {
replacements = replacementFunction;
}
if (!Array.isArray(replacements)) {
replacements = [replacements];
}
for (const replacement of replacements) {
if (typeof replacement !== "string") {
throw new TypeError(`Module specifier must be a non-empty string, received ${typeof pattern}`);
}
if (!replacement) {
throw new TypeError('Module specifier must be a non-empty string, received an empty string');
}
}
return replacements;
}
module.exports = class ModuleSpecifierConverter {
constructor(options) {
options = Object.assign({}, DEFAULT_OPTIONS, options);
this.options = Object.assign({
rootDir: ".",
}, options);
this.specifiers = options.moduleSpecifiers;
assert(options.baseDir && typeof options.baseDir === "string", "options.baseDir is required");
}
convert(jsSource, sourceFilePath, variables, additionalTransformFunc) {
const specifiers = this.specifiers;
const options = this.options;
const baseDir = options.baseDir;
const rootDir = options.rootDir;
function rewriteModulePath(modulePath) {
const specifier = modulePath.split("/", 1)[0];
let modulePathCandidates = [modulePath];
if (specifier === "" || specifier && specifier[0] !== "." && specifiers.hasOwnProperty(specifier)) {
//console.log(`Specifier: ${specifier}`);
if (specifier === "") {
// It starts with '/', resolve relative to rootDir
// (Defaults to current working directory if rootDir isn't set)
modulePathCandidates = [path.join(rootDir, modulePath)];
// modulePath = path.relative(path.dirname(destFilePath), modulePath);
} else if (specifiers.hasOwnProperty(specifier)) {
// Named specifier, look for replacement pattern
let replacements = getSpecifierReplacements(specifiers[specifier], variables);
modulePathCandidates = replacements.map(
replacement => {
if (replacement.startsWith("/")) {
replacement = path.join(rootDir, replacement);
} else {
replacement = path.join(baseDir, replacement);
}
return modulePath.replace(specifier, replacement);
}
)
}
// Find first candidate that exists, or go with first if none exist
modulePath = modulePathCandidates[0];
for (const candidate of modulePathCandidates) {
if (fs.existsSync(candidate.split('?')[0])) {
modulePath = candidate;
break;
}
}
// Make relative to current file
modulePath = path.relative(path.dirname(sourceFilePath), modulePath)
if (modulePath[0] != ".") {
if (modulePath[0] != "/") {
modulePath = "/" + modulePath;
}
modulePath = "." + modulePath;
}
}
if (additionalTransformFunc) {
modulePath = additionalTransformFunc(modulePath);
}
return modulePath;
}
const rewriteImport = (importStatement, modulePath) => {
const newModulePath = rewriteModulePath(modulePath);
if (newModulePath !== modulePath) {
importStatement = importStatement.replace(modulePath, newModulePath);
}
return importStatement;
}
return jsSource
.replace(IMPORT_REGEX,
(statement, _, modulePath) => rewriteImport(statement, modulePath),
).replace(EXPORT_REGEX,
(statement, modulePath) => rewriteImport(statement, modulePath),
).replace(DYNAMIC_IMPORT_REGEX,
(statement, modulePath) => rewriteImport(statement, modulePath),
);
}
}