@esportsplus/typescript 0.17.4 → 0.17.5
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/build/cli/tsc.js +43 -112
- package/build/transformer/code.d.ts +7 -0
- package/build/transformer/code.js +45 -0
- package/build/transformer/constants.d.ts +2 -4
- package/build/transformer/constants.js +2 -4
- package/build/transformer/index.d.ts +3 -8
- package/build/transformer/index.js +3 -111
- package/build/transformer/uid.d.ts +2 -0
- package/build/transformer/uid.js +6 -0
- package/package.json +1 -1
- package/src/cli/tsc.ts +56 -161
- package/src/transformer/code.ts +67 -0
- package/src/transformer/constants.ts +2 -8
- package/src/transformer/index.ts +3 -174
- package/src/transformer/uid.ts +11 -0
package/build/cli/tsc.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import { pathToFileURL } from 'url';
|
|
4
|
-
import fs from 'fs';
|
|
5
4
|
import path from 'path';
|
|
6
5
|
import ts from 'typescript';
|
|
7
6
|
const BACKSLASH_REGEX = /\\/g;
|
|
8
|
-
let require = createRequire(import.meta.url), skipFlags = ['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v'];
|
|
9
|
-
async function build(tsconfig, plugins) {
|
|
10
|
-
let
|
|
11
|
-
if (error) {
|
|
12
|
-
console.error(ts.flattenDiagnosticMessageText(error.messageText, '\n'));
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
|
15
|
-
let parsed = ts.parseJsonConfigFileContent(config, ts.sys, root);
|
|
7
|
+
let require = createRequire(import.meta.url), skipFlags = new Set(['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v']);
|
|
8
|
+
async function build(config, tsconfig, plugins) {
|
|
9
|
+
let root = path.dirname(path.resolve(tsconfig)), parsed = ts.parseJsonConfigFileContent(config, ts.sys, root);
|
|
16
10
|
if (parsed.errors.length > 0) {
|
|
17
11
|
for (let i = 0, n = parsed.errors.length; i < n; i++) {
|
|
18
12
|
console.error(ts.flattenDiagnosticMessageText(parsed.errors[i].messageText, '\n'));
|
|
@@ -29,29 +23,26 @@ async function build(tsconfig, plugins) {
|
|
|
29
23
|
}
|
|
30
24
|
let result = ts.transform(sourceFile, beforeTransformers), transformed = result.transformed[0];
|
|
31
25
|
if (transformed !== sourceFile) {
|
|
32
|
-
transformedFiles.set(fileName, printer.printFile(transformed));
|
|
26
|
+
transformedFiles.set(normalizePath(fileName), printer.printFile(transformed));
|
|
33
27
|
}
|
|
34
28
|
result.dispose();
|
|
35
29
|
}
|
|
36
30
|
if (transformedFiles.size > 0) {
|
|
37
31
|
let customHost = ts.createCompilerHost(parsed.options), originalGetSourceFile = customHost.getSourceFile.bind(customHost), originalReadFile = customHost.readFile.bind(customHost);
|
|
38
|
-
customHost.readFile = (fileName) => {
|
|
39
|
-
let transformed = transformedFiles.get(path.resolve(fileName).replace(BACKSLASH_REGEX, '/'));
|
|
40
|
-
if (transformed) {
|
|
41
|
-
return transformed;
|
|
42
|
-
}
|
|
43
|
-
return originalReadFile(fileName);
|
|
44
|
-
};
|
|
45
32
|
customHost.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
|
46
|
-
let transformed = transformedFiles.get(
|
|
33
|
+
let transformed = transformedFiles.get(normalizePath(fileName));
|
|
47
34
|
if (transformed) {
|
|
48
35
|
return ts.createSourceFile(fileName, transformed, languageVersion, true);
|
|
49
36
|
}
|
|
50
37
|
return originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
51
38
|
};
|
|
39
|
+
customHost.readFile = (fileName) => {
|
|
40
|
+
return transformedFiles.get(normalizePath(fileName)) ?? originalReadFile(fileName);
|
|
41
|
+
};
|
|
52
42
|
program = ts.createProgram(parsed.fileNames, parsed.options, customHost);
|
|
53
43
|
}
|
|
54
|
-
let diagnostics =
|
|
44
|
+
let { diagnostics, emitSkipped } = program.emit();
|
|
45
|
+
diagnostics = ts.getPreEmitDiagnostics(program).concat(diagnostics);
|
|
55
46
|
if (diagnostics.length > 0) {
|
|
56
47
|
console.error(ts.formatDiagnosticsWithColorAndContext(diagnostics, {
|
|
57
48
|
getCanonicalFileName: (fileName) => fileName,
|
|
@@ -59,58 +50,29 @@ async function build(tsconfig, plugins) {
|
|
|
59
50
|
getNewLine: () => '\n'
|
|
60
51
|
}));
|
|
61
52
|
}
|
|
62
|
-
if (
|
|
53
|
+
if (emitSkipped) {
|
|
63
54
|
process.exit(1);
|
|
64
55
|
}
|
|
65
|
-
|
|
66
|
-
return runTscAlias().then((code) => {
|
|
67
|
-
if (code !== 0) {
|
|
68
|
-
process.exit(code);
|
|
69
|
-
}
|
|
70
|
-
process.exit(0);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
process.exit(0);
|
|
56
|
+
return runTscAlias(process.argv.slice(2)).then((code) => process.exit(code));
|
|
74
57
|
});
|
|
75
58
|
}
|
|
76
|
-
function findPackageJson(moduleName, root) {
|
|
77
|
-
let nodeModulesPath = path.join(root, 'node_modules', moduleName.startsWith('@') ? moduleName.split('/').slice(0, 2).join('/') : moduleName.split('/')[0], 'package.json');
|
|
78
|
-
if (fs.existsSync(nodeModulesPath)) {
|
|
79
|
-
return nodeModulesPath;
|
|
80
|
-
}
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
function findTsconfig(args) {
|
|
84
|
-
let projectIndex = args.indexOf('-p');
|
|
85
|
-
if (projectIndex === -1) {
|
|
86
|
-
projectIndex = args.indexOf('--project');
|
|
87
|
-
}
|
|
88
|
-
if (projectIndex !== -1 && args[projectIndex + 1]) {
|
|
89
|
-
return args[projectIndex + 1];
|
|
90
|
-
}
|
|
91
|
-
return ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');
|
|
92
|
-
}
|
|
93
|
-
function getPlugins(tsconfig) {
|
|
94
|
-
let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
95
|
-
if (error) {
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
|
-
return config?.compilerOptions?.plugins?.filter((p) => typeof p === 'object' && p !== null && 'transform' in p) ?? [];
|
|
99
|
-
}
|
|
100
59
|
async function loadTransformers(plugins, root) {
|
|
101
|
-
let after = [],
|
|
60
|
+
let after = [], before = [], promises = [];
|
|
102
61
|
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
103
|
-
let plugin = plugins[i];
|
|
104
|
-
|
|
62
|
+
let plugin = plugins[i], pluginPath = plugin.transform;
|
|
63
|
+
if (pluginPath.startsWith('.')) {
|
|
64
|
+
pluginPath = pathToFileURL(path.resolve(root, pluginPath)).href;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
pluginPath = pathToFileURL(require.resolve(pluginPath, { paths: [root] })).href;
|
|
68
|
+
}
|
|
69
|
+
promises.push(import(pluginPath).then((module) => {
|
|
105
70
|
let factory = module.default ?? module.createTransformer ?? module;
|
|
106
71
|
if (typeof factory !== 'function') {
|
|
107
72
|
console.error(`Plugin ${plugin.transform}: no transformer factory found`);
|
|
108
73
|
return;
|
|
109
74
|
}
|
|
110
|
-
if (plugin.
|
|
111
|
-
afterDeclarations.push(factory);
|
|
112
|
-
}
|
|
113
|
-
else if (plugin.after) {
|
|
75
|
+
if (plugin.after) {
|
|
114
76
|
after.push(factory);
|
|
115
77
|
}
|
|
116
78
|
else {
|
|
@@ -118,77 +80,46 @@ async function loadTransformers(plugins, root) {
|
|
|
118
80
|
}
|
|
119
81
|
}));
|
|
120
82
|
}
|
|
121
|
-
return Promise.all(promises).then(() => ({ after,
|
|
83
|
+
return Promise.all(promises).then(() => ({ after, before }));
|
|
122
84
|
}
|
|
123
85
|
function main() {
|
|
124
|
-
let
|
|
86
|
+
let tsconfig = ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');
|
|
125
87
|
if (!tsconfig) {
|
|
126
|
-
passthrough();
|
|
127
|
-
return;
|
|
88
|
+
return passthrough();
|
|
128
89
|
}
|
|
129
|
-
let
|
|
130
|
-
if (
|
|
131
|
-
passthrough();
|
|
132
|
-
return;
|
|
90
|
+
let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
91
|
+
if (error) {
|
|
92
|
+
return passthrough();
|
|
133
93
|
}
|
|
94
|
+
let plugins = config?.compilerOptions?.plugins?.filter((p) => typeof p === 'object' && p !== null && 'transform' in p) ?? [];
|
|
134
95
|
console.log(`Found ${plugins.length} transformer plugin(s), using programmatic build...`);
|
|
135
|
-
build(tsconfig, plugins).catch((err) => {
|
|
96
|
+
build(config, tsconfig, plugins).catch((err) => {
|
|
136
97
|
console.error(err);
|
|
137
98
|
process.exit(1);
|
|
138
99
|
});
|
|
139
100
|
}
|
|
101
|
+
function normalizePath(fileName) {
|
|
102
|
+
return path.resolve(fileName).replace(BACKSLASH_REGEX, '/');
|
|
103
|
+
}
|
|
140
104
|
function passthrough() {
|
|
141
|
-
let args = process.argv.slice(2)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
105
|
+
let args = process.argv.slice(2);
|
|
106
|
+
spawn(process.execPath, [require.resolve('typescript/lib/tsc.js'), ...args], { stdio: 'inherit' })
|
|
107
|
+
.on('exit', async (code) => {
|
|
108
|
+
if (code === 0) {
|
|
109
|
+
code = await runTscAlias(args);
|
|
146
110
|
}
|
|
147
111
|
process.exit(code ?? 0);
|
|
148
112
|
});
|
|
149
113
|
}
|
|
150
|
-
function
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (exportValue && typeof exportValue === 'object') {
|
|
155
|
-
return exportValue.import ?? exportValue.default ?? null;
|
|
156
|
-
}
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
function resolvePlugin(modulePath, root) {
|
|
160
|
-
if (modulePath.startsWith('.')) {
|
|
161
|
-
return pathToFileURL(path.resolve(root, modulePath)).href;
|
|
162
|
-
}
|
|
163
|
-
let packageJsonPath = findPackageJson(modulePath, root);
|
|
164
|
-
if (!packageJsonPath) {
|
|
165
|
-
throw new Error(`tsc: cannot find package '${modulePath}' in ${root}`);
|
|
166
|
-
}
|
|
167
|
-
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('/');
|
|
168
|
-
if (packageJson.exports) {
|
|
169
|
-
let exportEntry = subpath === './' ? packageJson.exports['.'] : packageJson.exports[subpath];
|
|
170
|
-
if (exportEntry) {
|
|
171
|
-
let resolved = resolveExport(exportEntry);
|
|
172
|
-
if (resolved) {
|
|
173
|
-
return pathToFileURL(path.resolve(packageDir, resolved)).href;
|
|
174
|
-
}
|
|
114
|
+
function runTscAlias(args) {
|
|
115
|
+
for (let i = 0, n = args.length; i < n; i++) {
|
|
116
|
+
if (skipFlags.has(args[i])) {
|
|
117
|
+
return Promise.resolve(0);
|
|
175
118
|
}
|
|
176
|
-
throw new Error(`tsc: package subpath '${subpath}' is not exported by '${modulePath}'`);
|
|
177
119
|
}
|
|
178
|
-
return pathToFileURL(path.resolve(packageDir, packageJson.main ?? 'index.js')).href;
|
|
179
|
-
}
|
|
180
|
-
function runTscAlias() {
|
|
181
120
|
return new Promise((resolve) => {
|
|
182
|
-
let child = spawn(process.execPath, [require.resolve('tsc-alias/dist/bin/index.js'), ...
|
|
121
|
+
let child = spawn(process.execPath, [require.resolve('tsc-alias/dist/bin/index.js'), ...args], { stdio: 'inherit' });
|
|
183
122
|
child.on('exit', (code) => resolve(code ?? 0));
|
|
184
123
|
});
|
|
185
124
|
}
|
|
186
|
-
function shouldRunTscAlias(args) {
|
|
187
|
-
for (let i = 0, n = skipFlags.length; i < n; i++) {
|
|
188
|
-
if (args.includes(skipFlags[i])) {
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
125
|
main();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { QuickCheckPattern, Replacement } from './types.js';
|
|
2
|
+
declare const _default: {
|
|
3
|
+
contains: (code: string, { regex, patterns }: QuickCheckPattern) => boolean;
|
|
4
|
+
replace: (code: string, replacements: Replacement[]) => string;
|
|
5
|
+
replaceReverse: (code: string, replacements: Replacement[]) => string;
|
|
6
|
+
};
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const contains = (code, { regex, patterns }) => {
|
|
2
|
+
if (regex) {
|
|
3
|
+
return regex.test(code);
|
|
4
|
+
}
|
|
5
|
+
if (patterns) {
|
|
6
|
+
for (let i = 0, n = patterns.length; i < n; i++) {
|
|
7
|
+
if (code.indexOf(patterns[i]) !== -1) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return false;
|
|
13
|
+
};
|
|
14
|
+
const replace = (code, replacements) => {
|
|
15
|
+
if (replacements.length === 0) {
|
|
16
|
+
return code;
|
|
17
|
+
}
|
|
18
|
+
replacements.sort((a, b) => a.start - b.start);
|
|
19
|
+
let parts = [], pos = 0;
|
|
20
|
+
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
21
|
+
let r = replacements[i];
|
|
22
|
+
if (r.start > pos) {
|
|
23
|
+
parts.push(code.substring(pos, r.start));
|
|
24
|
+
}
|
|
25
|
+
parts.push(r.newText);
|
|
26
|
+
pos = r.end;
|
|
27
|
+
}
|
|
28
|
+
if (pos < code.length) {
|
|
29
|
+
parts.push(code.substring(pos));
|
|
30
|
+
}
|
|
31
|
+
return parts.join('');
|
|
32
|
+
};
|
|
33
|
+
const replaceReverse = (code, replacements) => {
|
|
34
|
+
if (replacements.length === 0) {
|
|
35
|
+
return code;
|
|
36
|
+
}
|
|
37
|
+
replacements.sort((a, b) => b.start - a.start);
|
|
38
|
+
let result = code;
|
|
39
|
+
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
40
|
+
let r = replacements[i];
|
|
41
|
+
result = result.substring(0, r.start) + r.newText + result.substring(r.end);
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
export default { contains, replace, replaceReverse };
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
declare const BRACES_CONTENT_REGEX: RegExp;
|
|
2
|
-
declare const REGEX_ESCAPE_PATTERN: RegExp;
|
|
3
1
|
declare const TRAILING_SEMICOLON: RegExp;
|
|
4
2
|
declare const TRANSFORM_PATTERN: RegExp;
|
|
5
|
-
declare const
|
|
6
|
-
export {
|
|
3
|
+
declare const UUID_REGEX: RegExp;
|
|
4
|
+
export { TRAILING_SEMICOLON, TRANSFORM_PATTERN, UUID_REGEX, };
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
const BRACES_CONTENT_REGEX = /\{([^}]*)\}/;
|
|
2
|
-
const REGEX_ESCAPE_PATTERN = /[.*+?^${}()|[\]\\]/g;
|
|
3
1
|
const TRAILING_SEMICOLON = /;$/;
|
|
4
2
|
const TRANSFORM_PATTERN = /\.[tj]sx?$/;
|
|
5
|
-
const
|
|
6
|
-
export {
|
|
3
|
+
const UUID_REGEX = /[^A-Za-z0-9_$]/g;
|
|
4
|
+
export { TRAILING_SEMICOLON, TRANSFORM_PATTERN, UUID_REGEX, };
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
declare const applyReplacements: (code: string, replacements: Replacement[]) => string;
|
|
5
|
-
declare const applyReplacementsReverse: (code: string, replacements: Replacement[]) => string;
|
|
6
|
-
declare const mightNeedTransform: (code: string, check: QuickCheckPattern) => boolean;
|
|
7
|
-
declare const uid: (prefix: string, updateUUID?: boolean) => string;
|
|
8
|
-
export { addImport, applyReplacements, applyReplacementsReverse, mightNeedTransform, program, uid };
|
|
1
|
+
export { default as code } from './code.js';
|
|
2
|
+
export { default as program } from './program.js';
|
|
3
|
+
export { default as uid } from './uid.js';
|
|
9
4
|
export type * from './types.js';
|
|
10
5
|
export * from './constants.js';
|
|
@@ -1,112 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
let i = 0, uidSuffix = uuid().replace(UUID_DASH_REGEX, '');
|
|
5
|
-
function buildImportRegex(escapedModule) {
|
|
6
|
-
return new RegExp(`(import\\s*\\{[^}]*\\}\\s*from\\s*['"]${escapedModule}['"])`);
|
|
7
|
-
}
|
|
8
|
-
function mergeAndSort(a, b) {
|
|
9
|
-
let combined = new Array(a.length + b.size), idx = 0, n = a.length;
|
|
10
|
-
for (let i = 0; i < n; i++) {
|
|
11
|
-
if (a[i]) {
|
|
12
|
-
combined[idx++] = a[i];
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
for (let item of b) {
|
|
16
|
-
if (item) {
|
|
17
|
-
combined[idx++] = item;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
combined.length = idx;
|
|
21
|
-
combined.sort();
|
|
22
|
-
return combined.join(', ');
|
|
23
|
-
}
|
|
24
|
-
function parseSpecifiers(str) {
|
|
25
|
-
let parts = str.split(','), result = new Set();
|
|
26
|
-
for (let i = 0, n = parts.length; i < n; i++) {
|
|
27
|
-
let trimmed = parts[i].trim();
|
|
28
|
-
if (trimmed) {
|
|
29
|
-
result.add(trimmed);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return result;
|
|
33
|
-
}
|
|
34
|
-
function updateImportsWithRegex(code, specifiers, importRegex) {
|
|
35
|
-
let match = code.match(importRegex);
|
|
36
|
-
if (!match) {
|
|
37
|
-
return code;
|
|
38
|
-
}
|
|
39
|
-
let bracesMatch = match[1].match(BRACES_CONTENT_REGEX), existing = bracesMatch?.[1] ? parseSpecifiers(bracesMatch[1]) : new Set(), toAdd = [];
|
|
40
|
-
for (let spec of specifiers) {
|
|
41
|
-
if (!existing.has(spec)) {
|
|
42
|
-
toAdd.push(spec);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
if (toAdd.length === 0) {
|
|
46
|
-
return code;
|
|
47
|
-
}
|
|
48
|
-
return code.replace(match[1], match[1].replace(BRACES_CONTENT_REGEX, `{ ${mergeAndSort(toAdd, existing)} }`));
|
|
49
|
-
}
|
|
50
|
-
const addImport = (code, module, specifiers) => {
|
|
51
|
-
if (specifiers.length === 0) {
|
|
52
|
-
return code;
|
|
53
|
-
}
|
|
54
|
-
let regex = buildImportRegex(module.replace(REGEX_ESCAPE_PATTERN, '\\$&'));
|
|
55
|
-
if (regex.test(code)) {
|
|
56
|
-
return updateImportsWithRegex(code, new Set(specifiers), regex);
|
|
57
|
-
}
|
|
58
|
-
let adding = `import { ${specifiers.sort().join(', ')} } from '${module}';\n`, first = code.indexOf('import ');
|
|
59
|
-
if (first === -1) {
|
|
60
|
-
return adding + code;
|
|
61
|
-
}
|
|
62
|
-
return code.substring(0, first) + adding + code.substring(first);
|
|
63
|
-
};
|
|
64
|
-
const applyReplacements = (code, replacements) => {
|
|
65
|
-
if (replacements.length === 0) {
|
|
66
|
-
return code;
|
|
67
|
-
}
|
|
68
|
-
replacements.sort((a, b) => a.start - b.start);
|
|
69
|
-
let parts = [], pos = 0;
|
|
70
|
-
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
71
|
-
let r = replacements[i];
|
|
72
|
-
if (r.start > pos) {
|
|
73
|
-
parts.push(code.substring(pos, r.start));
|
|
74
|
-
}
|
|
75
|
-
parts.push(r.newText);
|
|
76
|
-
pos = r.end;
|
|
77
|
-
}
|
|
78
|
-
if (pos < code.length) {
|
|
79
|
-
parts.push(code.substring(pos));
|
|
80
|
-
}
|
|
81
|
-
return parts.join('');
|
|
82
|
-
};
|
|
83
|
-
const applyReplacementsReverse = (code, replacements) => {
|
|
84
|
-
if (replacements.length === 0) {
|
|
85
|
-
return code;
|
|
86
|
-
}
|
|
87
|
-
replacements.sort((a, b) => b.start - a.start);
|
|
88
|
-
let result = code;
|
|
89
|
-
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
90
|
-
let r = replacements[i];
|
|
91
|
-
result = result.substring(0, r.start) + r.newText + result.substring(r.end);
|
|
92
|
-
}
|
|
93
|
-
return result;
|
|
94
|
-
};
|
|
95
|
-
const mightNeedTransform = (code, check) => {
|
|
96
|
-
if (check.regex) {
|
|
97
|
-
return check.regex.test(code);
|
|
98
|
-
}
|
|
99
|
-
if (check.patterns) {
|
|
100
|
-
for (let i = 0, n = check.patterns.length; i < n; i++) {
|
|
101
|
-
if (code.indexOf(check.patterns[i]) !== -1) {
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return false;
|
|
107
|
-
};
|
|
108
|
-
const uid = (prefix, updateUUID = false) => {
|
|
109
|
-
return prefix + '_' + (updateUUID ? uuid().replace(UUID_DASH_REGEX, '') : uidSuffix) + '_' + (i++).toString(36);
|
|
110
|
-
};
|
|
111
|
-
export { addImport, applyReplacements, applyReplacementsReverse, mightNeedTransform, program, uid };
|
|
1
|
+
export { default as code } from './code.js';
|
|
2
|
+
export { default as program } from './program.js';
|
|
3
|
+
export { default as uid } from './uid.js';
|
|
112
4
|
export * from './constants.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { uuid } from '@esportsplus/utilities';
|
|
2
|
+
import { UUID_REGEX } from './constants.js';
|
|
3
|
+
let cache = uuid().replace(UUID_REGEX, ''), i = 0;
|
|
4
|
+
export default (prefix, reset = false) => {
|
|
5
|
+
return prefix + '_' + (reset ? uuid().replace(UUID_REGEX, '') : cache) + (i++).toString(36);
|
|
6
|
+
};
|
package/package.json
CHANGED
package/src/cli/tsc.ts
CHANGED
|
@@ -2,16 +2,12 @@ import { spawn } from 'child_process';
|
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import { pathToFileURL } from 'url';
|
|
4
4
|
|
|
5
|
-
import fs from 'fs';
|
|
6
5
|
import path from 'path';
|
|
7
6
|
import ts from 'typescript';
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
type ExportValue = string | { default?: string; import?: string; types?: string } | null;
|
|
11
|
-
|
|
12
9
|
type PluginConfig = {
|
|
13
10
|
after?: boolean;
|
|
14
|
-
afterDeclarations?: boolean;
|
|
15
11
|
transform: string;
|
|
16
12
|
};
|
|
17
13
|
|
|
@@ -22,23 +18,18 @@ const BACKSLASH_REGEX = /\\/g;
|
|
|
22
18
|
|
|
23
19
|
|
|
24
20
|
let require = createRequire(import.meta.url),
|
|
25
|
-
skipFlags = ['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v'];
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
async function build(tsconfig: string, plugins: PluginConfig[]): Promise<void> {
|
|
29
|
-
let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile),
|
|
30
|
-
root = path.dirname(path.resolve(tsconfig));
|
|
21
|
+
skipFlags = new Set(['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v']);
|
|
31
22
|
|
|
32
|
-
if (error) {
|
|
33
|
-
console.error(ts.flattenDiagnosticMessageText(error.messageText, '\n'));
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
23
|
|
|
37
|
-
|
|
24
|
+
async function build(config: object, tsconfig: string, plugins: PluginConfig[]): Promise<void> {
|
|
25
|
+
let root = path.dirname(path.resolve(tsconfig)),
|
|
26
|
+
parsed = ts.parseJsonConfigFileContent(config, ts.sys, root);
|
|
38
27
|
|
|
39
28
|
if (parsed.errors.length > 0) {
|
|
40
29
|
for (let i = 0, n = parsed.errors.length; i < n; i++) {
|
|
41
|
-
console.error(
|
|
30
|
+
console.error(
|
|
31
|
+
ts.flattenDiagnosticMessageText(parsed.errors[i].messageText, '\n')
|
|
32
|
+
);
|
|
42
33
|
}
|
|
43
34
|
|
|
44
35
|
process.exit(1);
|
|
@@ -63,7 +54,7 @@ async function build(tsconfig: string, plugins: PluginConfig[]): Promise<void> {
|
|
|
63
54
|
transformed = result.transformed[0];
|
|
64
55
|
|
|
65
56
|
if (transformed !== sourceFile) {
|
|
66
|
-
transformedFiles.set(fileName, printer.printFile(transformed));
|
|
57
|
+
transformedFiles.set(normalizePath(fileName), printer.printFile(transformed));
|
|
67
58
|
}
|
|
68
59
|
|
|
69
60
|
result.dispose();
|
|
@@ -74,27 +65,13 @@ async function build(tsconfig: string, plugins: PluginConfig[]): Promise<void> {
|
|
|
74
65
|
originalGetSourceFile = customHost.getSourceFile.bind(customHost),
|
|
75
66
|
originalReadFile = customHost.readFile.bind(customHost);
|
|
76
67
|
|
|
77
|
-
customHost.readFile = (fileName: string): string | undefined => {
|
|
78
|
-
let transformed = transformedFiles.get(
|
|
79
|
-
path.resolve(fileName).replace(BACKSLASH_REGEX, '/')
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
if (transformed) {
|
|
83
|
-
return transformed;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return originalReadFile(fileName);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
68
|
customHost.getSourceFile = (
|
|
90
69
|
fileName: string,
|
|
91
70
|
languageVersion: ts.ScriptTarget,
|
|
92
71
|
onError?: (message: string) => void,
|
|
93
72
|
shouldCreateNewSourceFile?: boolean
|
|
94
73
|
): ts.SourceFile | undefined => {
|
|
95
|
-
let transformed = transformedFiles.get(
|
|
96
|
-
path.resolve(fileName).replace(BACKSLASH_REGEX, '/')
|
|
97
|
-
);
|
|
74
|
+
let transformed = transformedFiles.get(normalizePath(fileName));
|
|
98
75
|
|
|
99
76
|
if (transformed) {
|
|
100
77
|
return ts.createSourceFile(fileName, transformed, languageVersion, true);
|
|
@@ -103,10 +80,16 @@ async function build(tsconfig: string, plugins: PluginConfig[]): Promise<void> {
|
|
|
103
80
|
return originalGetSourceFile(fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
|
104
81
|
};
|
|
105
82
|
|
|
83
|
+
customHost.readFile = (fileName: string): string | undefined => {
|
|
84
|
+
return transformedFiles.get(normalizePath(fileName)) ?? originalReadFile(fileName);
|
|
85
|
+
};
|
|
86
|
+
|
|
106
87
|
program = ts.createProgram(parsed.fileNames, parsed.options, customHost);
|
|
107
88
|
}
|
|
108
89
|
|
|
109
|
-
let diagnostics =
|
|
90
|
+
let { diagnostics, emitSkipped } = program.emit();
|
|
91
|
+
|
|
92
|
+
diagnostics = ts.getPreEmitDiagnostics(program).concat(diagnostics);
|
|
110
93
|
|
|
111
94
|
if (diagnostics.length > 0) {
|
|
112
95
|
console.error(
|
|
@@ -118,75 +101,35 @@ async function build(tsconfig: string, plugins: PluginConfig[]): Promise<void> {
|
|
|
118
101
|
);
|
|
119
102
|
}
|
|
120
103
|
|
|
121
|
-
if (
|
|
104
|
+
if (emitSkipped) {
|
|
122
105
|
process.exit(1);
|
|
123
106
|
}
|
|
124
107
|
|
|
125
|
-
|
|
126
|
-
return runTscAlias().then((code) => {
|
|
127
|
-
if (code !== 0) {
|
|
128
|
-
process.exit(code);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
process.exit(0);
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
process.exit(0);
|
|
108
|
+
return runTscAlias(process.argv.slice(2)).then((code) => process.exit(code));
|
|
136
109
|
});
|
|
137
110
|
}
|
|
138
111
|
|
|
139
|
-
function findPackageJson(moduleName: string, root: string): string | null {
|
|
140
|
-
let nodeModulesPath = path.join(root, 'node_modules', moduleName.startsWith('@') ? moduleName.split('/').slice(0, 2).join('/') : moduleName.split('/')[0], 'package.json');
|
|
141
|
-
|
|
142
|
-
if (fs.existsSync(nodeModulesPath)) {
|
|
143
|
-
return nodeModulesPath;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return null;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function findTsconfig(args: string[]): string | undefined {
|
|
150
|
-
let projectIndex = args.indexOf('-p');
|
|
151
|
-
|
|
152
|
-
if (projectIndex === -1) {
|
|
153
|
-
projectIndex = args.indexOf('--project');
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
if (projectIndex !== -1 && args[projectIndex + 1]) {
|
|
157
|
-
return args[projectIndex + 1];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function getPlugins(tsconfig: string): PluginConfig[] {
|
|
164
|
-
let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
165
|
-
|
|
166
|
-
if (error) {
|
|
167
|
-
return [];
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return config?.compilerOptions?.plugins?.filter(
|
|
171
|
-
(p: unknown) => typeof p === 'object' && p !== null && 'transform' in p
|
|
172
|
-
) ?? [];
|
|
173
|
-
}
|
|
174
|
-
|
|
175
112
|
async function loadTransformers(plugins: PluginConfig[], root: string): Promise<{
|
|
176
113
|
after: TransformerCreator[];
|
|
177
|
-
afterDeclarations: TransformerCreator[];
|
|
178
114
|
before: TransformerCreator[];
|
|
179
115
|
}> {
|
|
180
116
|
let after: TransformerCreator[] = [],
|
|
181
|
-
afterDeclarations: TransformerCreator[] = [],
|
|
182
117
|
before: TransformerCreator[] = [],
|
|
183
118
|
promises: Promise<void>[] = [];
|
|
184
119
|
|
|
185
120
|
for (let i = 0, n = plugins.length; i < n; i++) {
|
|
186
|
-
let plugin = plugins[i]
|
|
121
|
+
let plugin = plugins[i],
|
|
122
|
+
pluginPath = plugin.transform;
|
|
123
|
+
|
|
124
|
+
if (pluginPath.startsWith('.')) {
|
|
125
|
+
pluginPath = pathToFileURL(path.resolve(root, pluginPath)).href;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
pluginPath = pathToFileURL(require.resolve(pluginPath, { paths: [root] })).href;
|
|
129
|
+
}
|
|
187
130
|
|
|
188
131
|
promises.push(
|
|
189
|
-
import(
|
|
132
|
+
import(pluginPath).then((module) => {
|
|
190
133
|
let factory = module.default ?? module.createTransformer ?? module;
|
|
191
134
|
|
|
192
135
|
if (typeof factory !== 'function') {
|
|
@@ -194,10 +137,7 @@ async function loadTransformers(plugins: PluginConfig[], root: string): Promise<
|
|
|
194
137
|
return;
|
|
195
138
|
}
|
|
196
139
|
|
|
197
|
-
if (plugin.
|
|
198
|
-
afterDeclarations.push(factory);
|
|
199
|
-
}
|
|
200
|
-
else if (plugin.after) {
|
|
140
|
+
if (plugin.after) {
|
|
201
141
|
after.push(factory);
|
|
202
142
|
}
|
|
203
143
|
else {
|
|
@@ -207,109 +147,64 @@ async function loadTransformers(plugins: PluginConfig[], root: string): Promise<
|
|
|
207
147
|
);
|
|
208
148
|
}
|
|
209
149
|
|
|
210
|
-
return Promise.all(promises).then(() => ({ after,
|
|
150
|
+
return Promise.all(promises).then(() => ({ after, before }));
|
|
211
151
|
}
|
|
212
152
|
|
|
213
153
|
function main(): void {
|
|
214
|
-
let
|
|
215
|
-
tsconfig = findTsconfig(args);
|
|
154
|
+
let tsconfig = ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');
|
|
216
155
|
|
|
217
156
|
if (!tsconfig) {
|
|
218
|
-
passthrough();
|
|
219
|
-
return;
|
|
157
|
+
return passthrough();
|
|
220
158
|
}
|
|
221
159
|
|
|
222
|
-
let
|
|
160
|
+
let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
|
|
223
161
|
|
|
224
|
-
if (
|
|
225
|
-
passthrough();
|
|
226
|
-
return;
|
|
162
|
+
if (error) {
|
|
163
|
+
return passthrough();
|
|
227
164
|
}
|
|
228
165
|
|
|
166
|
+
let plugins = config?.compilerOptions?.plugins?.filter(
|
|
167
|
+
(p: unknown) => typeof p === 'object' && p !== null && 'transform' in p
|
|
168
|
+
) ?? [];
|
|
169
|
+
|
|
229
170
|
console.log(`Found ${plugins.length} transformer plugin(s), using programmatic build...`);
|
|
230
171
|
|
|
231
|
-
build(tsconfig, plugins).catch((err) => {
|
|
172
|
+
build(config, tsconfig, plugins).catch((err) => {
|
|
232
173
|
console.error(err);
|
|
233
174
|
process.exit(1);
|
|
234
175
|
});
|
|
235
176
|
}
|
|
236
177
|
|
|
237
|
-
function
|
|
238
|
-
|
|
239
|
-
child = spawn(process.execPath, [require.resolve('typescript/lib/tsc.js'), ...args], { stdio: 'inherit' });
|
|
240
|
-
|
|
241
|
-
child.on('exit', (code) => {
|
|
242
|
-
if (code === 0 && shouldRunTscAlias(args)) {
|
|
243
|
-
runTscAlias().then((aliasCode) => process.exit(aliasCode ?? 0));
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
process.exit(code ?? 0);
|
|
248
|
-
});
|
|
178
|
+
function normalizePath(fileName: string): string {
|
|
179
|
+
return path.resolve(fileName).replace(BACKSLASH_REGEX, '/');
|
|
249
180
|
}
|
|
250
181
|
|
|
251
|
-
function
|
|
252
|
-
|
|
253
|
-
return exportValue;
|
|
254
|
-
}
|
|
182
|
+
function passthrough(): void {
|
|
183
|
+
let args = process.argv.slice(2);
|
|
255
184
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
185
|
+
spawn(process.execPath, [require.resolve('typescript/lib/tsc.js'), ...args], { stdio: 'inherit' })
|
|
186
|
+
.on('exit', async (code) => {
|
|
187
|
+
if (code === 0) {
|
|
188
|
+
code = await runTscAlias(args);
|
|
189
|
+
}
|
|
259
190
|
|
|
260
|
-
|
|
191
|
+
process.exit(code ?? 0);
|
|
192
|
+
});
|
|
261
193
|
}
|
|
262
194
|
|
|
263
|
-
function
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
let packageJsonPath = findPackageJson(modulePath, root);
|
|
269
|
-
|
|
270
|
-
if (!packageJsonPath) {
|
|
271
|
-
throw new Error(`tsc: cannot find package '${modulePath}' in ${root}`);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
let packageDir = path.dirname(packageJsonPath),
|
|
275
|
-
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')),
|
|
276
|
-
parts = modulePath.split('/'),
|
|
277
|
-
subpath = './' + (modulePath.startsWith('@') ? parts.slice(2) : parts.slice(1)).join('/');
|
|
278
|
-
|
|
279
|
-
if (packageJson.exports) {
|
|
280
|
-
let exportEntry = subpath === './' ? packageJson.exports['.'] : packageJson.exports[subpath];
|
|
281
|
-
|
|
282
|
-
if (exportEntry) {
|
|
283
|
-
let resolved = resolveExport(exportEntry);
|
|
284
|
-
|
|
285
|
-
if (resolved) {
|
|
286
|
-
return pathToFileURL(path.resolve(packageDir, resolved)).href;
|
|
287
|
-
}
|
|
195
|
+
function runTscAlias(args: string[]): Promise<number> {
|
|
196
|
+
for (let i = 0, n = args.length; i < n; i++) {
|
|
197
|
+
if (skipFlags.has(args[i])) {
|
|
198
|
+
return Promise.resolve(0);
|
|
288
199
|
}
|
|
289
|
-
|
|
290
|
-
throw new Error(`tsc: package subpath '${subpath}' is not exported by '${modulePath}'`);
|
|
291
200
|
}
|
|
292
201
|
|
|
293
|
-
return pathToFileURL(path.resolve(packageDir, packageJson.main ?? 'index.js')).href;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
function runTscAlias(): Promise<number> {
|
|
297
202
|
return new Promise((resolve) => {
|
|
298
|
-
let child = spawn(process.execPath, [require.resolve('tsc-alias/dist/bin/index.js'), ...
|
|
203
|
+
let child = spawn(process.execPath, [require.resolve('tsc-alias/dist/bin/index.js'), ...args], { stdio: 'inherit' });
|
|
299
204
|
|
|
300
205
|
child.on('exit', (code) => resolve(code ?? 0));
|
|
301
206
|
});
|
|
302
207
|
}
|
|
303
208
|
|
|
304
|
-
function shouldRunTscAlias(args: string[]): boolean {
|
|
305
|
-
for (let i = 0, n = skipFlags.length; i < n; i++) {
|
|
306
|
-
if (args.includes(skipFlags[i])) {
|
|
307
|
-
return false;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
return true;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
209
|
|
|
315
210
|
main();
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { QuickCheckPattern, Replacement } from './types.js';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
const contains = (code: string, { regex, patterns }: QuickCheckPattern): boolean => {
|
|
5
|
+
if (regex) {
|
|
6
|
+
return regex.test(code);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
if (patterns) {
|
|
10
|
+
for (let i = 0, n = patterns.length; i < n; i++) {
|
|
11
|
+
if (code.indexOf(patterns[i]) !== -1) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return false;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const replace = (code: string, replacements: Replacement[]): string => {
|
|
21
|
+
if (replacements.length === 0) {
|
|
22
|
+
return code;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
replacements.sort((a, b) => a.start - b.start);
|
|
26
|
+
|
|
27
|
+
let parts: string[] = [],
|
|
28
|
+
pos = 0;
|
|
29
|
+
|
|
30
|
+
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
31
|
+
let r = replacements[i];
|
|
32
|
+
|
|
33
|
+
if (r.start > pos) {
|
|
34
|
+
parts.push(code.substring(pos, r.start));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
parts.push(r.newText);
|
|
38
|
+
pos = r.end;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (pos < code.length) {
|
|
42
|
+
parts.push(code.substring(pos));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return parts.join('');
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const replaceReverse =(code: string, replacements: Replacement[]): string => {
|
|
49
|
+
if (replacements.length === 0) {
|
|
50
|
+
return code;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
replacements.sort((a, b) => b.start - a.start);
|
|
54
|
+
|
|
55
|
+
let result = code;
|
|
56
|
+
|
|
57
|
+
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
58
|
+
let r = replacements[i];
|
|
59
|
+
|
|
60
|
+
result = result.substring(0, r.start) + r.newText + result.substring(r.end);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return result;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
export default { contains, replace, replaceReverse };
|
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
const BRACES_CONTENT_REGEX = /\{([^}]*)\}/;
|
|
2
|
-
|
|
3
|
-
const REGEX_ESCAPE_PATTERN = /[.*+?^${}()|[\]\\]/g;
|
|
4
|
-
|
|
5
1
|
const TRAILING_SEMICOLON = /;$/;
|
|
6
2
|
|
|
7
3
|
const TRANSFORM_PATTERN = /\.[tj]sx?$/;
|
|
8
4
|
|
|
9
|
-
const
|
|
5
|
+
const UUID_REGEX = /[^A-Za-z0-9_$]/g;
|
|
10
6
|
|
|
11
7
|
|
|
12
8
|
export {
|
|
13
|
-
BRACES_CONTENT_REGEX,
|
|
14
|
-
REGEX_ESCAPE_PATTERN,
|
|
15
9
|
TRAILING_SEMICOLON, TRANSFORM_PATTERN,
|
|
16
|
-
|
|
10
|
+
UUID_REGEX,
|
|
17
11
|
};
|
package/src/transformer/index.ts
CHANGED
|
@@ -1,176 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import program from './program';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let i = 0,
|
|
8
|
-
uidSuffix = uuid().replace(UUID_DASH_REGEX, '');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
function buildImportRegex(escapedModule: string): RegExp {
|
|
12
|
-
return new RegExp(`(import\\s*\\{[^}]*\\}\\s*from\\s*['"]${escapedModule}['"])`);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function mergeAndSort(a: string[], b: Set<string>): string {
|
|
16
|
-
let combined = new Array<string>(a.length + b.size),
|
|
17
|
-
idx = 0,
|
|
18
|
-
n = a.length;
|
|
19
|
-
|
|
20
|
-
for (let i = 0; i < n; i++) {
|
|
21
|
-
if (a[i]) {
|
|
22
|
-
combined[idx++] = a[i];
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
for (let item of b) {
|
|
27
|
-
if (item) {
|
|
28
|
-
combined[idx++] = item;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
combined.length = idx;
|
|
33
|
-
combined.sort();
|
|
34
|
-
|
|
35
|
-
return combined.join(', ');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function parseSpecifiers(str: string): Set<string> {
|
|
39
|
-
let parts = str.split(','),
|
|
40
|
-
result = new Set<string>();
|
|
41
|
-
|
|
42
|
-
for (let i = 0, n = parts.length; i < n; i++) {
|
|
43
|
-
let trimmed = parts[i].trim();
|
|
44
|
-
|
|
45
|
-
if (trimmed) {
|
|
46
|
-
result.add(trimmed);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function updateImportsWithRegex(code: string, specifiers: Set<string>, importRegex: RegExp): string {
|
|
54
|
-
let match = code.match(importRegex);
|
|
55
|
-
|
|
56
|
-
if (!match) {
|
|
57
|
-
return code;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
let bracesMatch = match[1].match(BRACES_CONTENT_REGEX),
|
|
61
|
-
existing = bracesMatch?.[1] ? parseSpecifiers(bracesMatch[1]) : new Set<string>(),
|
|
62
|
-
toAdd: string[] = [];
|
|
63
|
-
|
|
64
|
-
for (let spec of specifiers) {
|
|
65
|
-
if (!existing.has(spec)) {
|
|
66
|
-
toAdd.push(spec);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (toAdd.length === 0) {
|
|
71
|
-
return code;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return code.replace(
|
|
75
|
-
match[1],
|
|
76
|
-
match[1].replace(BRACES_CONTENT_REGEX, `{ ${mergeAndSort(toAdd, existing)} }`)
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const addImport = (code: string, module: string, specifiers: string[]): string => {
|
|
82
|
-
if (specifiers.length === 0) {
|
|
83
|
-
return code;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
let regex = buildImportRegex( module.replace(REGEX_ESCAPE_PATTERN, '\\$&') );
|
|
87
|
-
|
|
88
|
-
if (regex.test(code)) {
|
|
89
|
-
return updateImportsWithRegex(code, new Set(specifiers), regex);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
let adding = `import { ${specifiers.sort().join(', ')} } from '${module}';\n`,
|
|
93
|
-
first = code.indexOf('import ');
|
|
94
|
-
|
|
95
|
-
if (first === -1) {
|
|
96
|
-
return adding + code;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return code.substring(0, first) + adding + code.substring(first);
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const applyReplacements = (code: string, replacements: Replacement[]): string => {
|
|
103
|
-
if (replacements.length === 0) {
|
|
104
|
-
return code;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
replacements.sort((a, b) => a.start - b.start);
|
|
108
|
-
|
|
109
|
-
let parts: string[] = [],
|
|
110
|
-
pos = 0;
|
|
111
|
-
|
|
112
|
-
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
113
|
-
let r = replacements[i];
|
|
114
|
-
|
|
115
|
-
if (r.start > pos) {
|
|
116
|
-
parts.push(code.substring(pos, r.start));
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
parts.push(r.newText);
|
|
120
|
-
pos = r.end;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (pos < code.length) {
|
|
124
|
-
parts.push(code.substring(pos));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return parts.join('');
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const applyReplacementsReverse = (code: string, replacements: Replacement[]): string => {
|
|
131
|
-
if (replacements.length === 0) {
|
|
132
|
-
return code;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
replacements.sort((a, b) => b.start - a.start);
|
|
136
|
-
|
|
137
|
-
let result = code;
|
|
138
|
-
|
|
139
|
-
for (let i = 0, n = replacements.length; i < n; i++) {
|
|
140
|
-
let r = replacements[i];
|
|
141
|
-
|
|
142
|
-
result = result.substring(0, r.start) + r.newText + result.substring(r.end);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return result;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const mightNeedTransform = (code: string, check: QuickCheckPattern): boolean => {
|
|
149
|
-
if (check.regex) {
|
|
150
|
-
return check.regex.test(code);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (check.patterns) {
|
|
154
|
-
for (let i = 0, n = check.patterns.length; i < n; i++) {
|
|
155
|
-
if (code.indexOf(check.patterns[i]) !== -1) {
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return false;
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
const uid = (prefix: string, updateUUID = false): string => {
|
|
165
|
-
return prefix + '_' + (updateUUID ? uuid().replace(UUID_DASH_REGEX, '') : uidSuffix) + '_' + (i++).toString(36);
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
export {
|
|
170
|
-
addImport, applyReplacements, applyReplacementsReverse,
|
|
171
|
-
mightNeedTransform,
|
|
172
|
-
program,
|
|
173
|
-
uid
|
|
174
|
-
};
|
|
1
|
+
export { default as code } from './code';
|
|
2
|
+
export { default as program } from './program';
|
|
3
|
+
export { default as uid } from './uid';
|
|
175
4
|
export type * from './types';
|
|
176
5
|
export * from './constants';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { uuid } from '@esportsplus/utilities';
|
|
2
|
+
import { UUID_REGEX } from './constants.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
let cache = uuid().replace(UUID_REGEX, ''),
|
|
6
|
+
i = 0;
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default (prefix: string, reset = false): string => {
|
|
10
|
+
return prefix + '_' + (reset ? uuid().replace(UUID_REGEX, '') : cache) + (i++).toString(36);
|
|
11
|
+
};
|