@bleedingdev/modern-js-server-utils 3.2.0-ultramodern.120 → 3.2.0-ultramodern.121

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,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
- const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs)=>{
61
- const output = await runTsgo([
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: external_path_default().dirname(tsconfigPath)
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(appDirectory, sourceDirs, config.files);
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
- const resolvedConfigPath = external_path_default().join(appDirectory, `.tsgo.${process.pid}.resolved.json`);
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 = (appDirectory, sourceDirs, files = [])=>{
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(appDirectory, fileName).split(external_path_default().sep).join(external_path_default().posix.sep);
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
- getTsgoBinPath(),
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 = ()=>external_path_default().join(external_path_default().dirname(require.resolve("@typescript/native-preview/package.json")), 'bin/tsgo.js');
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
- return findExistingSource(`${sourceBase}.ts`) || findExistingSource(`${sourceBase}.tsx`) || findExistingSource(`${sourceBase}.js`) || findExistingSource(`${sourceBase}.jsx`);
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
- let changed = false;
142
- const rewritten = content.replace(importSpecifierRE, (match, prefix, specifier, suffix)=>{
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 { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs);
175
- const result = await runTsgo([
176
- '-p',
177
- resolvedConfigPath
178
- ], {
179
- cwd: appDirectory,
180
- reject: false
181
- });
182
- await utils_namespaceObject.fs.remove(resolvedConfigPath);
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
- const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs)=>{
19
- const output = await runTsgo([
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: path.dirname(tsconfigPath)
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(appDirectory, sourceDirs, config.files);
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
- const resolvedConfigPath = path.join(appDirectory, `.tsgo.${process.pid}.resolved.json`);
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 = (appDirectory, sourceDirs, files = [])=>{
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(appDirectory, fileName).split(path.sep).join(path.posix.sep);
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
- getTsgoBinPath(),
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 = ()=>path.join(path.dirname(require.resolve("@typescript/native-preview/package.json")), 'bin/tsgo.js');
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
- return findExistingSource(`${sourceBase}.ts`) || findExistingSource(`${sourceBase}.tsx`) || findExistingSource(`${sourceBase}.js`) || findExistingSource(`${sourceBase}.jsx`);
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
- let changed = false;
100
- const rewritten = content.replace(importSpecifierRE, (match, prefix, specifier, suffix)=>{
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 { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs);
133
- const result = await runTsgo([
134
- '-p',
135
- resolvedConfigPath
136
- ], {
137
- cwd: appDirectory,
138
- reject: false
139
- });
140
- await fs.remove(resolvedConfigPath);
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
- const importSpecifierRE = /((?:from\s*|import\s*\(\s*|require\s*\(\s*)['"])([^'"]+)(['"])/g;
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
- const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs)=>{
21
- const output = await runTsgo([
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: path.dirname(tsconfigPath)
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(appDirectory, sourceDirs, config.files);
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
- const resolvedConfigPath = path.join(appDirectory, `.tsgo.${process.pid}.resolved.json`);
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 = (appDirectory, sourceDirs, files = [])=>{
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(appDirectory, fileName).split(path.sep).join(path.posix.sep);
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
- getTsgoBinPath(),
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 = ()=>path.join(path.dirname(require.resolve("@typescript/native-preview/package.json")), 'bin/tsgo.js');
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
- return findExistingSource(`${sourceBase}.ts`) || findExistingSource(`${sourceBase}.tsx`) || findExistingSource(`${sourceBase}.js`) || findExistingSource(`${sourceBase}.jsx`);
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
- let changed = false;
102
- const rewritten = content.replace(importSpecifierRE, (match, prefix, specifier, suffix)=>{
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 { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs);
135
- const result = await runTsgo([
136
- '-p',
137
- resolvedConfigPath
138
- ], {
139
- cwd: appDirectory,
140
- reject: false
141
- });
142
- await fs.remove(resolvedConfigPath);
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.120",
20
+ "version": "3.2.0-ultramodern.121",
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.120"
43
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.2.0-ultramodern.121"
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
- "@scripts/rstest-config": "2.66.0",
50
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.2.0-ultramodern.120"
49
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.2.0-ultramodern.121",
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": {