@bleedingdev/modern-js-server-utils 3.2.0-ultramodern.120 → 3.2.0-ultramodern.122
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/dist/cjs/compilers/typescript/importRewriter.js +242 -0
- package/dist/cjs/compilers/typescript/index.js +90 -32
- package/dist/esm/compilers/typescript/importRewriter.mjs +204 -0
- package/dist/esm/compilers/typescript/index.mjs +80 -31
- package/dist/esm-node/compilers/typescript/importRewriter.mjs +205 -0
- package/dist/esm-node/compilers/typescript/index.mjs +83 -31
- package/dist/types/compilers/typescript/importRewriter.d.ts +12 -0
- package/dist/types/compilers/typescript/index.d.ts +19 -0
- package/package.json +12 -4
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, getters, values)=>{
|
|
5
|
+
var define = (defs, kind)=>{
|
|
6
|
+
for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
[kind]: defs[key]
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
define(getters, "get");
|
|
12
|
+
define(values, "value");
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
(()=>{
|
|
16
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
17
|
+
})();
|
|
18
|
+
(()=>{
|
|
19
|
+
__webpack_require__.r = (exports1)=>{
|
|
20
|
+
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
21
|
+
value: 'Module'
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
24
|
+
value: true
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
})();
|
|
28
|
+
var __webpack_exports__ = {};
|
|
29
|
+
__webpack_require__.r(__webpack_exports__);
|
|
30
|
+
const IDENTIFIER_CHAR = /[A-Za-z0-9_$]/;
|
|
31
|
+
const WHITESPACE = /\s/;
|
|
32
|
+
const KEYWORDS_BEFORE_REGEX = new Set([
|
|
33
|
+
'return',
|
|
34
|
+
'typeof',
|
|
35
|
+
'instanceof',
|
|
36
|
+
'in',
|
|
37
|
+
'of',
|
|
38
|
+
'new',
|
|
39
|
+
'delete',
|
|
40
|
+
'void',
|
|
41
|
+
'throw',
|
|
42
|
+
'case',
|
|
43
|
+
'do',
|
|
44
|
+
'else',
|
|
45
|
+
'yield',
|
|
46
|
+
'await'
|
|
47
|
+
]);
|
|
48
|
+
const PUNCTUATORS_BEFORE_REGEX = new Set('{}(,;[=:?!&|+-*%^~<>/');
|
|
49
|
+
const isRegexAllowed = (lastToken)=>{
|
|
50
|
+
if (!lastToken) return true;
|
|
51
|
+
if (KEYWORDS_BEFORE_REGEX.has(lastToken)) return true;
|
|
52
|
+
return 1 === lastToken.length && PUNCTUATORS_BEFORE_REGEX.has(lastToken);
|
|
53
|
+
};
|
|
54
|
+
const isSpecifierContext = (prev1, prev2, prev3)=>{
|
|
55
|
+
if (('from' === prev1 || 'import' === prev1) && '.' !== prev2) return true;
|
|
56
|
+
return '(' === prev1 && ('import' === prev2 || 'require' === prev2) && '.' !== prev3;
|
|
57
|
+
};
|
|
58
|
+
const skipRegexLiteral = (content, start)=>{
|
|
59
|
+
let i = start + 1;
|
|
60
|
+
let inClass = false;
|
|
61
|
+
while(i < content.length){
|
|
62
|
+
const ch = content[i];
|
|
63
|
+
if ('\\' === ch) {
|
|
64
|
+
i += 2;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if ('\n' === ch) break;
|
|
68
|
+
if ('[' === ch) inClass = true;
|
|
69
|
+
else if (']' === ch) inClass = false;
|
|
70
|
+
else if ('/' === ch && !inClass) {
|
|
71
|
+
i++;
|
|
72
|
+
while(i < content.length && IDENTIFIER_CHAR.test(content[i]))i++;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
i++;
|
|
76
|
+
}
|
|
77
|
+
return i;
|
|
78
|
+
};
|
|
79
|
+
const scanSpecifiers = (content)=>{
|
|
80
|
+
const specifiers = [];
|
|
81
|
+
const length = content.length;
|
|
82
|
+
const templateExpressionDepths = [];
|
|
83
|
+
let prev1 = '';
|
|
84
|
+
let prev2 = '';
|
|
85
|
+
let prev3 = '';
|
|
86
|
+
const pushToken = (token)=>{
|
|
87
|
+
prev3 = prev2;
|
|
88
|
+
prev2 = prev1;
|
|
89
|
+
prev1 = token;
|
|
90
|
+
};
|
|
91
|
+
let mode = 'code';
|
|
92
|
+
let i = 0;
|
|
93
|
+
while(i < length){
|
|
94
|
+
const ch = content[i];
|
|
95
|
+
if ('template' === mode) {
|
|
96
|
+
if ('\\' === ch) {
|
|
97
|
+
i += 2;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if ('`' === ch) {
|
|
101
|
+
mode = 'code';
|
|
102
|
+
pushToken('`');
|
|
103
|
+
i++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if ('$' === ch && '{' === content[i + 1]) {
|
|
107
|
+
templateExpressionDepths.push(0);
|
|
108
|
+
mode = 'code';
|
|
109
|
+
pushToken('{');
|
|
110
|
+
i += 2;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
i++;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (WHITESPACE.test(ch)) {
|
|
117
|
+
i++;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if ('/' === ch) {
|
|
121
|
+
const next = content[i + 1];
|
|
122
|
+
if ('/' === next) {
|
|
123
|
+
const newline = content.indexOf('\n', i + 2);
|
|
124
|
+
i = -1 === newline ? length : newline + 1;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if ('*' === next) {
|
|
128
|
+
const end = content.indexOf('*/', i + 2);
|
|
129
|
+
i = -1 === end ? length : end + 2;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (isRegexAllowed(prev1)) {
|
|
133
|
+
i = skipRegexLiteral(content, i);
|
|
134
|
+
pushToken('/regex/');
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
pushToken('/');
|
|
138
|
+
i++;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if ('`' === ch) {
|
|
142
|
+
mode = 'template';
|
|
143
|
+
i++;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if ('{' === ch) {
|
|
147
|
+
if (templateExpressionDepths.length > 0) templateExpressionDepths[templateExpressionDepths.length - 1]++;
|
|
148
|
+
pushToken('{');
|
|
149
|
+
i++;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if ('}' === ch) {
|
|
153
|
+
if (templateExpressionDepths.length > 0) {
|
|
154
|
+
const top = templateExpressionDepths.length - 1;
|
|
155
|
+
if (0 === templateExpressionDepths[top]) {
|
|
156
|
+
templateExpressionDepths.pop();
|
|
157
|
+
mode = 'template';
|
|
158
|
+
i++;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
templateExpressionDepths[top]--;
|
|
162
|
+
}
|
|
163
|
+
pushToken('}');
|
|
164
|
+
i++;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if ('"' === ch || "'" === ch) {
|
|
168
|
+
const start = i;
|
|
169
|
+
let j = i + 1;
|
|
170
|
+
let terminated = false;
|
|
171
|
+
while(j < length){
|
|
172
|
+
const sch = content[j];
|
|
173
|
+
if ('\\' === sch) {
|
|
174
|
+
j += 2;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (sch === ch) {
|
|
178
|
+
terminated = true;
|
|
179
|
+
j++;
|
|
180
|
+
break;
|
|
181
|
+
}
|
|
182
|
+
if ('\n' === sch) break;
|
|
183
|
+
j++;
|
|
184
|
+
}
|
|
185
|
+
if (terminated && isSpecifierContext(prev1, prev2, prev3)) specifiers.push({
|
|
186
|
+
start: start + 1,
|
|
187
|
+
end: j - 1,
|
|
188
|
+
value: content.slice(start + 1, j - 1)
|
|
189
|
+
});
|
|
190
|
+
pushToken('"string"');
|
|
191
|
+
i = j;
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (IDENTIFIER_CHAR.test(ch)) {
|
|
195
|
+
let j = i + 1;
|
|
196
|
+
while(j < length && IDENTIFIER_CHAR.test(content[j]))j++;
|
|
197
|
+
pushToken(content.slice(i, j));
|
|
198
|
+
i = j;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
pushToken(ch);
|
|
202
|
+
i++;
|
|
203
|
+
}
|
|
204
|
+
return specifiers;
|
|
205
|
+
};
|
|
206
|
+
const rewriteImportSpecifiers = (content, rewrite)=>{
|
|
207
|
+
const specifiers = scanSpecifiers(content);
|
|
208
|
+
if (0 === specifiers.length) return {
|
|
209
|
+
content,
|
|
210
|
+
changed: false
|
|
211
|
+
};
|
|
212
|
+
let result = '';
|
|
213
|
+
let cursor = 0;
|
|
214
|
+
let changed = false;
|
|
215
|
+
for (const specifier of specifiers){
|
|
216
|
+
if (specifier.value.includes('\\')) continue;
|
|
217
|
+
const next = rewrite(specifier.value);
|
|
218
|
+
if (void 0 !== next && next !== specifier.value) {
|
|
219
|
+
changed = true;
|
|
220
|
+
result += content.slice(cursor, specifier.start) + next;
|
|
221
|
+
cursor = specifier.end;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (!changed) return {
|
|
225
|
+
content,
|
|
226
|
+
changed: false
|
|
227
|
+
};
|
|
228
|
+
return {
|
|
229
|
+
content: result + content.slice(cursor),
|
|
230
|
+
changed: true
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
__webpack_require__.d(__webpack_exports__, {}, {
|
|
234
|
+
rewriteImportSpecifiers: rewriteImportSpecifiers
|
|
235
|
+
});
|
|
236
|
+
exports.rewriteImportSpecifiers = __webpack_exports__.rewriteImportSpecifiers;
|
|
237
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
238
|
+
"rewriteImportSpecifiers"
|
|
239
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
240
|
+
Object.defineProperty(exports, '__esModule', {
|
|
241
|
+
value: true
|
|
242
|
+
});
|
|
@@ -37,14 +37,17 @@ var __webpack_require__ = {};
|
|
|
37
37
|
var __webpack_exports__ = {};
|
|
38
38
|
__webpack_require__.r(__webpack_exports__);
|
|
39
39
|
__webpack_require__.d(__webpack_exports__, {
|
|
40
|
-
compileByTs: ()=>compileByTs
|
|
40
|
+
compileByTs: ()=>compileByTs,
|
|
41
|
+
createResolvedTsgoConfig: ()=>createResolvedTsgoConfig,
|
|
42
|
+
getTsgoBinPath: ()=>getTsgoBinPath,
|
|
43
|
+
rewriteOutputSpecifiers: ()=>rewriteOutputSpecifiers
|
|
41
44
|
});
|
|
42
45
|
const utils_namespaceObject = require("@modern-js/utils");
|
|
43
46
|
const external_child_process_namespaceObject = require("child_process");
|
|
44
47
|
const external_path_namespaceObject = require("path");
|
|
45
48
|
var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
|
|
49
|
+
const external_importRewriter_js_namespaceObject = require("./importRewriter.js");
|
|
46
50
|
const external_tsconfigPathsPlugin_js_namespaceObject = require("./tsconfigPathsPlugin.js");
|
|
47
|
-
const importSpecifierRE = /((?:from\s*|import\s*\(\s*|require\s*\(\s*)['"])([^'"]+)(['"])/g;
|
|
48
51
|
const copyFiles = async (from, to, appDirectory)=>{
|
|
49
52
|
if (await utils_namespaceObject.fs.pathExists(from)) {
|
|
50
53
|
const relativePath = external_path_default().relative(appDirectory, from);
|
|
@@ -57,42 +60,55 @@ const copyFiles = async (from, to, appDirectory)=>{
|
|
|
57
60
|
});
|
|
58
61
|
}
|
|
59
62
|
};
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
let resolvedConfigCount = 0;
|
|
64
|
+
const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs, moduleType, tsgoBinPath)=>{
|
|
65
|
+
const tsconfigDir = external_path_default().dirname(tsconfigPath);
|
|
66
|
+
const output = await runTsgo(tsgoBinPath, [
|
|
62
67
|
'--showConfig',
|
|
63
68
|
'-p',
|
|
64
69
|
tsconfigPath
|
|
65
70
|
], {
|
|
66
|
-
cwd:
|
|
71
|
+
cwd: tsconfigDir
|
|
67
72
|
});
|
|
68
73
|
const config = JSON.parse(output.stdout);
|
|
69
74
|
config.compilerOptions ??= {};
|
|
70
75
|
config.compilerOptions.rootDir = appDirectory;
|
|
71
76
|
config.compilerOptions.outDir = distDir;
|
|
72
|
-
config.files = filterSourceFiles(
|
|
77
|
+
config.files = filterSourceFiles(tsconfigDir, sourceDirs, config.files);
|
|
73
78
|
delete config.include;
|
|
74
79
|
delete config.compilerOptions.baseUrl;
|
|
75
80
|
if ([
|
|
76
81
|
'node',
|
|
77
82
|
'node10'
|
|
78
83
|
].includes(String(config.compilerOptions.moduleResolution).toLowerCase())) delete config.compilerOptions.moduleResolution;
|
|
79
|
-
|
|
84
|
+
if ('module' !== moduleType && [
|
|
85
|
+
'preserve',
|
|
86
|
+
'esnext',
|
|
87
|
+
'es2015',
|
|
88
|
+
'es2020',
|
|
89
|
+
'es2022',
|
|
90
|
+
'es6'
|
|
91
|
+
].includes(String(config.compilerOptions.module).toLowerCase())) {
|
|
92
|
+
config.compilerOptions.module = 'commonjs';
|
|
93
|
+
delete config.compilerOptions.moduleResolution;
|
|
94
|
+
}
|
|
95
|
+
const resolvedConfigPath = external_path_default().join(tsconfigDir, `.tsgo.${process.pid}.${resolvedConfigCount++}.resolved.json`);
|
|
80
96
|
await utils_namespaceObject.fs.writeFile(resolvedConfigPath, JSON.stringify(config, null, 2));
|
|
81
97
|
return {
|
|
82
98
|
config,
|
|
83
99
|
resolvedConfigPath
|
|
84
100
|
};
|
|
85
101
|
};
|
|
86
|
-
const filterSourceFiles = (
|
|
102
|
+
const filterSourceFiles = (tsconfigDir, sourceDirs, files = [])=>{
|
|
87
103
|
const sourcePosixPaths = sourceDirs.map((sourceDir)=>sourceDir.split(external_path_default().sep).join(external_path_default().posix.sep));
|
|
88
104
|
return files.filter((fileName)=>{
|
|
89
|
-
const absoluteFileName = external_path_default().resolve(
|
|
105
|
+
const absoluteFileName = external_path_default().resolve(tsconfigDir, fileName).split(external_path_default().sep).join(external_path_default().posix.sep);
|
|
90
106
|
return fileName.endsWith('.d.ts') || sourcePosixPaths.some((sourceDir)=>absoluteFileName.includes(sourceDir));
|
|
91
107
|
});
|
|
92
108
|
};
|
|
93
|
-
const runTsgo = (args, options)=>new Promise((resolve, reject)=>{
|
|
109
|
+
const runTsgo = (tsgoBinPath, args, options)=>new Promise((resolve, reject)=>{
|
|
94
110
|
const child = (0, external_child_process_namespaceObject.spawn)(process.execPath, [
|
|
95
|
-
|
|
111
|
+
tsgoBinPath,
|
|
96
112
|
...args
|
|
97
113
|
], {
|
|
98
114
|
cwd: options.cwd,
|
|
@@ -121,14 +137,51 @@ const runTsgo = (args, options)=>new Promise((resolve, reject)=>{
|
|
|
121
137
|
resolve(result);
|
|
122
138
|
});
|
|
123
139
|
});
|
|
124
|
-
const getTsgoBinPath = (
|
|
140
|
+
const getTsgoBinPath = (appDirectory, resolvePaths = [
|
|
141
|
+
appDirectory,
|
|
142
|
+
__dirname
|
|
143
|
+
])=>{
|
|
144
|
+
try {
|
|
145
|
+
const pkgPath = require.resolve("@typescript/native-preview/package.json", {
|
|
146
|
+
paths: resolvePaths
|
|
147
|
+
});
|
|
148
|
+
return external_path_default().join(external_path_default().dirname(pkgPath), 'bin/tsgo.js');
|
|
149
|
+
} catch {
|
|
150
|
+
throw new Error('tsgo could not be found! Please install "@typescript/native-preview" in your project to compile BFF/server code.');
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const OUTPUT_SOURCE_EXTENSIONS = {
|
|
154
|
+
'.js': [
|
|
155
|
+
'.ts',
|
|
156
|
+
'.tsx',
|
|
157
|
+
'.js',
|
|
158
|
+
'.jsx'
|
|
159
|
+
],
|
|
160
|
+
'.mjs': [
|
|
161
|
+
'.mts',
|
|
162
|
+
'.mjs'
|
|
163
|
+
],
|
|
164
|
+
'.cjs': [
|
|
165
|
+
'.cts',
|
|
166
|
+
'.cjs'
|
|
167
|
+
]
|
|
168
|
+
};
|
|
125
169
|
const getSourceFileForOutput = (appDirectory, distDir, outputFile)=>{
|
|
126
170
|
const relativeOutput = external_path_default().relative(distDir, outputFile);
|
|
127
171
|
const parsed = external_path_default().parse(relativeOutput);
|
|
128
172
|
const sourceBase = external_path_default().join(appDirectory, parsed.dir, parsed.name);
|
|
129
|
-
|
|
173
|
+
const extensions = OUTPUT_SOURCE_EXTENSIONS[parsed.ext] ?? OUTPUT_SOURCE_EXTENSIONS['.js'];
|
|
174
|
+
for (const extension of extensions){
|
|
175
|
+
const candidate = `${sourceBase}${extension}`;
|
|
176
|
+
if (utils_namespaceObject.fs.existsSync(candidate)) return candidate;
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
const sourceMappingUrlRE = /^\/\/[#@] sourceMappingURL=.*$/gm;
|
|
180
|
+
const dropStaleSourceMap = async (outputFile, content)=>{
|
|
181
|
+
const mapFile = `${outputFile}.map`;
|
|
182
|
+
if (await utils_namespaceObject.fs.pathExists(mapFile)) await utils_namespaceObject.fs.remove(mapFile);
|
|
183
|
+
return content.replace(sourceMappingUrlRE, '');
|
|
130
184
|
};
|
|
131
|
-
const findExistingSource = (filePath)=>utils_namespaceObject.fs.existsSync(filePath) ? filePath : void 0;
|
|
132
185
|
const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, moduleType)=>{
|
|
133
186
|
if (0 === Object.keys(paths).length || !await utils_namespaceObject.fs.pathExists(distDir)) return;
|
|
134
187
|
const matcher = (0, external_tsconfigPathsPlugin_js_namespaceObject.createTsconfigPathsMatcher)(baseUrl, paths);
|
|
@@ -138,14 +191,8 @@ const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, mo
|
|
|
138
191
|
const sourceFile = getSourceFileForOutput(appDirectory, distDir, file);
|
|
139
192
|
if (!sourceFile) return;
|
|
140
193
|
const content = await utils_namespaceObject.fs.readFile(file, 'utf8');
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const nextSpecifier = (0, external_tsconfigPathsPlugin_js_namespaceObject.getNotAliasedPath)(sourceFile, matcher, specifier, moduleType);
|
|
144
|
-
if (!nextSpecifier || nextSpecifier === specifier) return match;
|
|
145
|
-
changed = true;
|
|
146
|
-
return `${prefix}${nextSpecifier}${suffix}`;
|
|
147
|
-
});
|
|
148
|
-
if (changed) await utils_namespaceObject.fs.writeFile(file, rewritten);
|
|
194
|
+
const { content: rewritten, changed } = (0, external_importRewriter_js_namespaceObject.rewriteImportSpecifiers)(content, (specifier)=>(0, external_tsconfigPathsPlugin_js_namespaceObject.getNotAliasedPath)(sourceFile, matcher, specifier, moduleType));
|
|
195
|
+
if (changed) await utils_namespaceObject.fs.writeFile(file, await dropStaleSourceMap(file, rewritten));
|
|
149
196
|
}));
|
|
150
197
|
};
|
|
151
198
|
const collectOutputFiles = async (dir)=>{
|
|
@@ -171,15 +218,20 @@ const compileByTs = async (appDirectory, config, compileOptions)=>{
|
|
|
171
218
|
tsconfigPath
|
|
172
219
|
});
|
|
173
220
|
const { paths = {}, absoluteBaseUrl = './' } = aliasOption;
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
221
|
+
const tsgoBinPath = getTsgoBinPath(appDirectory);
|
|
222
|
+
const { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs, compileOptions.moduleType, tsgoBinPath);
|
|
223
|
+
let result;
|
|
224
|
+
try {
|
|
225
|
+
result = await runTsgo(tsgoBinPath, [
|
|
226
|
+
'-p',
|
|
227
|
+
resolvedConfigPath
|
|
228
|
+
], {
|
|
229
|
+
cwd: appDirectory,
|
|
230
|
+
reject: false
|
|
231
|
+
});
|
|
232
|
+
} finally{
|
|
233
|
+
await utils_namespaceObject.fs.remove(resolvedConfigPath);
|
|
234
|
+
}
|
|
183
235
|
if (result.stderr) utils_namespaceObject.logger.error(result.stderr);
|
|
184
236
|
if (result.stdout) utils_namespaceObject.logger.info(result.stdout);
|
|
185
237
|
if (0 !== result.code) {
|
|
@@ -192,8 +244,14 @@ const compileByTs = async (appDirectory, config, compileOptions)=>{
|
|
|
192
244
|
utils_namespaceObject.logger.info("TS-Go compile succeed");
|
|
193
245
|
};
|
|
194
246
|
exports.compileByTs = __webpack_exports__.compileByTs;
|
|
247
|
+
exports.createResolvedTsgoConfig = __webpack_exports__.createResolvedTsgoConfig;
|
|
248
|
+
exports.getTsgoBinPath = __webpack_exports__.getTsgoBinPath;
|
|
249
|
+
exports.rewriteOutputSpecifiers = __webpack_exports__.rewriteOutputSpecifiers;
|
|
195
250
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
196
|
-
"compileByTs"
|
|
251
|
+
"compileByTs",
|
|
252
|
+
"createResolvedTsgoConfig",
|
|
253
|
+
"getTsgoBinPath",
|
|
254
|
+
"rewriteOutputSpecifiers"
|
|
197
255
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
198
256
|
Object.defineProperty(exports, '__esModule', {
|
|
199
257
|
value: true
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
const IDENTIFIER_CHAR = /[A-Za-z0-9_$]/;
|
|
2
|
+
const WHITESPACE = /\s/;
|
|
3
|
+
const KEYWORDS_BEFORE_REGEX = new Set([
|
|
4
|
+
'return',
|
|
5
|
+
'typeof',
|
|
6
|
+
'instanceof',
|
|
7
|
+
'in',
|
|
8
|
+
'of',
|
|
9
|
+
'new',
|
|
10
|
+
'delete',
|
|
11
|
+
'void',
|
|
12
|
+
'throw',
|
|
13
|
+
'case',
|
|
14
|
+
'do',
|
|
15
|
+
'else',
|
|
16
|
+
'yield',
|
|
17
|
+
'await'
|
|
18
|
+
]);
|
|
19
|
+
const PUNCTUATORS_BEFORE_REGEX = new Set('{}(,;[=:?!&|+-*%^~<>/');
|
|
20
|
+
const isRegexAllowed = (lastToken)=>{
|
|
21
|
+
if (!lastToken) return true;
|
|
22
|
+
if (KEYWORDS_BEFORE_REGEX.has(lastToken)) return true;
|
|
23
|
+
return 1 === lastToken.length && PUNCTUATORS_BEFORE_REGEX.has(lastToken);
|
|
24
|
+
};
|
|
25
|
+
const isSpecifierContext = (prev1, prev2, prev3)=>{
|
|
26
|
+
if (('from' === prev1 || 'import' === prev1) && '.' !== prev2) return true;
|
|
27
|
+
return '(' === prev1 && ('import' === prev2 || 'require' === prev2) && '.' !== prev3;
|
|
28
|
+
};
|
|
29
|
+
const skipRegexLiteral = (content, start)=>{
|
|
30
|
+
let i = start + 1;
|
|
31
|
+
let inClass = false;
|
|
32
|
+
while(i < content.length){
|
|
33
|
+
const ch = content[i];
|
|
34
|
+
if ('\\' === ch) {
|
|
35
|
+
i += 2;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if ('\n' === ch) break;
|
|
39
|
+
if ('[' === ch) inClass = true;
|
|
40
|
+
else if (']' === ch) inClass = false;
|
|
41
|
+
else if ('/' === ch && !inClass) {
|
|
42
|
+
i++;
|
|
43
|
+
while(i < content.length && IDENTIFIER_CHAR.test(content[i]))i++;
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
i++;
|
|
47
|
+
}
|
|
48
|
+
return i;
|
|
49
|
+
};
|
|
50
|
+
const scanSpecifiers = (content)=>{
|
|
51
|
+
const specifiers = [];
|
|
52
|
+
const length = content.length;
|
|
53
|
+
const templateExpressionDepths = [];
|
|
54
|
+
let prev1 = '';
|
|
55
|
+
let prev2 = '';
|
|
56
|
+
let prev3 = '';
|
|
57
|
+
const pushToken = (token)=>{
|
|
58
|
+
prev3 = prev2;
|
|
59
|
+
prev2 = prev1;
|
|
60
|
+
prev1 = token;
|
|
61
|
+
};
|
|
62
|
+
let mode = 'code';
|
|
63
|
+
let i = 0;
|
|
64
|
+
while(i < length){
|
|
65
|
+
const ch = content[i];
|
|
66
|
+
if ('template' === mode) {
|
|
67
|
+
if ('\\' === ch) {
|
|
68
|
+
i += 2;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if ('`' === ch) {
|
|
72
|
+
mode = 'code';
|
|
73
|
+
pushToken('`');
|
|
74
|
+
i++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if ('$' === ch && '{' === content[i + 1]) {
|
|
78
|
+
templateExpressionDepths.push(0);
|
|
79
|
+
mode = 'code';
|
|
80
|
+
pushToken('{');
|
|
81
|
+
i += 2;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
i++;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (WHITESPACE.test(ch)) {
|
|
88
|
+
i++;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if ('/' === ch) {
|
|
92
|
+
const next = content[i + 1];
|
|
93
|
+
if ('/' === next) {
|
|
94
|
+
const newline = content.indexOf('\n', i + 2);
|
|
95
|
+
i = -1 === newline ? length : newline + 1;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if ('*' === next) {
|
|
99
|
+
const end = content.indexOf('*/', i + 2);
|
|
100
|
+
i = -1 === end ? length : end + 2;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (isRegexAllowed(prev1)) {
|
|
104
|
+
i = skipRegexLiteral(content, i);
|
|
105
|
+
pushToken('/regex/');
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
pushToken('/');
|
|
109
|
+
i++;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if ('`' === ch) {
|
|
113
|
+
mode = 'template';
|
|
114
|
+
i++;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if ('{' === ch) {
|
|
118
|
+
if (templateExpressionDepths.length > 0) templateExpressionDepths[templateExpressionDepths.length - 1]++;
|
|
119
|
+
pushToken('{');
|
|
120
|
+
i++;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if ('}' === ch) {
|
|
124
|
+
if (templateExpressionDepths.length > 0) {
|
|
125
|
+
const top = templateExpressionDepths.length - 1;
|
|
126
|
+
if (0 === templateExpressionDepths[top]) {
|
|
127
|
+
templateExpressionDepths.pop();
|
|
128
|
+
mode = 'template';
|
|
129
|
+
i++;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
templateExpressionDepths[top]--;
|
|
133
|
+
}
|
|
134
|
+
pushToken('}');
|
|
135
|
+
i++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if ('"' === ch || "'" === ch) {
|
|
139
|
+
const start = i;
|
|
140
|
+
let j = i + 1;
|
|
141
|
+
let terminated = false;
|
|
142
|
+
while(j < length){
|
|
143
|
+
const sch = content[j];
|
|
144
|
+
if ('\\' === sch) {
|
|
145
|
+
j += 2;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (sch === ch) {
|
|
149
|
+
terminated = true;
|
|
150
|
+
j++;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
if ('\n' === sch) break;
|
|
154
|
+
j++;
|
|
155
|
+
}
|
|
156
|
+
if (terminated && isSpecifierContext(prev1, prev2, prev3)) specifiers.push({
|
|
157
|
+
start: start + 1,
|
|
158
|
+
end: j - 1,
|
|
159
|
+
value: content.slice(start + 1, j - 1)
|
|
160
|
+
});
|
|
161
|
+
pushToken('"string"');
|
|
162
|
+
i = j;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (IDENTIFIER_CHAR.test(ch)) {
|
|
166
|
+
let j = i + 1;
|
|
167
|
+
while(j < length && IDENTIFIER_CHAR.test(content[j]))j++;
|
|
168
|
+
pushToken(content.slice(i, j));
|
|
169
|
+
i = j;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
pushToken(ch);
|
|
173
|
+
i++;
|
|
174
|
+
}
|
|
175
|
+
return specifiers;
|
|
176
|
+
};
|
|
177
|
+
const rewriteImportSpecifiers = (content, rewrite)=>{
|
|
178
|
+
const specifiers = scanSpecifiers(content);
|
|
179
|
+
if (0 === specifiers.length) return {
|
|
180
|
+
content,
|
|
181
|
+
changed: false
|
|
182
|
+
};
|
|
183
|
+
let result = '';
|
|
184
|
+
let cursor = 0;
|
|
185
|
+
let changed = false;
|
|
186
|
+
for (const specifier of specifiers){
|
|
187
|
+
if (specifier.value.includes('\\')) continue;
|
|
188
|
+
const next = rewrite(specifier.value);
|
|
189
|
+
if (void 0 !== next && next !== specifier.value) {
|
|
190
|
+
changed = true;
|
|
191
|
+
result += content.slice(cursor, specifier.start) + next;
|
|
192
|
+
cursor = specifier.end;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (!changed) return {
|
|
196
|
+
content,
|
|
197
|
+
changed: false
|
|
198
|
+
};
|
|
199
|
+
return {
|
|
200
|
+
content: result + content.slice(cursor),
|
|
201
|
+
changed: true
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
export { rewriteImportSpecifiers };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { fs, getAliasConfig, logger } from "@modern-js/utils";
|
|
2
2
|
import { spawn } from "child_process";
|
|
3
3
|
import path from "path";
|
|
4
|
+
import { rewriteImportSpecifiers } from "./importRewriter.mjs";
|
|
4
5
|
import { createTsconfigPathsMatcher, getNotAliasedPath } from "./tsconfigPathsPlugin.mjs";
|
|
5
|
-
const importSpecifierRE = /((?:from\s*|import\s*\(\s*|require\s*\(\s*)['"])([^'"]+)(['"])/g;
|
|
6
6
|
const copyFiles = async (from, to, appDirectory)=>{
|
|
7
7
|
if (await fs.pathExists(from)) {
|
|
8
8
|
const relativePath = path.relative(appDirectory, from);
|
|
@@ -15,42 +15,55 @@ const copyFiles = async (from, to, appDirectory)=>{
|
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
let resolvedConfigCount = 0;
|
|
19
|
+
const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs, moduleType, tsgoBinPath)=>{
|
|
20
|
+
const tsconfigDir = path.dirname(tsconfigPath);
|
|
21
|
+
const output = await runTsgo(tsgoBinPath, [
|
|
20
22
|
'--showConfig',
|
|
21
23
|
'-p',
|
|
22
24
|
tsconfigPath
|
|
23
25
|
], {
|
|
24
|
-
cwd:
|
|
26
|
+
cwd: tsconfigDir
|
|
25
27
|
});
|
|
26
28
|
const config = JSON.parse(output.stdout);
|
|
27
29
|
config.compilerOptions ??= {};
|
|
28
30
|
config.compilerOptions.rootDir = appDirectory;
|
|
29
31
|
config.compilerOptions.outDir = distDir;
|
|
30
|
-
config.files = filterSourceFiles(
|
|
32
|
+
config.files = filterSourceFiles(tsconfigDir, sourceDirs, config.files);
|
|
31
33
|
delete config.include;
|
|
32
34
|
delete config.compilerOptions.baseUrl;
|
|
33
35
|
if ([
|
|
34
36
|
'node',
|
|
35
37
|
'node10'
|
|
36
38
|
].includes(String(config.compilerOptions.moduleResolution).toLowerCase())) delete config.compilerOptions.moduleResolution;
|
|
37
|
-
|
|
39
|
+
if ('module' !== moduleType && [
|
|
40
|
+
'preserve',
|
|
41
|
+
'esnext',
|
|
42
|
+
'es2015',
|
|
43
|
+
'es2020',
|
|
44
|
+
'es2022',
|
|
45
|
+
'es6'
|
|
46
|
+
].includes(String(config.compilerOptions.module).toLowerCase())) {
|
|
47
|
+
config.compilerOptions.module = 'commonjs';
|
|
48
|
+
delete config.compilerOptions.moduleResolution;
|
|
49
|
+
}
|
|
50
|
+
const resolvedConfigPath = path.join(tsconfigDir, `.tsgo.${process.pid}.${resolvedConfigCount++}.resolved.json`);
|
|
38
51
|
await fs.writeFile(resolvedConfigPath, JSON.stringify(config, null, 2));
|
|
39
52
|
return {
|
|
40
53
|
config,
|
|
41
54
|
resolvedConfigPath
|
|
42
55
|
};
|
|
43
56
|
};
|
|
44
|
-
const filterSourceFiles = (
|
|
57
|
+
const filterSourceFiles = (tsconfigDir, sourceDirs, files = [])=>{
|
|
45
58
|
const sourcePosixPaths = sourceDirs.map((sourceDir)=>sourceDir.split(path.sep).join(path.posix.sep));
|
|
46
59
|
return files.filter((fileName)=>{
|
|
47
|
-
const absoluteFileName = path.resolve(
|
|
60
|
+
const absoluteFileName = path.resolve(tsconfigDir, fileName).split(path.sep).join(path.posix.sep);
|
|
48
61
|
return fileName.endsWith('.d.ts') || sourcePosixPaths.some((sourceDir)=>absoluteFileName.includes(sourceDir));
|
|
49
62
|
});
|
|
50
63
|
};
|
|
51
|
-
const runTsgo = (args, options)=>new Promise((resolve, reject)=>{
|
|
64
|
+
const runTsgo = (tsgoBinPath, args, options)=>new Promise((resolve, reject)=>{
|
|
52
65
|
const child = spawn(process.execPath, [
|
|
53
|
-
|
|
66
|
+
tsgoBinPath,
|
|
54
67
|
...args
|
|
55
68
|
], {
|
|
56
69
|
cwd: options.cwd,
|
|
@@ -79,14 +92,51 @@ const runTsgo = (args, options)=>new Promise((resolve, reject)=>{
|
|
|
79
92
|
resolve(result);
|
|
80
93
|
});
|
|
81
94
|
});
|
|
82
|
-
const getTsgoBinPath = (
|
|
95
|
+
const getTsgoBinPath = (appDirectory, resolvePaths = [
|
|
96
|
+
appDirectory,
|
|
97
|
+
__dirname
|
|
98
|
+
])=>{
|
|
99
|
+
try {
|
|
100
|
+
const pkgPath = require.resolve("@typescript/native-preview/package.json", {
|
|
101
|
+
paths: resolvePaths
|
|
102
|
+
});
|
|
103
|
+
return path.join(path.dirname(pkgPath), 'bin/tsgo.js');
|
|
104
|
+
} catch {
|
|
105
|
+
throw new Error('tsgo could not be found! Please install "@typescript/native-preview" in your project to compile BFF/server code.');
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const OUTPUT_SOURCE_EXTENSIONS = {
|
|
109
|
+
'.js': [
|
|
110
|
+
'.ts',
|
|
111
|
+
'.tsx',
|
|
112
|
+
'.js',
|
|
113
|
+
'.jsx'
|
|
114
|
+
],
|
|
115
|
+
'.mjs': [
|
|
116
|
+
'.mts',
|
|
117
|
+
'.mjs'
|
|
118
|
+
],
|
|
119
|
+
'.cjs': [
|
|
120
|
+
'.cts',
|
|
121
|
+
'.cjs'
|
|
122
|
+
]
|
|
123
|
+
};
|
|
83
124
|
const getSourceFileForOutput = (appDirectory, distDir, outputFile)=>{
|
|
84
125
|
const relativeOutput = path.relative(distDir, outputFile);
|
|
85
126
|
const parsed = path.parse(relativeOutput);
|
|
86
127
|
const sourceBase = path.join(appDirectory, parsed.dir, parsed.name);
|
|
87
|
-
|
|
128
|
+
const extensions = OUTPUT_SOURCE_EXTENSIONS[parsed.ext] ?? OUTPUT_SOURCE_EXTENSIONS['.js'];
|
|
129
|
+
for (const extension of extensions){
|
|
130
|
+
const candidate = `${sourceBase}${extension}`;
|
|
131
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const sourceMappingUrlRE = /^\/\/[#@] sourceMappingURL=.*$/gm;
|
|
135
|
+
const dropStaleSourceMap = async (outputFile, content)=>{
|
|
136
|
+
const mapFile = `${outputFile}.map`;
|
|
137
|
+
if (await fs.pathExists(mapFile)) await fs.remove(mapFile);
|
|
138
|
+
return content.replace(sourceMappingUrlRE, '');
|
|
88
139
|
};
|
|
89
|
-
const findExistingSource = (filePath)=>fs.existsSync(filePath) ? filePath : void 0;
|
|
90
140
|
const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, moduleType)=>{
|
|
91
141
|
if (0 === Object.keys(paths).length || !await fs.pathExists(distDir)) return;
|
|
92
142
|
const matcher = createTsconfigPathsMatcher(baseUrl, paths);
|
|
@@ -96,14 +146,8 @@ const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, mo
|
|
|
96
146
|
const sourceFile = getSourceFileForOutput(appDirectory, distDir, file);
|
|
97
147
|
if (!sourceFile) return;
|
|
98
148
|
const content = await fs.readFile(file, 'utf8');
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const nextSpecifier = getNotAliasedPath(sourceFile, matcher, specifier, moduleType);
|
|
102
|
-
if (!nextSpecifier || nextSpecifier === specifier) return match;
|
|
103
|
-
changed = true;
|
|
104
|
-
return `${prefix}${nextSpecifier}${suffix}`;
|
|
105
|
-
});
|
|
106
|
-
if (changed) await fs.writeFile(file, rewritten);
|
|
149
|
+
const { content: rewritten, changed } = rewriteImportSpecifiers(content, (specifier)=>getNotAliasedPath(sourceFile, matcher, specifier, moduleType));
|
|
150
|
+
if (changed) await fs.writeFile(file, await dropStaleSourceMap(file, rewritten));
|
|
107
151
|
}));
|
|
108
152
|
};
|
|
109
153
|
const collectOutputFiles = async (dir)=>{
|
|
@@ -129,15 +173,20 @@ const compileByTs = async (appDirectory, config, compileOptions)=>{
|
|
|
129
173
|
tsconfigPath
|
|
130
174
|
});
|
|
131
175
|
const { paths = {}, absoluteBaseUrl = './' } = aliasOption;
|
|
132
|
-
const
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
176
|
+
const tsgoBinPath = getTsgoBinPath(appDirectory);
|
|
177
|
+
const { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs, compileOptions.moduleType, tsgoBinPath);
|
|
178
|
+
let result;
|
|
179
|
+
try {
|
|
180
|
+
result = await runTsgo(tsgoBinPath, [
|
|
181
|
+
'-p',
|
|
182
|
+
resolvedConfigPath
|
|
183
|
+
], {
|
|
184
|
+
cwd: appDirectory,
|
|
185
|
+
reject: false
|
|
186
|
+
});
|
|
187
|
+
} finally{
|
|
188
|
+
await fs.remove(resolvedConfigPath);
|
|
189
|
+
}
|
|
141
190
|
if (result.stderr) logger.error(result.stderr);
|
|
142
191
|
if (result.stdout) logger.info(result.stdout);
|
|
143
192
|
if (0 !== result.code) {
|
|
@@ -149,4 +198,4 @@ const compileByTs = async (appDirectory, config, compileOptions)=>{
|
|
|
149
198
|
for (const source of sourceDirs)await copyFiles(source, distDir, appDirectory);
|
|
150
199
|
logger.info("TS-Go compile succeed");
|
|
151
200
|
};
|
|
152
|
-
export { compileByTs };
|
|
201
|
+
export { compileByTs, createResolvedTsgoConfig, getTsgoBinPath, rewriteOutputSpecifiers };
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
const IDENTIFIER_CHAR = /[A-Za-z0-9_$]/;
|
|
3
|
+
const WHITESPACE = /\s/;
|
|
4
|
+
const KEYWORDS_BEFORE_REGEX = new Set([
|
|
5
|
+
'return',
|
|
6
|
+
'typeof',
|
|
7
|
+
'instanceof',
|
|
8
|
+
'in',
|
|
9
|
+
'of',
|
|
10
|
+
'new',
|
|
11
|
+
'delete',
|
|
12
|
+
'void',
|
|
13
|
+
'throw',
|
|
14
|
+
'case',
|
|
15
|
+
'do',
|
|
16
|
+
'else',
|
|
17
|
+
'yield',
|
|
18
|
+
'await'
|
|
19
|
+
]);
|
|
20
|
+
const PUNCTUATORS_BEFORE_REGEX = new Set('{}(,;[=:?!&|+-*%^~<>/');
|
|
21
|
+
const isRegexAllowed = (lastToken)=>{
|
|
22
|
+
if (!lastToken) return true;
|
|
23
|
+
if (KEYWORDS_BEFORE_REGEX.has(lastToken)) return true;
|
|
24
|
+
return 1 === lastToken.length && PUNCTUATORS_BEFORE_REGEX.has(lastToken);
|
|
25
|
+
};
|
|
26
|
+
const isSpecifierContext = (prev1, prev2, prev3)=>{
|
|
27
|
+
if (('from' === prev1 || 'import' === prev1) && '.' !== prev2) return true;
|
|
28
|
+
return '(' === prev1 && ('import' === prev2 || 'require' === prev2) && '.' !== prev3;
|
|
29
|
+
};
|
|
30
|
+
const skipRegexLiteral = (content, start)=>{
|
|
31
|
+
let i = start + 1;
|
|
32
|
+
let inClass = false;
|
|
33
|
+
while(i < content.length){
|
|
34
|
+
const ch = content[i];
|
|
35
|
+
if ('\\' === ch) {
|
|
36
|
+
i += 2;
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if ('\n' === ch) break;
|
|
40
|
+
if ('[' === ch) inClass = true;
|
|
41
|
+
else if (']' === ch) inClass = false;
|
|
42
|
+
else if ('/' === ch && !inClass) {
|
|
43
|
+
i++;
|
|
44
|
+
while(i < content.length && IDENTIFIER_CHAR.test(content[i]))i++;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
i++;
|
|
48
|
+
}
|
|
49
|
+
return i;
|
|
50
|
+
};
|
|
51
|
+
const scanSpecifiers = (content)=>{
|
|
52
|
+
const specifiers = [];
|
|
53
|
+
const length = content.length;
|
|
54
|
+
const templateExpressionDepths = [];
|
|
55
|
+
let prev1 = '';
|
|
56
|
+
let prev2 = '';
|
|
57
|
+
let prev3 = '';
|
|
58
|
+
const pushToken = (token)=>{
|
|
59
|
+
prev3 = prev2;
|
|
60
|
+
prev2 = prev1;
|
|
61
|
+
prev1 = token;
|
|
62
|
+
};
|
|
63
|
+
let mode = 'code';
|
|
64
|
+
let i = 0;
|
|
65
|
+
while(i < length){
|
|
66
|
+
const ch = content[i];
|
|
67
|
+
if ('template' === mode) {
|
|
68
|
+
if ('\\' === ch) {
|
|
69
|
+
i += 2;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if ('`' === ch) {
|
|
73
|
+
mode = 'code';
|
|
74
|
+
pushToken('`');
|
|
75
|
+
i++;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if ('$' === ch && '{' === content[i + 1]) {
|
|
79
|
+
templateExpressionDepths.push(0);
|
|
80
|
+
mode = 'code';
|
|
81
|
+
pushToken('{');
|
|
82
|
+
i += 2;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
i++;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (WHITESPACE.test(ch)) {
|
|
89
|
+
i++;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if ('/' === ch) {
|
|
93
|
+
const next = content[i + 1];
|
|
94
|
+
if ('/' === next) {
|
|
95
|
+
const newline = content.indexOf('\n', i + 2);
|
|
96
|
+
i = -1 === newline ? length : newline + 1;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
if ('*' === next) {
|
|
100
|
+
const end = content.indexOf('*/', i + 2);
|
|
101
|
+
i = -1 === end ? length : end + 2;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (isRegexAllowed(prev1)) {
|
|
105
|
+
i = skipRegexLiteral(content, i);
|
|
106
|
+
pushToken('/regex/');
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
pushToken('/');
|
|
110
|
+
i++;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if ('`' === ch) {
|
|
114
|
+
mode = 'template';
|
|
115
|
+
i++;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if ('{' === ch) {
|
|
119
|
+
if (templateExpressionDepths.length > 0) templateExpressionDepths[templateExpressionDepths.length - 1]++;
|
|
120
|
+
pushToken('{');
|
|
121
|
+
i++;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if ('}' === ch) {
|
|
125
|
+
if (templateExpressionDepths.length > 0) {
|
|
126
|
+
const top = templateExpressionDepths.length - 1;
|
|
127
|
+
if (0 === templateExpressionDepths[top]) {
|
|
128
|
+
templateExpressionDepths.pop();
|
|
129
|
+
mode = 'template';
|
|
130
|
+
i++;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
templateExpressionDepths[top]--;
|
|
134
|
+
}
|
|
135
|
+
pushToken('}');
|
|
136
|
+
i++;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if ('"' === ch || "'" === ch) {
|
|
140
|
+
const start = i;
|
|
141
|
+
let j = i + 1;
|
|
142
|
+
let terminated = false;
|
|
143
|
+
while(j < length){
|
|
144
|
+
const sch = content[j];
|
|
145
|
+
if ('\\' === sch) {
|
|
146
|
+
j += 2;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (sch === ch) {
|
|
150
|
+
terminated = true;
|
|
151
|
+
j++;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
if ('\n' === sch) break;
|
|
155
|
+
j++;
|
|
156
|
+
}
|
|
157
|
+
if (terminated && isSpecifierContext(prev1, prev2, prev3)) specifiers.push({
|
|
158
|
+
start: start + 1,
|
|
159
|
+
end: j - 1,
|
|
160
|
+
value: content.slice(start + 1, j - 1)
|
|
161
|
+
});
|
|
162
|
+
pushToken('"string"');
|
|
163
|
+
i = j;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (IDENTIFIER_CHAR.test(ch)) {
|
|
167
|
+
let j = i + 1;
|
|
168
|
+
while(j < length && IDENTIFIER_CHAR.test(content[j]))j++;
|
|
169
|
+
pushToken(content.slice(i, j));
|
|
170
|
+
i = j;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
pushToken(ch);
|
|
174
|
+
i++;
|
|
175
|
+
}
|
|
176
|
+
return specifiers;
|
|
177
|
+
};
|
|
178
|
+
const rewriteImportSpecifiers = (content, rewrite)=>{
|
|
179
|
+
const specifiers = scanSpecifiers(content);
|
|
180
|
+
if (0 === specifiers.length) return {
|
|
181
|
+
content,
|
|
182
|
+
changed: false
|
|
183
|
+
};
|
|
184
|
+
let result = '';
|
|
185
|
+
let cursor = 0;
|
|
186
|
+
let changed = false;
|
|
187
|
+
for (const specifier of specifiers){
|
|
188
|
+
if (specifier.value.includes('\\')) continue;
|
|
189
|
+
const next = rewrite(specifier.value);
|
|
190
|
+
if (void 0 !== next && next !== specifier.value) {
|
|
191
|
+
changed = true;
|
|
192
|
+
result += content.slice(cursor, specifier.start) + next;
|
|
193
|
+
cursor = specifier.end;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (!changed) return {
|
|
197
|
+
content,
|
|
198
|
+
changed: false
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
content: result + content.slice(cursor),
|
|
202
|
+
changed: true
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
export { rewriteImportSpecifiers };
|
|
@@ -3,8 +3,11 @@ const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/
|
|
|
3
3
|
import { fs, getAliasConfig, logger } from "@modern-js/utils";
|
|
4
4
|
import { spawn } from "child_process";
|
|
5
5
|
import path from "path";
|
|
6
|
+
import { rewriteImportSpecifiers } from "./importRewriter.mjs";
|
|
6
7
|
import { createTsconfigPathsMatcher, getNotAliasedPath } from "./tsconfigPathsPlugin.mjs";
|
|
7
|
-
|
|
8
|
+
import { fileURLToPath as __rspack_fileURLToPath } from "node:url";
|
|
9
|
+
import { dirname as __rspack_dirname } from "node:path";
|
|
10
|
+
var typescript_dirname = __rspack_dirname(__rspack_fileURLToPath(import.meta.url));
|
|
8
11
|
const copyFiles = async (from, to, appDirectory)=>{
|
|
9
12
|
if (await fs.pathExists(from)) {
|
|
10
13
|
const relativePath = path.relative(appDirectory, from);
|
|
@@ -17,42 +20,55 @@ const copyFiles = async (from, to, appDirectory)=>{
|
|
|
17
20
|
});
|
|
18
21
|
}
|
|
19
22
|
};
|
|
20
|
-
|
|
21
|
-
|
|
23
|
+
let resolvedConfigCount = 0;
|
|
24
|
+
const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs, moduleType, tsgoBinPath)=>{
|
|
25
|
+
const tsconfigDir = path.dirname(tsconfigPath);
|
|
26
|
+
const output = await runTsgo(tsgoBinPath, [
|
|
22
27
|
'--showConfig',
|
|
23
28
|
'-p',
|
|
24
29
|
tsconfigPath
|
|
25
30
|
], {
|
|
26
|
-
cwd:
|
|
31
|
+
cwd: tsconfigDir
|
|
27
32
|
});
|
|
28
33
|
const config = JSON.parse(output.stdout);
|
|
29
34
|
config.compilerOptions ??= {};
|
|
30
35
|
config.compilerOptions.rootDir = appDirectory;
|
|
31
36
|
config.compilerOptions.outDir = distDir;
|
|
32
|
-
config.files = filterSourceFiles(
|
|
37
|
+
config.files = filterSourceFiles(tsconfigDir, sourceDirs, config.files);
|
|
33
38
|
delete config.include;
|
|
34
39
|
delete config.compilerOptions.baseUrl;
|
|
35
40
|
if ([
|
|
36
41
|
'node',
|
|
37
42
|
'node10'
|
|
38
43
|
].includes(String(config.compilerOptions.moduleResolution).toLowerCase())) delete config.compilerOptions.moduleResolution;
|
|
39
|
-
|
|
44
|
+
if ('module' !== moduleType && [
|
|
45
|
+
'preserve',
|
|
46
|
+
'esnext',
|
|
47
|
+
'es2015',
|
|
48
|
+
'es2020',
|
|
49
|
+
'es2022',
|
|
50
|
+
'es6'
|
|
51
|
+
].includes(String(config.compilerOptions.module).toLowerCase())) {
|
|
52
|
+
config.compilerOptions.module = 'commonjs';
|
|
53
|
+
delete config.compilerOptions.moduleResolution;
|
|
54
|
+
}
|
|
55
|
+
const resolvedConfigPath = path.join(tsconfigDir, `.tsgo.${process.pid}.${resolvedConfigCount++}.resolved.json`);
|
|
40
56
|
await fs.writeFile(resolvedConfigPath, JSON.stringify(config, null, 2));
|
|
41
57
|
return {
|
|
42
58
|
config,
|
|
43
59
|
resolvedConfigPath
|
|
44
60
|
};
|
|
45
61
|
};
|
|
46
|
-
const filterSourceFiles = (
|
|
62
|
+
const filterSourceFiles = (tsconfigDir, sourceDirs, files = [])=>{
|
|
47
63
|
const sourcePosixPaths = sourceDirs.map((sourceDir)=>sourceDir.split(path.sep).join(path.posix.sep));
|
|
48
64
|
return files.filter((fileName)=>{
|
|
49
|
-
const absoluteFileName = path.resolve(
|
|
65
|
+
const absoluteFileName = path.resolve(tsconfigDir, fileName).split(path.sep).join(path.posix.sep);
|
|
50
66
|
return fileName.endsWith('.d.ts') || sourcePosixPaths.some((sourceDir)=>absoluteFileName.includes(sourceDir));
|
|
51
67
|
});
|
|
52
68
|
};
|
|
53
|
-
const runTsgo = (args, options)=>new Promise((resolve, reject)=>{
|
|
69
|
+
const runTsgo = (tsgoBinPath, args, options)=>new Promise((resolve, reject)=>{
|
|
54
70
|
const child = spawn(process.execPath, [
|
|
55
|
-
|
|
71
|
+
tsgoBinPath,
|
|
56
72
|
...args
|
|
57
73
|
], {
|
|
58
74
|
cwd: options.cwd,
|
|
@@ -81,14 +97,51 @@ const runTsgo = (args, options)=>new Promise((resolve, reject)=>{
|
|
|
81
97
|
resolve(result);
|
|
82
98
|
});
|
|
83
99
|
});
|
|
84
|
-
const getTsgoBinPath = (
|
|
100
|
+
const getTsgoBinPath = (appDirectory, resolvePaths = [
|
|
101
|
+
appDirectory,
|
|
102
|
+
typescript_dirname
|
|
103
|
+
])=>{
|
|
104
|
+
try {
|
|
105
|
+
const pkgPath = require.resolve("@typescript/native-preview/package.json", {
|
|
106
|
+
paths: resolvePaths
|
|
107
|
+
});
|
|
108
|
+
return path.join(path.dirname(pkgPath), 'bin/tsgo.js');
|
|
109
|
+
} catch {
|
|
110
|
+
throw new Error('tsgo could not be found! Please install "@typescript/native-preview" in your project to compile BFF/server code.');
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const OUTPUT_SOURCE_EXTENSIONS = {
|
|
114
|
+
'.js': [
|
|
115
|
+
'.ts',
|
|
116
|
+
'.tsx',
|
|
117
|
+
'.js',
|
|
118
|
+
'.jsx'
|
|
119
|
+
],
|
|
120
|
+
'.mjs': [
|
|
121
|
+
'.mts',
|
|
122
|
+
'.mjs'
|
|
123
|
+
],
|
|
124
|
+
'.cjs': [
|
|
125
|
+
'.cts',
|
|
126
|
+
'.cjs'
|
|
127
|
+
]
|
|
128
|
+
};
|
|
85
129
|
const getSourceFileForOutput = (appDirectory, distDir, outputFile)=>{
|
|
86
130
|
const relativeOutput = path.relative(distDir, outputFile);
|
|
87
131
|
const parsed = path.parse(relativeOutput);
|
|
88
132
|
const sourceBase = path.join(appDirectory, parsed.dir, parsed.name);
|
|
89
|
-
|
|
133
|
+
const extensions = OUTPUT_SOURCE_EXTENSIONS[parsed.ext] ?? OUTPUT_SOURCE_EXTENSIONS['.js'];
|
|
134
|
+
for (const extension of extensions){
|
|
135
|
+
const candidate = `${sourceBase}${extension}`;
|
|
136
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
const sourceMappingUrlRE = /^\/\/[#@] sourceMappingURL=.*$/gm;
|
|
140
|
+
const dropStaleSourceMap = async (outputFile, content)=>{
|
|
141
|
+
const mapFile = `${outputFile}.map`;
|
|
142
|
+
if (await fs.pathExists(mapFile)) await fs.remove(mapFile);
|
|
143
|
+
return content.replace(sourceMappingUrlRE, '');
|
|
90
144
|
};
|
|
91
|
-
const findExistingSource = (filePath)=>fs.existsSync(filePath) ? filePath : void 0;
|
|
92
145
|
const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, moduleType)=>{
|
|
93
146
|
if (0 === Object.keys(paths).length || !await fs.pathExists(distDir)) return;
|
|
94
147
|
const matcher = createTsconfigPathsMatcher(baseUrl, paths);
|
|
@@ -98,14 +151,8 @@ const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, mo
|
|
|
98
151
|
const sourceFile = getSourceFileForOutput(appDirectory, distDir, file);
|
|
99
152
|
if (!sourceFile) return;
|
|
100
153
|
const content = await fs.readFile(file, 'utf8');
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const nextSpecifier = getNotAliasedPath(sourceFile, matcher, specifier, moduleType);
|
|
104
|
-
if (!nextSpecifier || nextSpecifier === specifier) return match;
|
|
105
|
-
changed = true;
|
|
106
|
-
return `${prefix}${nextSpecifier}${suffix}`;
|
|
107
|
-
});
|
|
108
|
-
if (changed) await fs.writeFile(file, rewritten);
|
|
154
|
+
const { content: rewritten, changed } = rewriteImportSpecifiers(content, (specifier)=>getNotAliasedPath(sourceFile, matcher, specifier, moduleType));
|
|
155
|
+
if (changed) await fs.writeFile(file, await dropStaleSourceMap(file, rewritten));
|
|
109
156
|
}));
|
|
110
157
|
};
|
|
111
158
|
const collectOutputFiles = async (dir)=>{
|
|
@@ -131,15 +178,20 @@ const compileByTs = async (appDirectory, config, compileOptions)=>{
|
|
|
131
178
|
tsconfigPath
|
|
132
179
|
});
|
|
133
180
|
const { paths = {}, absoluteBaseUrl = './' } = aliasOption;
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
181
|
+
const tsgoBinPath = getTsgoBinPath(appDirectory);
|
|
182
|
+
const { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs, compileOptions.moduleType, tsgoBinPath);
|
|
183
|
+
let result;
|
|
184
|
+
try {
|
|
185
|
+
result = await runTsgo(tsgoBinPath, [
|
|
186
|
+
'-p',
|
|
187
|
+
resolvedConfigPath
|
|
188
|
+
], {
|
|
189
|
+
cwd: appDirectory,
|
|
190
|
+
reject: false
|
|
191
|
+
});
|
|
192
|
+
} finally{
|
|
193
|
+
await fs.remove(resolvedConfigPath);
|
|
194
|
+
}
|
|
143
195
|
if (result.stderr) logger.error(result.stderr);
|
|
144
196
|
if (result.stdout) logger.info(result.stdout);
|
|
145
197
|
if (0 !== result.code) {
|
|
@@ -151,4 +203,4 @@ const compileByTs = async (appDirectory, config, compileOptions)=>{
|
|
|
151
203
|
for (const source of sourceDirs)await copyFiles(source, distDir, appDirectory);
|
|
152
204
|
logger.info("TS-Go compile succeed");
|
|
153
205
|
};
|
|
154
|
-
export { compileByTs };
|
|
206
|
+
export { compileByTs, createResolvedTsgoConfig, getTsgoBinPath, rewriteOutputSpecifiers };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type SpecifierRewrite = (specifier: string) => string | undefined;
|
|
2
|
+
/**
|
|
3
|
+
* Rewrite the import/export/require specifiers of emitted JavaScript.
|
|
4
|
+
*
|
|
5
|
+
* Specifiers whose contents contain escape sequences are left untouched (the
|
|
6
|
+
* raw source slice would not round-trip), which never happens for the
|
|
7
|
+
* compiler-emitted relative/alias specifiers this is used on.
|
|
8
|
+
*/
|
|
9
|
+
export declare const rewriteImportSpecifiers: (content: string, rewrite: SpecifierRewrite) => {
|
|
10
|
+
content: string;
|
|
11
|
+
changed: boolean;
|
|
12
|
+
};
|
|
@@ -1,2 +1,21 @@
|
|
|
1
1
|
import type { CompileFunc } from '../../common';
|
|
2
|
+
type TsgoConfig = {
|
|
3
|
+
compilerOptions?: {
|
|
4
|
+
baseUrl?: unknown;
|
|
5
|
+
module?: string;
|
|
6
|
+
moduleResolution?: string;
|
|
7
|
+
noEmitOnError?: boolean;
|
|
8
|
+
outDir?: string;
|
|
9
|
+
rootDir?: string;
|
|
10
|
+
};
|
|
11
|
+
files?: string[];
|
|
12
|
+
include?: string[];
|
|
13
|
+
};
|
|
14
|
+
export declare const createResolvedTsgoConfig: (appDirectory: string, tsconfigPath: string, distDir: string, sourceDirs: string[], moduleType: 'module' | 'commonjs' | undefined, tsgoBinPath: string) => Promise<{
|
|
15
|
+
config: TsgoConfig;
|
|
16
|
+
resolvedConfigPath: string;
|
|
17
|
+
}>;
|
|
18
|
+
export declare const getTsgoBinPath: (appDirectory: string, resolvePaths?: string[]) => string;
|
|
19
|
+
export declare const rewriteOutputSpecifiers: (appDirectory: string, distDir: string, baseUrl: string, paths: Record<string, string[] | string>, moduleType?: 'module' | 'commonjs') => Promise<void>;
|
|
2
20
|
export declare const compileByTs: CompileFunc;
|
|
21
|
+
export {};
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"modern",
|
|
18
18
|
"modern.js"
|
|
19
19
|
],
|
|
20
|
-
"version": "3.2.0-ultramodern.
|
|
20
|
+
"version": "3.2.0-ultramodern.122",
|
|
21
21
|
"types": "./dist/types/index.d.ts",
|
|
22
22
|
"main": "./dist/cjs/index.js",
|
|
23
23
|
"exports": {
|
|
@@ -40,14 +40,22 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@swc/helpers": "^0.5.23",
|
|
43
|
-
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.
|
|
43
|
+
"@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.122"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@rslib/core": "0.22.0",
|
|
47
47
|
"@types/node": "^25.9.3",
|
|
48
48
|
"@typescript/native-preview": "7.0.0-dev.20260610.1",
|
|
49
|
-
"@
|
|
50
|
-
"@
|
|
49
|
+
"@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.2.0-ultramodern.122",
|
|
50
|
+
"@scripts/rstest-config": "2.66.0"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@typescript/native-preview": ">=7.0.0-dev.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependenciesMeta": {
|
|
56
|
+
"@typescript/native-preview": {
|
|
57
|
+
"optional": true
|
|
58
|
+
}
|
|
51
59
|
},
|
|
52
60
|
"sideEffects": false,
|
|
53
61
|
"publishConfig": {
|