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