@bleedingdev/modern-js-server-utils 3.9.0-ultramodern.18 → 3.9.0-ultramodern.19

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.
@@ -1,257 +0,0 @@
1
- import { fs, getAliasConfig, logger } from "@modern-js/utils";
2
- import { spawn } from "child_process";
3
- import path from "path";
4
- import { assertNoNativeModuleOutputCollision, rewriteImportSpecifiers } from "./importRewriter.mjs";
5
- import { createTsconfigPathsMatcher, getNotAliasedPath } from "./tsconfigPathsPlugin.mjs";
6
- const copyFiles = async (from, to, appDirectory)=>{
7
- if (await fs.pathExists(from)) {
8
- const relativePath = path.relative(appDirectory, from);
9
- const targetDir = path.join(to, relativePath);
10
- await fs.copy(from, targetDir, {
11
- filter: (src)=>!/\.(?:[cm]?ts|tsx|jsx?)$/u.test(src) && !src.endsWith('tsconfig.json')
12
- });
13
- }
14
- };
15
- let resolvedConfigCount = 0;
16
- const createResolvedTsgoConfig = async (appDirectory, tsconfigPath, distDir, sourceDirs, moduleType, tsgoBinPath, excludeFiles = [])=>{
17
- const tsconfigDir = path.dirname(tsconfigPath);
18
- const output = await runTsgo(tsgoBinPath, [
19
- '--showConfig',
20
- '-p',
21
- tsconfigPath
22
- ], {
23
- cwd: tsconfigDir
24
- });
25
- const config = JSON.parse(output.stdout);
26
- config.compilerOptions ??= {};
27
- config.compilerOptions.rootDir = appDirectory;
28
- config.compilerOptions.outDir = distDir;
29
- config.compilerOptions.composite = false;
30
- config.compilerOptions.declarationMap = false;
31
- config.compilerOptions.emitDeclarationOnly = false;
32
- config.compilerOptions.incremental = false;
33
- config.compilerOptions.noEmit = false;
34
- if (void 0 === config.compilerOptions.jsx || 'preserve' === config.compilerOptions.jsx) config.compilerOptions.jsx = 'react-jsx';
35
- delete config.compilerOptions.tsBuildInfoFile;
36
- if (true === config.compilerOptions.allowImportingTsExtensions) config.compilerOptions.rewriteRelativeImportExtensions = true;
37
- config.files = filterSourceFiles(tsconfigDir, sourceDirs, config.files, excludeFiles);
38
- delete config.include;
39
- delete config.references;
40
- delete config.compilerOptions.baseUrl;
41
- if ([
42
- 'node',
43
- 'node10'
44
- ].includes(String(config.compilerOptions.moduleResolution).toLowerCase())) delete config.compilerOptions.moduleResolution;
45
- if ('module' !== moduleType) {
46
- if ([
47
- 'preserve',
48
- 'esnext',
49
- 'es2015',
50
- 'es2020',
51
- 'es2022',
52
- 'es6'
53
- ].includes(String(config.compilerOptions.module).toLowerCase())) {
54
- config.compilerOptions.module = 'commonjs';
55
- delete config.compilerOptions.moduleResolution;
56
- }
57
- config.compilerOptions.verbatimModuleSyntax = false;
58
- }
59
- const resolvedConfigPath = path.join(tsconfigDir, `.tsgo.${process.pid}.${resolvedConfigCount++}.resolved.json`);
60
- await fs.writeFile(resolvedConfigPath, JSON.stringify(config, null, 2));
61
- return {
62
- config,
63
- resolvedConfigPath
64
- };
65
- };
66
- const filterSourceFiles = (tsconfigDir, sourceDirs, files = [], excludeFiles = [])=>{
67
- const sourcePosixPaths = sourceDirs.map((sourceDir)=>sourceDir.split(path.sep).join(path.posix.sep));
68
- const excludedPaths = new Set(excludeFiles.map((file)=>path.normalize(file).split(path.sep).join(path.posix.sep)));
69
- return files.filter((fileName)=>{
70
- const absoluteFileName = path.resolve(tsconfigDir, fileName).split(path.sep).join(path.posix.sep);
71
- if (excludedPaths.has(absoluteFileName)) return false;
72
- return fileName.endsWith('.d.ts') || sourcePosixPaths.some((sourceDir)=>absoluteFileName.includes(sourceDir));
73
- });
74
- };
75
- const runTsgo = (tsgoBinPath, args, options)=>new Promise((resolve, reject)=>{
76
- const child = spawn(process.execPath, [
77
- tsgoBinPath,
78
- ...args
79
- ], {
80
- cwd: options.cwd,
81
- stdio: [
82
- 'ignore',
83
- 'pipe',
84
- 'pipe'
85
- ]
86
- });
87
- let stdout = '';
88
- let stderr = '';
89
- child.stdout.on('data', (data)=>{
90
- stdout += data;
91
- });
92
- child.stderr.on('data', (data)=>{
93
- stderr += data;
94
- });
95
- child.on('error', reject);
96
- child.on('close', (code)=>{
97
- const result = {
98
- stdout,
99
- stderr,
100
- code: code ?? 1
101
- };
102
- if (false !== options.reject && 0 !== result.code) return void reject(new Error(stderr || stdout || `tsgo exited with ${result.code}`));
103
- resolve(result);
104
- });
105
- });
106
- const getTsgoBinEntry = (pkg)=>{
107
- if ('string' == typeof pkg.bin) return pkg.bin;
108
- return pkg.bin?.tsc ?? pkg.bin?.tsgo;
109
- };
110
- const resolveTsgoBinPath = (pkgPath)=>{
111
- const pkgDir = path.dirname(pkgPath);
112
- const pkg = require(pkgPath);
113
- const declaredBinEntry = getTsgoBinEntry(pkg);
114
- const candidates = [
115
- declaredBinEntry ? path.resolve(pkgDir, declaredBinEntry) : void 0,
116
- path.join(pkgDir, 'bin/tsgo.js')
117
- ].filter((candidate)=>Boolean(candidate));
118
- return candidates.find((candidate)=>fs.existsSync(candidate)) ?? candidates[0];
119
- };
120
- const getTsgoBinPath = (appDirectory, resolvePaths = [
121
- appDirectory,
122
- __dirname
123
- ])=>{
124
- try {
125
- let pkgPath;
126
- try {
127
- pkgPath = require.resolve("@typescript/native/package.json", {
128
- paths: resolvePaths
129
- });
130
- } catch {
131
- pkgPath = require.resolve("@typescript/native-preview/package.json", {
132
- paths: resolvePaths
133
- });
134
- }
135
- return resolveTsgoBinPath(pkgPath);
136
- } catch {
137
- throw new Error('tsgo could not be found! Please install "@typescript/native" (or legacy "@typescript/native-preview") in your project to compile BFF/server code.');
138
- }
139
- };
140
- const OUTPUT_SOURCE_EXTENSIONS = {
141
- '.js': [
142
- '.ts',
143
- '.tsx',
144
- '.js',
145
- '.jsx'
146
- ],
147
- '.mjs': [
148
- '.mts',
149
- '.mjs'
150
- ],
151
- '.cjs': [
152
- '.cts',
153
- '.cjs'
154
- ],
155
- '.d.ts': [
156
- '.ts',
157
- '.tsx',
158
- '.js',
159
- '.jsx'
160
- ],
161
- '.d.mts': [
162
- '.mts',
163
- '.mjs'
164
- ],
165
- '.d.cts': [
166
- '.cts',
167
- '.cjs'
168
- ]
169
- };
170
- const getSourceFileForOutput = (appDirectory, distDir, outputFile)=>{
171
- const relativeOutput = path.relative(distDir, outputFile);
172
- const parsed = path.parse(relativeOutput);
173
- const isDeclaration = parsed.name.endsWith('.d');
174
- const outputExtension = isDeclaration ? `.d${parsed.ext}` : parsed.ext;
175
- const sourceName = isDeclaration ? parsed.name.slice(0, -2) : parsed.name;
176
- const sourceBase = path.join(appDirectory, parsed.dir, sourceName);
177
- const extensions = OUTPUT_SOURCE_EXTENSIONS[outputExtension] ?? OUTPUT_SOURCE_EXTENSIONS['.js'];
178
- for (const extension of extensions){
179
- const candidate = `${sourceBase}${extension}`;
180
- if (fs.existsSync(candidate)) return candidate;
181
- }
182
- };
183
- const sourceMappingUrlRE = /^\/\/[#@] sourceMappingURL=.*$/gm;
184
- const dropStaleSourceMap = async (outputFile, content)=>{
185
- const mapFile = `${outputFile}.map`;
186
- if (await fs.pathExists(mapFile)) await fs.remove(mapFile);
187
- return content.replace(sourceMappingUrlRE, '');
188
- };
189
- const rewriteOutputSpecifiers = async (appDirectory, distDir, baseUrl, paths, moduleType)=>{
190
- if (!await fs.pathExists(distDir)) return;
191
- const matcher = createTsconfigPathsMatcher(baseUrl, paths);
192
- if (!matcher) return;
193
- const files = await collectOutputFiles(distDir);
194
- await Promise.all(files.map(async (file)=>{
195
- const sourceFile = getSourceFileForOutput(appDirectory, distDir, file);
196
- if (!sourceFile) return;
197
- assertNoNativeModuleOutputCollision(sourceFile, fs.existsSync);
198
- const content = await fs.readFile(file, 'utf8');
199
- const { content: rewritten, changed } = rewriteImportSpecifiers(content, (specifier)=>getNotAliasedPath(sourceFile, matcher, specifier, moduleType));
200
- if (changed) await fs.writeFile(file, await dropStaleSourceMap(file, rewritten));
201
- }));
202
- };
203
- const collectOutputFiles = async (dir)=>{
204
- const entries = await fs.readdir(dir, {
205
- withFileTypes: true
206
- });
207
- const files = await Promise.all(entries.map(async (entry)=>{
208
- const fullPath = path.join(dir, entry.name);
209
- if (entry.isDirectory()) return collectOutputFiles(fullPath);
210
- return /\.(?:c|m)?js$|\.d\.(?:c|m)?ts$/.test(entry.name) ? [
211
- fullPath
212
- ] : [];
213
- }));
214
- return files.flat();
215
- };
216
- const compileByTs = async (appDirectory, config, compileOptions)=>{
217
- logger.info("Running tsgo compile...");
218
- const { sourceDirs, distDir, tsconfigPath } = compileOptions;
219
- if (!tsconfigPath) return;
220
- const { alias } = config;
221
- const aliasOption = getAliasConfig(alias, {
222
- appDirectory,
223
- tsconfigPath
224
- });
225
- const { paths = {}, absoluteBaseUrl = './' } = aliasOption;
226
- const tsgoBinPath = getTsgoBinPath(appDirectory);
227
- const { config: tsgoConfig, resolvedConfigPath } = await createResolvedTsgoConfig(appDirectory, tsconfigPath, distDir, sourceDirs, compileOptions.moduleType, tsgoBinPath, compileOptions.excludeFiles);
228
- let result;
229
- try {
230
- result = await runTsgo(tsgoBinPath, [
231
- '-p',
232
- resolvedConfigPath
233
- ], {
234
- cwd: appDirectory,
235
- reject: false
236
- });
237
- } finally{
238
- await fs.remove(resolvedConfigPath);
239
- }
240
- if (result.stderr) logger.error(result.stderr);
241
- if (result.stdout) logger.info(result.stdout);
242
- await rewriteOutputSpecifiers(appDirectory, distDir, absoluteBaseUrl, paths, compileOptions.moduleType);
243
- if (0 !== result.code) {
244
- const noEmitOnError = tsgoConfig.compilerOptions?.noEmitOnError;
245
- if (void 0 === noEmitOnError || true === noEmitOnError) if (compileOptions.throwErrorInsteadOfExit) {
246
- logger.error('TS-Go compilation failed');
247
- throw new Error([
248
- `TS-Go compilation failed with exit code ${result.code}.`,
249
- result.stderr.trim() || result.stdout.trim()
250
- ].filter(Boolean).join('\n'));
251
- } else process.exit(1);
252
- }
253
- for (const source of sourceDirs)await copyFiles(source, distDir, appDirectory);
254
- await rewriteOutputSpecifiers(appDirectory, distDir, absoluteBaseUrl, paths, compileOptions.moduleType);
255
- logger.info("TS-Go compile succeed");
256
- };
257
- export { compileByTs, createResolvedTsgoConfig, getTsgoBinPath, rewriteOutputSpecifiers };
@@ -1,143 +0,0 @@
1
- import { findMatchedSourcePath, findSourceEntry } from "@modern-js/utils";
2
- import { createMatchPath } from "@modern-js/utils/tsconfig-paths";
3
- import path from "path";
4
- const windowsAbsolutePathRE = /^[A-Za-z]:[\\/]/u;
5
- const isAbsolutePath = (input)=>path.isAbsolute(input) || path.win32.isAbsolute(input);
6
- const pathApiFor = (...inputs)=>inputs.some((input)=>windowsAbsolutePathRE.test(input)) ? path.win32 : path;
7
- const toImportSpecifier = (sourceFile, resolvedPath)=>{
8
- const pathApi = pathApiFor(sourceFile, resolvedPath);
9
- const relativePath = pathApi.relative(pathApi.dirname(sourceFile), resolvedPath).split(pathApi.sep).join(path.posix.sep);
10
- return '.' === relativePath[0] ? relativePath : `./${relativePath}`;
11
- };
12
- const SOURCE_TO_OUTPUT_EXTENSION = new Map([
13
- [
14
- '.ts',
15
- '.js'
16
- ],
17
- [
18
- '.tsx',
19
- '.js'
20
- ],
21
- [
22
- '.js',
23
- '.js'
24
- ],
25
- [
26
- '.jsx',
27
- '.js'
28
- ],
29
- [
30
- '.mts',
31
- '.mjs'
32
- ],
33
- [
34
- '.mjs',
35
- '.mjs'
36
- ],
37
- [
38
- '.cts',
39
- '.cjs'
40
- ],
41
- [
42
- '.cjs',
43
- '.cjs'
44
- ]
45
- ]);
46
- const toEsmOutputPath = (resolvedPath)=>{
47
- const sourcePath = (findSourceEntry(resolvedPath) || resolvedPath).replace(/\\/g, '/');
48
- const ext = path.extname(sourcePath);
49
- if (!ext) return `${sourcePath}.js`;
50
- const outputExtension = SOURCE_TO_OUTPUT_EXTENSION.get(ext);
51
- if (!outputExtension) return sourcePath;
52
- return `${sourcePath.slice(0, -ext.length)}${outputExtension}`;
53
- };
54
- const resolveRelativeEsmSpecifier = (sourceFile, text)=>{
55
- if (!text.startsWith('./') && !text.startsWith('../')) return;
56
- const pathApi = pathApiFor(sourceFile);
57
- return pathApi.resolve(pathApi.dirname(sourceFile), text);
58
- };
59
- const isRegExpKey = (str)=>str.startsWith('^') || str.endsWith('$');
60
- const resolveAliasPath = (baseUrl, filePath)=>{
61
- if (filePath.startsWith('.') || filePath.startsWith('..')) return path.resolve(baseUrl, filePath);
62
- return filePath;
63
- };
64
- const createAliasMatcher = (baseUrl, alias)=>{
65
- const aliasPairs = Object.keys(alias).reduce((o, key)=>{
66
- if (isRegExpKey(key)) {
67
- const regexp = new RegExp(key);
68
- const aliasPath = resolveAliasPath(baseUrl, alias[key]);
69
- o.push([
70
- regexp,
71
- aliasPath
72
- ]);
73
- } else {
74
- const aliasPath = resolveAliasPath(baseUrl, alias[key]);
75
- o.push([
76
- key,
77
- aliasPath
78
- ]);
79
- }
80
- return o;
81
- }, []);
82
- const cacheMap = new Map();
83
- return (requestedModule)=>{
84
- if (cacheMap.has(requestedModule)) return cacheMap.get(requestedModule);
85
- for (const [key, value] of aliasPairs){
86
- if (key instanceof RegExp) {
87
- if (key.test(requestedModule)) {
88
- cacheMap.set(requestedModule, value);
89
- return value;
90
- }
91
- }
92
- if (requestedModule === key) {
93
- cacheMap.set(requestedModule, value);
94
- return value;
95
- }
96
- }
97
- };
98
- };
99
- const createTsconfigPathsMatcher = (baseUrl, paths)=>{
100
- const tsPaths = {};
101
- const alias = {};
102
- Object.keys(paths).forEach((key)=>{
103
- if (Array.isArray(paths[key])) tsPaths[key] = paths[key];
104
- else alias[key] = paths[key];
105
- });
106
- const matchAliasPath = createAliasMatcher(baseUrl, alias);
107
- const matchTsPath = createMatchPath(baseUrl, tsPaths, [
108
- 'main'
109
- ]);
110
- return (requestedModule, readJSONSync, fileExists, extensions)=>{
111
- const result = matchTsPath(requestedModule, readJSONSync, fileExists, extensions);
112
- if (result) return result;
113
- return matchAliasPath(requestedModule);
114
- };
115
- };
116
- function getNotAliasedPath(sourceFile, matcher, text, moduleType) {
117
- let result = findMatchedSourcePath(matcher, text);
118
- if (!result && 'module' === moduleType) result = resolveRelativeEsmSpecifier(sourceFile, text);
119
- if (!result) return;
120
- if (!isAbsolutePath(result)) {
121
- if (!result.startsWith('.') && !result.startsWith('..')) try {
122
- const packagePath = require.resolve(result, {
123
- paths: [
124
- process.cwd(),
125
- ...module.paths
126
- ]
127
- });
128
- if (packagePath) return result;
129
- } catch {}
130
- try {
131
- const packagePath = require.resolve(text, {
132
- paths: [
133
- process.cwd(),
134
- ...module.paths
135
- ]
136
- });
137
- if (packagePath) return text;
138
- } catch {}
139
- }
140
- if ('module' === moduleType || /\.[cm]ts$/iu.test(result)) result = toEsmOutputPath(result);
141
- return toImportSpecifier(sourceFile, result) || './';
142
- }
143
- export { createTsconfigPathsMatcher, getNotAliasedPath };
@@ -1,135 +0,0 @@
1
- import "node:module";
2
- import { parseSync } from "@swc/core";
3
- const assertNoNativeModuleOutputCollision = (sourceFile, fileExists)=>{
4
- const rawModuleFile = sourceFile.endsWith('.mts') ? `${sourceFile.slice(0, -4)}.mjs` : sourceFile.endsWith('.cts') ? `${sourceFile.slice(0, -4)}.cjs` : void 0;
5
- if (rawModuleFile && fileExists(rawModuleFile)) throw new Error(`Native module sources collide: "${sourceFile}" and "${rawModuleFile}" publish the same output.`);
6
- };
7
- const isObjectRecord = (value)=>'object' == typeof value && null !== value;
8
- const isAstNode = (value)=>isObjectRecord(value) && 'string' == typeof value.type;
9
- const isStringLiteral = (value)=>isAstNode(value) && 'StringLiteral' === value.type && 'string' == typeof value.value && 'object' == typeof value.span && null !== value.span && 'number' == typeof value.span.start && 'number' == typeof value.span.end;
10
- const getCallSpecifier = (node)=>{
11
- if ('CallExpression' !== node.type || !Array.isArray(node.arguments)) return;
12
- const callee = node.callee;
13
- const isDynamicImport = isAstNode(callee) && 'Import' === callee.type;
14
- const isCommonJsRequire = isAstNode(callee) && 'Identifier' === callee.type && 'require' === callee.value;
15
- if (!isDynamicImport && !isCommonJsRequire) return;
16
- const firstArgument = node.arguments[0];
17
- if (!isObjectRecord(firstArgument)) return;
18
- return isStringLiteral(firstArgument.expression) ? firstArgument.expression : void 0;
19
- };
20
- const collectSpecifierLiterals = (content)=>{
21
- const parserOptions = {
22
- decorators: true,
23
- syntax: "typescript",
24
- target: 'esnext'
25
- };
26
- let program;
27
- try {
28
- program = parseSync(content, parserOptions);
29
- } catch (typescriptError) {
30
- try {
31
- program = parseSync(content, {
32
- ...parserOptions,
33
- tsx: true
34
- });
35
- } catch {
36
- throw typescriptError;
37
- }
38
- }
39
- const literals = [];
40
- const seenSpans = new Set();
41
- const add = (value)=>{
42
- if (!isStringLiteral(value)) return;
43
- const spanKey = `${value.span.start}:${value.span.end}`;
44
- if (!seenSpans.has(spanKey)) {
45
- seenSpans.add(spanKey);
46
- literals.push(value);
47
- }
48
- };
49
- const visit = (value)=>{
50
- if (Array.isArray(value)) return void value.forEach(visit);
51
- if (!isObjectRecord(value)) return;
52
- if (isAstNode(value)) switch(value.type){
53
- case 'ImportDeclaration':
54
- case 'ExportAllDeclaration':
55
- case 'ExportNamedDeclaration':
56
- add(value.source);
57
- break;
58
- case 'TsImportType':
59
- add(value.argument);
60
- break;
61
- case 'TsExternalModuleReference':
62
- add(value.expression);
63
- break;
64
- case 'CallExpression':
65
- add(getCallSpecifier(value));
66
- break;
67
- }
68
- for (const [key, child] of Object.entries(value))if ('span' !== key) visit(child);
69
- };
70
- visit(program);
71
- return literals.sort((left, right)=>left.span.start - right.span.start);
72
- };
73
- const mapUtf8ByteOffsets = (content, byteOffsets)=>{
74
- const pending = new Set(byteOffsets);
75
- const result = new Map();
76
- let byteOffset = 0;
77
- let stringOffset = 0;
78
- while(stringOffset <= content.length && pending.size > 0){
79
- if (pending.delete(byteOffset)) result.set(byteOffset, stringOffset);
80
- if (stringOffset === content.length) break;
81
- const codePoint = content.codePointAt(stringOffset);
82
- if (void 0 === codePoint) break;
83
- const character = String.fromCodePoint(codePoint);
84
- byteOffset += Buffer.byteLength(character);
85
- stringOffset += character.length;
86
- }
87
- if (pending.size > 0) throw new Error('SWC returned an import specifier span outside its source');
88
- return result;
89
- };
90
- const scanSpecifiers = (content)=>{
91
- const literals = collectSpecifierLiterals(content);
92
- const byteOffsets = literals.flatMap((literal)=>[
93
- literal.span.start,
94
- literal.span.end - 2
95
- ]);
96
- const stringOffsets = mapUtf8ByteOffsets(content, byteOffsets);
97
- return literals.map((literal)=>{
98
- const start = stringOffsets.get(literal.span.start);
99
- const end = stringOffsets.get(literal.span.end - 2);
100
- if (void 0 === start || void 0 === end) throw new Error('Could not locate an SWC import specifier in its source');
101
- return {
102
- start,
103
- end,
104
- value: content.slice(start, end)
105
- };
106
- });
107
- };
108
- const rewriteImportSpecifiers = (content, rewrite)=>{
109
- const specifiers = scanSpecifiers(content);
110
- if (0 === specifiers.length) return {
111
- content,
112
- changed: false
113
- };
114
- let result = '';
115
- let cursor = 0;
116
- let changed = false;
117
- for (const specifier of specifiers){
118
- if (specifier.value.includes('\\')) continue;
119
- const next = rewrite(specifier.value);
120
- if (void 0 !== next && next !== specifier.value) {
121
- changed = true;
122
- result += content.slice(cursor, specifier.start) + next;
123
- cursor = specifier.end;
124
- }
125
- }
126
- if (!changed) return {
127
- content,
128
- changed: false
129
- };
130
- return {
131
- content: result + content.slice(cursor),
132
- changed: true
133
- };
134
- };
135
- export { assertNoNativeModuleOutputCollision, rewriteImportSpecifiers };