@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 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
- let require = createRequire(import.meta.url), skipFlags = ['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v'];
8
- async function build(tsconfig, plugins) {
9
- let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile), root = path.dirname(path.resolve(tsconfig));
10
- if (error) {
11
- console.error(ts.flattenDiagnosticMessageText(error.messageText, '\n'));
12
- process.exit(1);
13
- }
14
- let parsed = ts.parseJsonConfigFileContent(config, ts.sys, root);
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 resolved = path.resolve(fileName), transformed = transformedFiles.get(resolved);
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 = ts.getPreEmitDiagnostics(program).concat(program.emit().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 (program.emit().emitSkipped) {
53
+ if (emitSkipped) {
62
54
  process.exit(1);
63
55
  }
64
- if (shouldRunTscAlias(process.argv.slice(2))) {
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 = [], afterDeclarations = [], before = [], promises = [];
60
+ let after = [], before = [], promises = [];
101
61
  for (let i = 0, n = plugins.length; i < n; i++) {
102
- let plugin = plugins[i];
103
- 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) => {
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.afterDeclarations) {
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, afterDeclarations, before }));
83
+ return Promise.all(promises).then(() => ({ after, before }));
121
84
  }
122
85
  function main() {
123
- let args = process.argv.slice(2), tsconfig = findTsconfig(args);
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 plugins = getPlugins(tsconfig);
129
- if (plugins.length === 0) {
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), child = spawn(process.execPath, [require.resolve('typescript/lib/tsc.js'), ...args], { stdio: 'inherit' });
141
- child.on('exit', (code) => {
142
- if (code === 0 && shouldRunTscAlias(args)) {
143
- runTscAlias().then((aliasCode) => process.exit(aliasCode ?? 0));
144
- 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);
145
110
  }
146
111
  process.exit(code ?? 0);
147
112
  });
148
113
  }
149
- function resolveExport(exportValue) {
150
- if (typeof exportValue === 'string') {
151
- return exportValue;
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'), ...process.argv.slice(2)], { stdio: 'inherit' });
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 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.3",
37
+ "version": "0.17.5",
38
38
  "scripts": {
39
39
  "build": "tsc && tsc-alias",
40
40
  "-": "-"
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
- let require = createRequire(import.meta.url),
22
- skipFlags = ['--help', '--init', '--noEmit', '--showConfig', '--version', '-h', '-noEmit', '-v'];
17
+ const BACKSLASH_REGEX = /\\/g;
23
18
 
24
19
 
25
- async function build(tsconfig: string, plugins: PluginConfig[]): Promise<void> {
26
- let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile),
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
- 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);
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(ts.flattenDiagnosticMessageText(parsed.errors[i].messageText, '\n'));
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 resolved = path.resolve(fileName),
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 = ts.getPreEmitDiagnostics(program).concat(program.emit().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 (program.emit().emitSkipped) {
104
+ if (emitSkipped) {
116
105
  process.exit(1);
117
106
  }
118
107
 
119
- if (shouldRunTscAlias(process.argv.slice(2))) {
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(resolvePlugin(plugin.transform, root)).then((module) => {
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.afterDeclarations) {
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, afterDeclarations, before }));
150
+ return Promise.all(promises).then(() => ({ after, before }));
205
151
  }
206
152
 
207
153
  function main(): void {
208
- let args = process.argv.slice(2),
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 plugins = getPlugins(tsconfig);
160
+ let { config, error } = ts.readConfigFile(tsconfig, ts.sys.readFile);
217
161
 
218
- if (plugins.length === 0) {
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 passthrough(): void {
232
- let args = process.argv.slice(2),
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 resolveExport(exportValue: ExportValue): string | null {
246
- if (typeof exportValue === 'string') {
247
- return exportValue;
248
- }
182
+ function passthrough(): void {
183
+ let args = process.argv.slice(2);
249
184
 
250
- if (exportValue && typeof exportValue === 'object') {
251
- return exportValue.import ?? exportValue.default ?? null;
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
- return null;
191
+ process.exit(code ?? 0);
192
+ });
255
193
  }
256
194
 
257
- function resolvePlugin(modulePath: string, root: string): string {
258
- if (modulePath.startsWith('.')) {
259
- return pathToFileURL(path.resolve(root, modulePath)).href;
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'), ...process.argv.slice(2)], { stdio: 'inherit' });
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 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
+ };