@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 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 { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile), root = path.dirname(path.resolve(tsconfig));
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(path.resolve(fileName).replace(BACKSLASH_REGEX, '/'));
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 = ts.getPreEmitDiagnostics(program).concat(program.emit().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 (program.emit().emitSkipped) {
53
+ if (emitSkipped) {
63
54
  process.exit(1);
64
55
  }
65
- if (shouldRunTscAlias(process.argv.slice(2))) {
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 = [], afterDeclarations = [], before = [], promises = [];
60
+ let after = [], before = [], promises = [];
102
61
  for (let i = 0, n = plugins.length; i < n; i++) {
103
- let plugin = plugins[i];
104
- promises.push(import(resolvePlugin(plugin.transform, root)).then((module) => {
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.afterDeclarations) {
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, afterDeclarations, before }));
83
+ return Promise.all(promises).then(() => ({ after, before }));
122
84
  }
123
85
  function main() {
124
- let args = process.argv.slice(2), tsconfig = findTsconfig(args);
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 plugins = getPlugins(tsconfig);
130
- if (plugins.length === 0) {
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), child = spawn(process.execPath, [require.resolve('typescript/lib/tsc.js'), ...args], { stdio: 'inherit' });
142
- child.on('exit', (code) => {
143
- if (code === 0 && shouldRunTscAlias(args)) {
144
- runTscAlias().then((aliasCode) => process.exit(aliasCode ?? 0));
145
- return;
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 resolveExport(exportValue) {
151
- if (typeof exportValue === 'string') {
152
- return exportValue;
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'), ...process.argv.slice(2)], { stdio: 'inherit' });
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 UUID_DASH_REGEX: RegExp;
6
- export { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, TRAILING_SEMICOLON, TRANSFORM_PATTERN, UUID_DASH_REGEX, };
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 UUID_DASH_REGEX = /-/g;
6
- export { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, TRAILING_SEMICOLON, TRANSFORM_PATTERN, UUID_DASH_REGEX, };
3
+ const UUID_REGEX = /[^A-Za-z0-9_$]/g;
4
+ export { TRAILING_SEMICOLON, TRANSFORM_PATTERN, UUID_REGEX, };
@@ -1,10 +1,5 @@
1
- import type { QuickCheckPattern, Replacement } from './types.js';
2
- import program from './program.js';
3
- declare const addImport: (code: string, module: string, specifiers: string[]) => string;
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
- import { uuid } from '@esportsplus/utilities';
2
- import { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX } from './constants.js';
3
- import program from './program.js';
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,2 @@
1
+ declare const _default: (prefix: string, reset?: boolean) => string;
2
+ export default _default;
@@ -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
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "type": "module",
36
36
  "types": "build/index.d.ts",
37
- "version": "0.17.4",
37
+ "version": "0.17.5",
38
38
  "scripts": {
39
39
  "build": "tsc && tsc-alias",
40
40
  "-": "-"
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
- let parsed = ts.parseJsonConfigFileContent(config, ts.sys, root);
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(ts.flattenDiagnosticMessageText(parsed.errors[i].messageText, '\n'));
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 = ts.getPreEmitDiagnostics(program).concat(program.emit().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 (program.emit().emitSkipped) {
104
+ if (emitSkipped) {
122
105
  process.exit(1);
123
106
  }
124
107
 
125
- if (shouldRunTscAlias(process.argv.slice(2))) {
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(resolvePlugin(plugin.transform, root)).then((module) => {
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.afterDeclarations) {
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, afterDeclarations, before }));
150
+ return Promise.all(promises).then(() => ({ after, before }));
211
151
  }
212
152
 
213
153
  function main(): void {
214
- let args = process.argv.slice(2),
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 plugins = getPlugins(tsconfig);
160
+ let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
223
161
 
224
- if (plugins.length === 0) {
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 passthrough(): void {
238
- let args = process.argv.slice(2),
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 resolveExport(exportValue: ExportValue): string | null {
252
- if (typeof exportValue === 'string') {
253
- return exportValue;
254
- }
182
+ function passthrough(): void {
183
+ let args = process.argv.slice(2);
255
184
 
256
- if (exportValue && typeof exportValue === 'object') {
257
- return exportValue.import ?? exportValue.default ?? null;
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
- return null;
191
+ process.exit(code ?? 0);
192
+ });
261
193
  }
262
194
 
263
- function resolvePlugin(modulePath: string, root: string): string {
264
- if (modulePath.startsWith('.')) {
265
- return pathToFileURL(path.resolve(root, modulePath)).href;
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'), ...process.argv.slice(2)], { stdio: 'inherit' });
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 UUID_DASH_REGEX = /-/g;
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
- UUID_DASH_REGEX,
10
+ UUID_REGEX,
17
11
  };
@@ -1,176 +1,5 @@
1
- import { uuid } from '@esportsplus/utilities';
2
- import { BRACES_CONTENT_REGEX, REGEX_ESCAPE_PATTERN, UUID_DASH_REGEX } from './constants.js';
3
- import type { QuickCheckPattern, Replacement } from './types.js';
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
+ };