@esportsplus/typescript 0.13.0 → 0.14.1
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/bin/tsc +1 -1
- package/build/cli/tsc.d.ts +1 -0
- package/build/cli/tsc.js +167 -0
- package/build/transformer/index.d.ts +2 -7
- package/build/transformer/index.js +1 -49
- package/build/transformer/types.d.ts +1 -12
- package/package.json +5 -7
- package/src/cli/tsc.ts +258 -0
- package/src/transformer/index.ts +3 -84
- package/src/transformer/types.ts +1 -24
- package/bin/tsc-alias +0 -3
package/bin/tsc
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/build/cli/tsc.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import { pathToFileURL } from 'url';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import ts from 'typescript';
|
|
7
|
+
let require = createRequire(import.meta.url), skipFlags = ['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v'];
|
|
8
|
+
async function build(tsconfig, plugins) {
|
|
9
|
+
let root = path.dirname(path.resolve(tsconfig)), { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
10
|
+
if (error) {
|
|
11
|
+
console.error(ts.flattenDiagnosticMessageText(error.messageText, '\n'));
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
let parsed = ts.parseJsonConfigFileContent(config, ts.sys, root);
|
|
15
|
+
if (parsed.errors.length > 0) {
|
|
16
|
+
for (let i = 0, n = parsed.errors.length; i < n; i++) {
|
|
17
|
+
console.error(ts.flattenDiagnosticMessageText(parsed.errors[i].messageText, '\n'));
|
|
18
|
+
}
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
await loadTransformers(plugins, root).then((transformers) => {
|
|
22
|
+
let program = ts.createProgram(parsed.fileNames, parsed.options), result = program.emit(undefined, undefined, undefined, false, {
|
|
23
|
+
after: transformers.after.map(f => f(program)),
|
|
24
|
+
afterDeclarations: transformers.afterDeclarations.map(f => f(program)),
|
|
25
|
+
before: transformers.before.map(f => f(program))
|
|
26
|
+
});
|
|
27
|
+
let diagnostics = ts.getPreEmitDiagnostics(program).concat(result.diagnostics);
|
|
28
|
+
if (diagnostics.length > 0) {
|
|
29
|
+
console.error(ts.formatDiagnosticsWithColorAndContext(diagnostics, {
|
|
30
|
+
getCanonicalFileName: (fileName) => fileName,
|
|
31
|
+
getCurrentDirectory: () => root,
|
|
32
|
+
getNewLine: () => '\n'
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
if (result.emitSkipped) {
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
if (shouldRunTscAlias(process.argv.slice(2))) {
|
|
39
|
+
return runTscAlias().then((code) => {
|
|
40
|
+
if (code !== 0) {
|
|
41
|
+
process.exit(code);
|
|
42
|
+
}
|
|
43
|
+
process.exit(0);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
process.exit(0);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function findPackageJson(moduleName, root) {
|
|
50
|
+
let nodeModulesPath = path.join(root, 'node_modules', moduleName.startsWith('@') ? moduleName.split('/').slice(0, 2).join('/') : moduleName.split('/')[0], 'package.json');
|
|
51
|
+
if (fs.existsSync(nodeModulesPath)) {
|
|
52
|
+
return nodeModulesPath;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function findTsconfig(args) {
|
|
57
|
+
let projectIndex = args.indexOf('-p');
|
|
58
|
+
if (projectIndex === -1) {
|
|
59
|
+
projectIndex = args.indexOf('--project');
|
|
60
|
+
}
|
|
61
|
+
if (projectIndex !== -1 && args[projectIndex + 1]) {
|
|
62
|
+
return args[projectIndex + 1];
|
|
63
|
+
}
|
|
64
|
+
return ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');
|
|
65
|
+
}
|
|
66
|
+
function getPlugins(tsconfig) {
|
|
67
|
+
let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
68
|
+
if (error) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return config?.compilerOptions?.plugins?.filter((p) => typeof p === 'object' && p !== null && 'transform' in p) ?? [];
|
|
72
|
+
}
|
|
73
|
+
async function loadTransformers(plugins, root) {
|
|
74
|
+
let after = [], afterDeclarations = [], before = [], promises = [];
|
|
75
|
+
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
76
|
+
let plugin = plugins[i];
|
|
77
|
+
promises.push(import(resolvePlugin(plugin.transform, root)).then((module) => {
|
|
78
|
+
let factory = module.default ?? module.createTransformer ?? module;
|
|
79
|
+
if (typeof factory !== 'function') {
|
|
80
|
+
console.error(`Plugin ${plugin.transform}: no transformer factory found`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (plugin.afterDeclarations) {
|
|
84
|
+
afterDeclarations.push(factory);
|
|
85
|
+
}
|
|
86
|
+
else if (plugin.after) {
|
|
87
|
+
after.push(factory);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
before.push(factory);
|
|
91
|
+
}
|
|
92
|
+
}));
|
|
93
|
+
}
|
|
94
|
+
return Promise.all(promises).then(() => ({ after, afterDeclarations, before }));
|
|
95
|
+
}
|
|
96
|
+
function main() {
|
|
97
|
+
let args = process.argv.slice(2), tsconfig = findTsconfig(args);
|
|
98
|
+
if (!tsconfig) {
|
|
99
|
+
passthrough();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let plugins = getPlugins(tsconfig);
|
|
103
|
+
if (plugins.length === 0) {
|
|
104
|
+
passthrough();
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
console.log(`Found ${plugins.length} transformer plugin(s), using programmatic build...`);
|
|
108
|
+
build(tsconfig, plugins).catch((err) => {
|
|
109
|
+
console.error(err);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function passthrough() {
|
|
114
|
+
let args = process.argv.slice(2), child = spawn(process.execPath, [require.resolve('typescript/lib/tsc.js'), ...args], { stdio: 'inherit' });
|
|
115
|
+
child.on('exit', (code) => {
|
|
116
|
+
if (code === 0 && shouldRunTscAlias(args)) {
|
|
117
|
+
runTscAlias().then((aliasCode) => process.exit(aliasCode ?? 0));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
process.exit(code ?? 0);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function resolveExport(exportValue) {
|
|
124
|
+
if (typeof exportValue === 'string') {
|
|
125
|
+
return exportValue;
|
|
126
|
+
}
|
|
127
|
+
if (exportValue && typeof exportValue === 'object') {
|
|
128
|
+
return exportValue.import ?? exportValue.default ?? null;
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
function resolvePlugin(modulePath, root) {
|
|
133
|
+
if (modulePath.startsWith('.')) {
|
|
134
|
+
return pathToFileURL(path.resolve(root, modulePath)).href;
|
|
135
|
+
}
|
|
136
|
+
let packageJsonPath = findPackageJson(modulePath, root);
|
|
137
|
+
if (!packageJsonPath) {
|
|
138
|
+
throw new Error(`tsc: cannot find package '${modulePath}' in ${root}`);
|
|
139
|
+
}
|
|
140
|
+
let packageDir = path.dirname(packageJsonPath), packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')), parts = modulePath.split('/'), subpath = './' + (modulePath.startsWith('@') ? parts.slice(2) : parts.slice(1)).join('/');
|
|
141
|
+
if (packageJson.exports) {
|
|
142
|
+
let exportEntry = subpath === './' ? packageJson.exports['.'] : packageJson.exports[subpath];
|
|
143
|
+
if (exportEntry) {
|
|
144
|
+
let resolved = resolveExport(exportEntry);
|
|
145
|
+
if (resolved) {
|
|
146
|
+
return pathToFileURL(path.resolve(packageDir, resolved)).href;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
throw new Error(`tsc: package subpath '${subpath}' is not exported by '${modulePath}'`);
|
|
150
|
+
}
|
|
151
|
+
return pathToFileURL(path.resolve(packageDir, packageJson.main ?? 'index.js')).href;
|
|
152
|
+
}
|
|
153
|
+
function runTscAlias() {
|
|
154
|
+
return new Promise((resolve) => {
|
|
155
|
+
let child = spawn(process.execPath, [require.resolve('tsc-alias/dist/bin/index.js'), ...process.argv.slice(2)], { stdio: 'inherit' });
|
|
156
|
+
child.on('exit', (code) => resolve(code ?? 0));
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function shouldRunTscAlias(args) {
|
|
160
|
+
for (let i = 0, n = skipFlags.length; i < n; i++) {
|
|
161
|
+
if (args.includes(skipFlags[i])) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
main();
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { ImportModification, NodeMatch, QuickCheckPattern, Replacement, VisitorCallback, VisitorPredicate } from './types.js';
|
|
1
|
+
import type { QuickCheckPattern, Replacement } from './types.js';
|
|
3
2
|
import program from './program.js';
|
|
4
3
|
declare const addImport: (code: string, module: string, specifiers: string[]) => string;
|
|
5
4
|
declare const applyReplacements: (code: string, replacements: Replacement[]) => string;
|
|
6
5
|
declare const applyReplacementsReverse: (code: string, replacements: Replacement[]) => string;
|
|
7
|
-
declare const collectNodes: <T>(sourceFile: ts.SourceFile, predicate: (node: ts.Node) => T | null) => NodeMatch<T>[];
|
|
8
6
|
declare const mightNeedTransform: (code: string, check: QuickCheckPattern) => boolean;
|
|
9
7
|
declare const uid: (prefix: string, updateUUID?: boolean) => string;
|
|
10
|
-
|
|
11
|
-
declare const visitAst: <T>(sourceFile: ts.SourceFile, callback: VisitorCallback<T>, state: T, predicate?: VisitorPredicate) => T;
|
|
12
|
-
declare const visitAstWithDepth: <T>(sourceFile: ts.SourceFile, callback: (node: ts.Node, depth: number, state: T) => void, state: T, depthTrigger: (node: ts.Node) => boolean) => T;
|
|
13
|
-
export { addImport, applyReplacements, applyReplacementsReverse, collectNodes, mightNeedTransform, program, uid, updateImports, visitAst, visitAstWithDepth };
|
|
8
|
+
export { addImport, applyReplacements, applyReplacementsReverse, mightNeedTransform, program, uid };
|
|
14
9
|
export type * from './types.js';
|
|
15
10
|
export * from './constants.js';
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { uuid } from '@esportsplus/utilities';
|
|
2
|
-
import ts from 'typescript';
|
|
3
2
|
import { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX } from './constants.js';
|
|
4
3
|
import program from './program.js';
|
|
5
4
|
let i = 0, uidSuffix = uuid().replace(UUID_DASH_REGEX, '');
|
|
@@ -93,23 +92,6 @@ const applyReplacementsReverse = (code, replacements) => {
|
|
|
93
92
|
}
|
|
94
93
|
return result;
|
|
95
94
|
};
|
|
96
|
-
const collectNodes = (sourceFile, predicate) => {
|
|
97
|
-
let matches = [];
|
|
98
|
-
function visit(node) {
|
|
99
|
-
let data = predicate(node);
|
|
100
|
-
if (data !== null) {
|
|
101
|
-
matches.push({
|
|
102
|
-
data,
|
|
103
|
-
end: node.end,
|
|
104
|
-
node,
|
|
105
|
-
start: node.getStart(sourceFile)
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
ts.forEachChild(node, visit);
|
|
109
|
-
}
|
|
110
|
-
visit(sourceFile);
|
|
111
|
-
return matches;
|
|
112
|
-
};
|
|
113
95
|
const mightNeedTransform = (code, check) => {
|
|
114
96
|
if (check.regex) {
|
|
115
97
|
return check.regex.test(code);
|
|
@@ -126,35 +108,5 @@ const mightNeedTransform = (code, check) => {
|
|
|
126
108
|
const uid = (prefix, updateUUID = false) => {
|
|
127
109
|
return prefix + '_' + (updateUUID ? uuid().replace(UUID_DASH_REGEX, '') : uidSuffix) + '_' + (i++).toString(36);
|
|
128
110
|
};
|
|
129
|
-
|
|
130
|
-
let { module, specifiers } = modification;
|
|
131
|
-
if (specifiers.size === 0) {
|
|
132
|
-
return code;
|
|
133
|
-
}
|
|
134
|
-
let escapedModule = module.replace(REGEX_ESCAPE_PATTERN, '\\$&'), importRegex = buildImportRegex(escapedModule);
|
|
135
|
-
return updateImportsWithRegex(code, specifiers, importRegex);
|
|
136
|
-
};
|
|
137
|
-
const visitAst = (sourceFile, callback, state, predicate) => {
|
|
138
|
-
function visit(node) {
|
|
139
|
-
if (!predicate || predicate(node)) {
|
|
140
|
-
callback(node, state);
|
|
141
|
-
}
|
|
142
|
-
ts.forEachChild(node, visit);
|
|
143
|
-
}
|
|
144
|
-
visit(sourceFile);
|
|
145
|
-
return state;
|
|
146
|
-
};
|
|
147
|
-
const visitAstWithDepth = (sourceFile, callback, state, depthTrigger) => {
|
|
148
|
-
let depthStack = [0];
|
|
149
|
-
function visit(node) {
|
|
150
|
-
let depth = depthStack[depthStack.length - 1], nextDepth = depthTrigger(node) ? depth + 1 : depth;
|
|
151
|
-
callback(node, depth, state);
|
|
152
|
-
depthStack.push(nextDepth);
|
|
153
|
-
ts.forEachChild(node, visit);
|
|
154
|
-
depthStack.pop();
|
|
155
|
-
}
|
|
156
|
-
visit(sourceFile);
|
|
157
|
-
return state;
|
|
158
|
-
};
|
|
159
|
-
export { addImport, applyReplacements, applyReplacementsReverse, collectNodes, mightNeedTransform, program, uid, updateImports, visitAst, visitAstWithDepth };
|
|
111
|
+
export { addImport, applyReplacements, applyReplacementsReverse, mightNeedTransform, program, uid };
|
|
160
112
|
export * from './constants.js';
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
type ImportModification = {
|
|
3
|
-
module: string;
|
|
4
|
-
specifiers: Set<string>;
|
|
5
|
-
};
|
|
6
|
-
type NodeMatch<T> = Range & {
|
|
7
|
-
data: T;
|
|
8
|
-
node: ts.Node;
|
|
9
|
-
};
|
|
10
1
|
type QuickCheckPattern = {
|
|
11
2
|
patterns?: string[];
|
|
12
3
|
regex?: RegExp;
|
|
@@ -18,6 +9,4 @@ type Range = {
|
|
|
18
9
|
type Replacement = Range & {
|
|
19
10
|
newText: string;
|
|
20
11
|
};
|
|
21
|
-
type
|
|
22
|
-
type VisitorPredicate = (node: ts.Node) => boolean;
|
|
23
|
-
export type { ImportModification, NodeMatch, QuickCheckPattern, Range, Replacement, VisitorCallback, VisitorPredicate };
|
|
12
|
+
export type { QuickCheckPattern, Range, Replacement };
|
package/package.json
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "ICJR",
|
|
3
3
|
"bin": {
|
|
4
|
-
"tsc": "./bin/tsc"
|
|
5
|
-
"tsc-alias": "./bin/tsc-alias"
|
|
4
|
+
"esportsplus-tsc": "./bin/tsc"
|
|
6
5
|
},
|
|
7
6
|
"dependencies": {
|
|
8
|
-
"@esportsplus/cli-passthrough": "^0.0.12",
|
|
9
7
|
"@esportsplus/utilities": "^0.27.2",
|
|
10
8
|
"@types/node": "^25.0.3",
|
|
11
9
|
"tsc-alias": "^1.8.16",
|
|
@@ -13,13 +11,13 @@
|
|
|
13
11
|
},
|
|
14
12
|
"exports": {
|
|
15
13
|
"./package.json": "./package.json",
|
|
16
|
-
"./tsconfig.browser.json": "./tsconfig.browser.json",
|
|
17
|
-
"./tsconfig.node.json": "./tsconfig.node.json",
|
|
18
|
-
"./tsconfig.package.json": "./tsconfig.package.json",
|
|
19
14
|
"./transformer": {
|
|
20
15
|
"types": "./build/transformer/index.d.ts",
|
|
21
16
|
"default": "./build/transformer/index.js"
|
|
22
17
|
},
|
|
18
|
+
"./tsconfig.browser.json": "./tsconfig.browser.json",
|
|
19
|
+
"./tsconfig.node.json": "./tsconfig.node.json",
|
|
20
|
+
"./tsconfig.package.json": "./tsconfig.package.json",
|
|
23
21
|
".": {
|
|
24
22
|
"types": "./build/index.d.ts",
|
|
25
23
|
"default": "./build/index.js"
|
|
@@ -34,7 +32,7 @@
|
|
|
34
32
|
},
|
|
35
33
|
"type": "module",
|
|
36
34
|
"types": "build/index.d.ts",
|
|
37
|
-
"version": "0.
|
|
35
|
+
"version": "0.14.1",
|
|
38
36
|
"scripts": {
|
|
39
37
|
"build": "tsc && tsc-alias",
|
|
40
38
|
"-": "-"
|
package/src/cli/tsc.ts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import { pathToFileURL } from 'url';
|
|
4
|
+
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import ts from 'typescript';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
type ExportValue = string | { default?: string; import?: string; types?: string } | null;
|
|
11
|
+
|
|
12
|
+
type PluginConfig = {
|
|
13
|
+
after?: boolean;
|
|
14
|
+
afterDeclarations?: boolean;
|
|
15
|
+
transform: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type TransformerCreator = (program: ts.Program) => ts.TransformerFactory<ts.SourceFile>;
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
let require = createRequire(import.meta.url),
|
|
22
|
+
skipFlags = ['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v'];
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
async function build(tsconfig: string, plugins: PluginConfig[]): Promise<void> {
|
|
26
|
+
let root = path.dirname(path.resolve(tsconfig)),
|
|
27
|
+
{ config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
28
|
+
|
|
29
|
+
if (error) {
|
|
30
|
+
console.error(ts.flattenDiagnosticMessageText(error.messageText, '\n'));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let parsed = ts.parseJsonConfigFileContent(config, ts.sys, root);
|
|
35
|
+
|
|
36
|
+
if (parsed.errors.length > 0) {
|
|
37
|
+
for (let i = 0, n = parsed.errors.length; i < n; i++) {
|
|
38
|
+
console.error(ts.flattenDiagnosticMessageText(parsed.errors[i].messageText, '\n'));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
await loadTransformers(plugins, root).then((transformers) => {
|
|
45
|
+
let program = ts.createProgram(parsed.fileNames, parsed.options),
|
|
46
|
+
result = program.emit(undefined, undefined, undefined, false, {
|
|
47
|
+
after: transformers.after.map(f => f(program)),
|
|
48
|
+
afterDeclarations: transformers.afterDeclarations.map(f => f(program)) as ts.TransformerFactory<ts.SourceFile | ts.Bundle>[],
|
|
49
|
+
before: transformers.before.map(f => f(program))
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
let diagnostics = ts.getPreEmitDiagnostics(program).concat(result.diagnostics);
|
|
53
|
+
|
|
54
|
+
if (diagnostics.length > 0) {
|
|
55
|
+
console.error(
|
|
56
|
+
ts.formatDiagnosticsWithColorAndContext(diagnostics, {
|
|
57
|
+
getCanonicalFileName: (fileName) => fileName,
|
|
58
|
+
getCurrentDirectory: () => root,
|
|
59
|
+
getNewLine: () => '\n'
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (result.emitSkipped) {
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (shouldRunTscAlias(process.argv.slice(2))) {
|
|
69
|
+
return runTscAlias().then((code) => {
|
|
70
|
+
if (code !== 0) {
|
|
71
|
+
process.exit(code);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
process.exit(0);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
process.exit(0);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function findPackageJson(moduleName: string, root: string): string | null {
|
|
83
|
+
let nodeModulesPath = path.join(root, 'node_modules', moduleName.startsWith('@') ? moduleName.split('/').slice(0, 2).join('/') : moduleName.split('/')[0], 'package.json');
|
|
84
|
+
|
|
85
|
+
if (fs.existsSync(nodeModulesPath)) {
|
|
86
|
+
return nodeModulesPath;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function findTsconfig(args: string[]): string | undefined {
|
|
93
|
+
let projectIndex = args.indexOf('-p');
|
|
94
|
+
|
|
95
|
+
if (projectIndex === -1) {
|
|
96
|
+
projectIndex = args.indexOf('--project');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (projectIndex !== -1 && args[projectIndex + 1]) {
|
|
100
|
+
return args[projectIndex + 1];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getPlugins(tsconfig: string): PluginConfig[] {
|
|
107
|
+
let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
108
|
+
|
|
109
|
+
if (error) {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return config?.compilerOptions?.plugins?.filter(
|
|
114
|
+
(p: unknown) => typeof p === 'object' && p !== null && 'transform' in p
|
|
115
|
+
) ?? [];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function loadTransformers(plugins: PluginConfig[], root: string): Promise<{
|
|
119
|
+
after: TransformerCreator[];
|
|
120
|
+
afterDeclarations: TransformerCreator[];
|
|
121
|
+
before: TransformerCreator[];
|
|
122
|
+
}> {
|
|
123
|
+
let after: TransformerCreator[] = [],
|
|
124
|
+
afterDeclarations: TransformerCreator[] = [],
|
|
125
|
+
before: TransformerCreator[] = [],
|
|
126
|
+
promises: Promise<void>[] = [];
|
|
127
|
+
|
|
128
|
+
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
129
|
+
let plugin = plugins[i];
|
|
130
|
+
|
|
131
|
+
promises.push(
|
|
132
|
+
import(resolvePlugin(plugin.transform, root)).then((module) => {
|
|
133
|
+
let factory = module.default ?? module.createTransformer ?? module;
|
|
134
|
+
|
|
135
|
+
if (typeof factory !== 'function') {
|
|
136
|
+
console.error(`Plugin ${plugin.transform}: no transformer factory found`);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (plugin.afterDeclarations) {
|
|
141
|
+
afterDeclarations.push(factory);
|
|
142
|
+
}
|
|
143
|
+
else if (plugin.after) {
|
|
144
|
+
after.push(factory);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
before.push(factory);
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return Promise.all(promises).then(() => ({ after, afterDeclarations, before }));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function main(): void {
|
|
157
|
+
let args = process.argv.slice(2),
|
|
158
|
+
tsconfig = findTsconfig(args);
|
|
159
|
+
|
|
160
|
+
if (!tsconfig) {
|
|
161
|
+
passthrough();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
let plugins = getPlugins(tsconfig);
|
|
166
|
+
|
|
167
|
+
if (plugins.length === 0) {
|
|
168
|
+
passthrough();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
console.log(`Found ${plugins.length} transformer plugin(s), using programmatic build...`);
|
|
173
|
+
|
|
174
|
+
build(tsconfig, plugins).catch((err) => {
|
|
175
|
+
console.error(err);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function passthrough(): void {
|
|
181
|
+
let args = process.argv.slice(2),
|
|
182
|
+
child = spawn(process.execPath, [require.resolve('typescript/lib/tsc.js'), ...args], { stdio: 'inherit' });
|
|
183
|
+
|
|
184
|
+
child.on('exit', (code) => {
|
|
185
|
+
if (code === 0 && shouldRunTscAlias(args)) {
|
|
186
|
+
runTscAlias().then((aliasCode) => process.exit(aliasCode ?? 0));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
process.exit(code ?? 0);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function resolveExport(exportValue: ExportValue): string | null {
|
|
195
|
+
if (typeof exportValue === 'string') {
|
|
196
|
+
return exportValue;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (exportValue && typeof exportValue === 'object') {
|
|
200
|
+
return exportValue.import ?? exportValue.default ?? null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function resolvePlugin(modulePath: string, root: string): string {
|
|
207
|
+
if (modulePath.startsWith('.')) {
|
|
208
|
+
return pathToFileURL(path.resolve(root, modulePath)).href;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let packageJsonPath = findPackageJson(modulePath, root);
|
|
212
|
+
|
|
213
|
+
if (!packageJsonPath) {
|
|
214
|
+
throw new Error(`tsc: cannot find package '${modulePath}' in ${root}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
let packageDir = path.dirname(packageJsonPath),
|
|
218
|
+
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')),
|
|
219
|
+
parts = modulePath.split('/'),
|
|
220
|
+
subpath = './' + (modulePath.startsWith('@') ? parts.slice(2) : parts.slice(1)).join('/');
|
|
221
|
+
|
|
222
|
+
if (packageJson.exports) {
|
|
223
|
+
let exportEntry = subpath === './' ? packageJson.exports['.'] : packageJson.exports[subpath];
|
|
224
|
+
|
|
225
|
+
if (exportEntry) {
|
|
226
|
+
let resolved = resolveExport(exportEntry);
|
|
227
|
+
|
|
228
|
+
if (resolved) {
|
|
229
|
+
return pathToFileURL(path.resolve(packageDir, resolved)).href;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
throw new Error(`tsc: package subpath '${subpath}' is not exported by '${modulePath}'`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return pathToFileURL(path.resolve(packageDir, packageJson.main ?? 'index.js')).href;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function runTscAlias(): Promise<number> {
|
|
240
|
+
return new Promise((resolve) => {
|
|
241
|
+
let child = spawn(process.execPath, [require.resolve('tsc-alias/dist/bin/index.js'), ...process.argv.slice(2)], { stdio: 'inherit' });
|
|
242
|
+
|
|
243
|
+
child.on('exit', (code) => resolve(code ?? 0));
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function shouldRunTscAlias(args: string[]): boolean {
|
|
248
|
+
for (let i = 0, n = skipFlags.length; i < n; i++) {
|
|
249
|
+
if (args.includes(skipFlags[i])) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
main();
|
package/src/transformer/index.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { uuid } from '@esportsplus/utilities';
|
|
2
|
-
import ts from 'typescript';
|
|
3
2
|
import { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX } from './constants.js';
|
|
4
|
-
import type {
|
|
3
|
+
import type { QuickCheckPattern, Replacement } from './types.js';
|
|
5
4
|
import program from './program';
|
|
6
5
|
|
|
7
6
|
|
|
@@ -146,29 +145,6 @@ const applyReplacementsReverse = (code: string, replacements: Replacement[]): st
|
|
|
146
145
|
return result;
|
|
147
146
|
};
|
|
148
147
|
|
|
149
|
-
const collectNodes = <T>(sourceFile: ts.SourceFile, predicate: (node: ts.Node) => T | null): NodeMatch<T>[] => {
|
|
150
|
-
let matches: NodeMatch<T>[] = [];
|
|
151
|
-
|
|
152
|
-
function visit(node: ts.Node): void {
|
|
153
|
-
let data = predicate(node);
|
|
154
|
-
|
|
155
|
-
if (data !== null) {
|
|
156
|
-
matches.push({
|
|
157
|
-
data,
|
|
158
|
-
end: node.end,
|
|
159
|
-
node,
|
|
160
|
-
start: node.getStart(sourceFile)
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
ts.forEachChild(node, visit);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
visit(sourceFile);
|
|
168
|
-
|
|
169
|
-
return matches;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
148
|
const mightNeedTransform = (code: string, check: QuickCheckPattern): boolean => {
|
|
173
149
|
if (check.regex) {
|
|
174
150
|
return check.regex.test(code);
|
|
@@ -189,69 +165,12 @@ const uid = (prefix: string, updateUUID = false): string => {
|
|
|
189
165
|
return prefix + '_' + (updateUUID ? uuid().replace(UUID_DASH_REGEX, '') : uidSuffix) + '_' + (i++).toString(36);
|
|
190
166
|
};
|
|
191
167
|
|
|
192
|
-
const updateImports = (code: string, modification: ImportModification): string => {
|
|
193
|
-
let { module, specifiers } = modification;
|
|
194
|
-
|
|
195
|
-
if (specifiers.size === 0) {
|
|
196
|
-
return code;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
let escapedModule = module.replace(REGEX_ESCAPE_PATTERN, '\\$&'),
|
|
200
|
-
importRegex = buildImportRegex(escapedModule);
|
|
201
|
-
|
|
202
|
-
return updateImportsWithRegex(code, specifiers, importRegex);
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const visitAst = <T>(
|
|
206
|
-
sourceFile: ts.SourceFile,
|
|
207
|
-
callback: VisitorCallback<T>,
|
|
208
|
-
state: T,
|
|
209
|
-
predicate?: VisitorPredicate
|
|
210
|
-
): T => {
|
|
211
|
-
function visit(node: ts.Node): void {
|
|
212
|
-
if (!predicate || predicate(node)) {
|
|
213
|
-
callback(node, state);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
ts.forEachChild(node, visit);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
visit(sourceFile);
|
|
220
|
-
|
|
221
|
-
return state;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
const visitAstWithDepth = <T>(
|
|
225
|
-
sourceFile: ts.SourceFile,
|
|
226
|
-
callback: (node: ts.Node, depth: number, state: T) => void,
|
|
227
|
-
state: T,
|
|
228
|
-
depthTrigger: (node: ts.Node) => boolean
|
|
229
|
-
): T => {
|
|
230
|
-
let depthStack: number[] = [0];
|
|
231
|
-
|
|
232
|
-
function visit(node: ts.Node): void {
|
|
233
|
-
let depth = depthStack[depthStack.length - 1],
|
|
234
|
-
nextDepth = depthTrigger(node) ? depth + 1 : depth;
|
|
235
|
-
|
|
236
|
-
callback(node, depth, state);
|
|
237
|
-
depthStack.push(nextDepth);
|
|
238
|
-
ts.forEachChild(node, visit);
|
|
239
|
-
depthStack.pop();
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
visit(sourceFile);
|
|
243
|
-
|
|
244
|
-
return state;
|
|
245
|
-
};
|
|
246
|
-
|
|
247
168
|
|
|
248
169
|
export {
|
|
249
170
|
addImport, applyReplacements, applyReplacementsReverse,
|
|
250
|
-
collectNodes,
|
|
251
171
|
mightNeedTransform,
|
|
252
172
|
program,
|
|
253
|
-
uid
|
|
254
|
-
visitAst, visitAstWithDepth
|
|
173
|
+
uid
|
|
255
174
|
};
|
|
256
175
|
export type * from './types';
|
|
257
|
-
export * from './constants';
|
|
176
|
+
export * from './constants';
|
package/src/transformer/types.ts
CHANGED
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
import ts from 'typescript';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type ImportModification = {
|
|
5
|
-
module: string;
|
|
6
|
-
specifiers: Set<string>;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
type NodeMatch<T> = Range & {
|
|
10
|
-
data: T;
|
|
11
|
-
node: ts.Node;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
1
|
type QuickCheckPattern = {
|
|
15
2
|
patterns?: string[];
|
|
16
3
|
regex?: RegExp;
|
|
@@ -25,15 +12,5 @@ type Replacement = Range & {
|
|
|
25
12
|
newText: string;
|
|
26
13
|
};
|
|
27
14
|
|
|
28
|
-
type VisitorCallback<T> = (node: ts.Node, state: T) => void;
|
|
29
|
-
|
|
30
|
-
type VisitorPredicate = (node: ts.Node) => boolean;
|
|
31
|
-
|
|
32
15
|
|
|
33
|
-
export type {
|
|
34
|
-
ImportModification,
|
|
35
|
-
NodeMatch,
|
|
36
|
-
QuickCheckPattern,
|
|
37
|
-
Range, Replacement,
|
|
38
|
-
VisitorCallback, VisitorPredicate
|
|
39
|
-
};
|
|
16
|
+
export type { QuickCheckPattern, Range, Replacement };
|
package/bin/tsc-alias
DELETED