@travetto/compiler 3.0.0-rc.11 → 3.0.0-rc.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/trv.js +72 -57
- package/package.json +7 -6
- package/src/compiler.ts +83 -85
- package/src/state.ts +50 -64
- package/src/util.ts +21 -80
- package/support/compiler-entry.ts +2 -0
- package/support/launcher.ts +160 -0
- package/support/transpile.ts +185 -0
- package/tsconfig.trv.json +1 -0
- package/bin/transpile.d.ts +0 -32
- package/bin/transpile.js +0 -227
- package/support/bin/compiler-bootstrap.ts +0 -151
- package/support/bin/utils.ts +0 -116
- package/support/main.output.ts +0 -11
package/src/util.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
-
import fs from 'fs/promises';
|
|
3
|
-
import { readdirSync } from 'fs';
|
|
4
2
|
|
|
5
|
-
import {
|
|
3
|
+
import { ManifestRoot, Package, path } from '@travetto/manifest';
|
|
6
4
|
|
|
7
|
-
type InputToSource = (inputFile: string) => ({ source: string
|
|
5
|
+
type InputToSource = (inputFile: string) => ({ source: string } | undefined);
|
|
8
6
|
export type FileWatchEvent = { type: 'create' | 'delete' | 'update', path: string };
|
|
9
7
|
|
|
10
8
|
const nativeCwd = process.cwd();
|
|
@@ -14,6 +12,15 @@ const nativeCwd = process.cwd();
|
|
|
14
12
|
*/
|
|
15
13
|
export class CompilerUtil {
|
|
16
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Map input file to output format, generally converting ts extensions to js
|
|
17
|
+
* @param file
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
static inputToOutput(file: string): string {
|
|
21
|
+
return file.replace(/[.][tj]s$/, '.js');
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
/**
|
|
18
25
|
* Determines if write callback data has sourcemap information
|
|
19
26
|
* @param data
|
|
@@ -27,14 +34,14 @@ export class CompilerUtil {
|
|
|
27
34
|
* Rewrite's sourcemap locations to real folders
|
|
28
35
|
* @returns
|
|
29
36
|
*/
|
|
30
|
-
static rewriteSourceMap(text: string, inputToSource: InputToSource): string {
|
|
37
|
+
static rewriteSourceMap(root: string, text: string, inputToSource: InputToSource): string {
|
|
31
38
|
const data: { sourceRoot: string, sources: string[] } = JSON.parse(text);
|
|
32
|
-
const
|
|
39
|
+
const src = path.resolve(data.sourceRoot, data.sources[0]);
|
|
33
40
|
|
|
34
|
-
const { source: file
|
|
35
|
-
if (file
|
|
36
|
-
data.sourceRoot =
|
|
37
|
-
data.sources = [file
|
|
41
|
+
const { source: file } = inputToSource(src) ?? {};
|
|
42
|
+
if (file) {
|
|
43
|
+
data.sourceRoot = root;
|
|
44
|
+
data.sources = [file];
|
|
38
45
|
text = JSON.stringify(data);
|
|
39
46
|
}
|
|
40
47
|
|
|
@@ -49,13 +56,14 @@ export class CompilerUtil {
|
|
|
49
56
|
* @returns
|
|
50
57
|
*/
|
|
51
58
|
static rewriteInlineSourceMap(
|
|
59
|
+
root: string,
|
|
52
60
|
text: string,
|
|
53
61
|
inputToSource: InputToSource,
|
|
54
62
|
{ sourceMapUrlPos }: ts.WriteFileCallbackData & { sourceMapUrlPos: number }
|
|
55
63
|
): string {
|
|
56
64
|
const sourceMapUrl = text.substring(sourceMapUrlPos);
|
|
57
65
|
const [prefix, sourceMapData] = sourceMapUrl.split('base64,');
|
|
58
|
-
const rewritten = this.rewriteSourceMap(Buffer.from(sourceMapData, 'base64url').toString('utf8'), inputToSource);
|
|
66
|
+
const rewritten = this.rewriteSourceMap(root, Buffer.from(sourceMapData, 'base64url').toString('utf8'), inputToSource);
|
|
59
67
|
return [
|
|
60
68
|
text.substring(0, sourceMapUrlPos),
|
|
61
69
|
prefix,
|
|
@@ -74,10 +82,10 @@ export class CompilerUtil {
|
|
|
74
82
|
static rewritePackageJSON(manifest: ManifestRoot, text: string, opts: ts.CompilerOptions): string {
|
|
75
83
|
const pkg: Package = JSON.parse(text);
|
|
76
84
|
if (pkg.files) {
|
|
77
|
-
pkg.files = pkg.files.map(x =>
|
|
85
|
+
pkg.files = pkg.files.map(x => this.inputToOutput(x));
|
|
78
86
|
}
|
|
79
87
|
if (pkg.main) {
|
|
80
|
-
pkg.main = pkg.main
|
|
88
|
+
pkg.main = this.inputToOutput(pkg.main);
|
|
81
89
|
}
|
|
82
90
|
pkg.type = opts.module !== ts.ModuleKind.CommonJS ? 'module' : 'commonjs';
|
|
83
91
|
for (const key of ['devDependencies', 'dependencies', 'peerDependencies'] as const) {
|
|
@@ -92,20 +100,6 @@ export class CompilerUtil {
|
|
|
92
100
|
return JSON.stringify(pkg, null, 2);
|
|
93
101
|
}
|
|
94
102
|
|
|
95
|
-
/**
|
|
96
|
-
* Read the given tsconfig.json values for the project
|
|
97
|
-
* @param path
|
|
98
|
-
* @returns
|
|
99
|
-
*/
|
|
100
|
-
static async readTsConfigOptions(file: string): Promise<ts.CompilerOptions> {
|
|
101
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
102
|
-
const { options } = ts.parseJsonSourceFileConfigFileContent(
|
|
103
|
-
ts.readJsonConfigFile(file, ts.sys.readFile), ts.sys, nativeCwd
|
|
104
|
-
);
|
|
105
|
-
options.target = ts.ScriptTarget.ESNext;
|
|
106
|
-
return options;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
103
|
/**
|
|
110
104
|
* Build transpilation error
|
|
111
105
|
* @param filename The name of the file
|
|
@@ -133,59 +127,6 @@ export class CompilerUtil {
|
|
|
133
127
|
return new Error(`Transpiling ${filename.replace(nativeCwd, '.')} failed: \n${errors.join('\n')}`);
|
|
134
128
|
}
|
|
135
129
|
|
|
136
|
-
/**
|
|
137
|
-
* Allows for watching of explicit folders
|
|
138
|
-
*
|
|
139
|
-
* @param onEvent
|
|
140
|
-
* @returns
|
|
141
|
-
*/
|
|
142
|
-
static async fileWatcher(
|
|
143
|
-
folders: string[],
|
|
144
|
-
onEvent: (ev: FileWatchEvent, folder: string) => void
|
|
145
|
-
): Promise<() => Promise<void>> {
|
|
146
|
-
const watcher = await import('@parcel/watcher');
|
|
147
|
-
const subs: (() => Promise<void>)[] = [];
|
|
148
|
-
for (const folder of folders) {
|
|
149
|
-
const sub = await watcher.subscribe(folder, (err, events) => {
|
|
150
|
-
for (const ev of events) {
|
|
151
|
-
onEvent(ev, folder);
|
|
152
|
-
}
|
|
153
|
-
}, { ignore: ['node_modules', ...readdirSync(folder).filter(x => x.startsWith('.') && x.length > 2)] });
|
|
154
|
-
subs.push(() => sub.unsubscribe());
|
|
155
|
-
}
|
|
156
|
-
const readiedSubs = await Promise.all(subs);
|
|
157
|
-
return () => Promise.all(readiedSubs.map(s => s())).then(() => { });
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Get loaded compiler options
|
|
162
|
-
*/
|
|
163
|
-
static async getCompilerOptions(outputFolder: string, bootTsConfig: string, workspace: string): Promise<ts.CompilerOptions> {
|
|
164
|
-
const opts: Partial<ts.CompilerOptions> = {};
|
|
165
|
-
const rootDir = nativeCwd;
|
|
166
|
-
const projTsconfig = path.resolve('tsconfig.json');
|
|
167
|
-
// Fallback to base tsconfig if not found in local folder
|
|
168
|
-
const config = (await fs.stat(projTsconfig).catch(() => false)) ? projTsconfig : bootTsConfig;
|
|
169
|
-
const base = await this.readTsConfigOptions(config);
|
|
170
|
-
|
|
171
|
-
const { type } = PackageUtil.readPackage(workspace);
|
|
172
|
-
|
|
173
|
-
if (type !== undefined) {
|
|
174
|
-
base.module = `${type}`.toLowerCase() === 'commonjs' ? ts.ModuleKind.CommonJS : ts.ModuleKind.ESNext;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return {
|
|
178
|
-
...base,
|
|
179
|
-
resolveJsonModule: true,
|
|
180
|
-
allowJs: true,
|
|
181
|
-
outDir: outputFolder,
|
|
182
|
-
sourceRoot: rootDir,
|
|
183
|
-
...opts,
|
|
184
|
-
rootDir,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
130
|
/**
|
|
190
131
|
* Naive hashing
|
|
191
132
|
*/
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { Module } from 'module';
|
|
4
|
+
|
|
5
|
+
import type { ManifestContext } from '@travetto/manifest';
|
|
6
|
+
import { TranspileUtil } from './transpile';
|
|
7
|
+
|
|
8
|
+
const SOURCE_SEED = ['package.json', 'index.ts', '__index__.ts', 'src', 'support', 'bin'];
|
|
9
|
+
const PRECOMPILE_MODS = ['@travetto/terminal', '@travetto/manifest', '@travetto/transformer', '@travetto/compiler'];
|
|
10
|
+
|
|
11
|
+
const importManifest = (ctx: ManifestContext): Promise<typeof import('@travetto/manifest')> =>
|
|
12
|
+
import(path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', '@travetto/manifest/__index__.js'));
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Recompile folder if stale
|
|
16
|
+
*/
|
|
17
|
+
async function compileIfStale(ctx: ManifestContext, scope: string, mod: string, seed: string[]): Promise<string[]> {
|
|
18
|
+
const files = await TranspileUtil.getModuleSources(ctx, mod, seed);
|
|
19
|
+
const changes = files.filter(x => x.stale).map(x => x.input);
|
|
20
|
+
const out: string[] = [];
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
await TranspileUtil.withLogger(scope, { args: [mod], basic: false }, async log => {
|
|
24
|
+
if (files.some(f => f.stale)) {
|
|
25
|
+
log('debug', 'Starting');
|
|
26
|
+
for (const file of files.filter(x => x.stale)) {
|
|
27
|
+
await TranspileUtil.transpileFile(ctx, file.input, file.output);
|
|
28
|
+
}
|
|
29
|
+
if (changes.length) {
|
|
30
|
+
out.push(...changes.map(x => `${mod}/${x}`));
|
|
31
|
+
log('debug', `Source changed: ${changes.join(', ')}`);
|
|
32
|
+
}
|
|
33
|
+
log('debug', 'Completed');
|
|
34
|
+
} else {
|
|
35
|
+
log('debug', 'Skipped');
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.error(err);
|
|
40
|
+
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Run the compiler
|
|
46
|
+
*/
|
|
47
|
+
export async function compile(ctx: ManifestContext, op?: 'watch' | 'build'): Promise<void> {
|
|
48
|
+
let changes = 0;
|
|
49
|
+
|
|
50
|
+
await TranspileUtil.withLogger('precompile', async () => {
|
|
51
|
+
for (const mod of PRECOMPILE_MODS) {
|
|
52
|
+
changes += (await compileIfStale(ctx, 'precompile', mod, SOURCE_SEED)).length;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const { ManifestUtil, ManifestDeltaUtil } = await importManifest(ctx);
|
|
57
|
+
|
|
58
|
+
const manifest = await TranspileUtil.withLogger('manifest', async () => ManifestUtil.buildManifest(ctx));
|
|
59
|
+
|
|
60
|
+
await TranspileUtil.withLogger('transformers', async () => {
|
|
61
|
+
for (const mod of Object.values(manifest.modules).filter(m => m.files.$transformer?.length)) {
|
|
62
|
+
changes += (await compileIfStale(ctx, 'transformers', mod.name, ['package.json', ...mod.files.$transformer!.map(x => x[0])])).length;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const delta = await TranspileUtil.withLogger('delta', async log => {
|
|
67
|
+
if (changes) {
|
|
68
|
+
log('debug', 'Skipping, everything changed');
|
|
69
|
+
return [{ type: 'changed', file: '*', module: ctx.mainModule } as const];
|
|
70
|
+
} else {
|
|
71
|
+
return ManifestDeltaUtil.produceDelta(ctx, manifest);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (changes) {
|
|
76
|
+
await fs.rm(path.resolve(ctx.workspacePath, ctx.outputFolder), { recursive: true, force: true });
|
|
77
|
+
TranspileUtil.log('reset', [], 'info', 'Clearing output due to compiler changes');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Write manifest
|
|
81
|
+
await TranspileUtil.withLogger('manifest', async log => {
|
|
82
|
+
await ManifestUtil.writeManifest(ctx, manifest);
|
|
83
|
+
log('debug', `Wrote manifest ${ctx.mainModule}`);
|
|
84
|
+
|
|
85
|
+
// Update all manifests
|
|
86
|
+
if (delta.length && ctx.monoRepo && !ctx.mainFolder) {
|
|
87
|
+
const names: string[] = [];
|
|
88
|
+
const mods = Object.values(manifest.modules).filter(x => x.local && x.name !== ctx.mainModule);
|
|
89
|
+
for (const mod of mods) {
|
|
90
|
+
await ManifestUtil.rewriteManifest(path.resolve(ctx.workspacePath, mod.sourceFolder));
|
|
91
|
+
names.push(mod.name);
|
|
92
|
+
}
|
|
93
|
+
log('debug', `Changes triggered ${delta.map(x => `${x.type}:${x.module}:${x.file}`)}`);
|
|
94
|
+
log('debug', `Rewrote monorepo manifests [changes=${delta.length}] ${names.join(', ')}`);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await TranspileUtil.withLogger('compile', { args: [], basic: false }, async log => {
|
|
99
|
+
const changed = delta.filter(x => x.type === 'added' || x.type === 'changed');
|
|
100
|
+
log('debug', `Started action=${op} changed=${changed.map(x => `${x.module}/${x.file}`)}`);
|
|
101
|
+
if (changed.length || op === 'watch') {
|
|
102
|
+
await TranspileUtil.runCompiler(ctx, manifest, changed, op === 'watch');
|
|
103
|
+
log('debug', 'Finished');
|
|
104
|
+
} else {
|
|
105
|
+
log('debug', 'Skipped');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (op === 'build') {
|
|
110
|
+
TranspileUtil.log('build', [], 'info', 'Successfully built');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Export manifests
|
|
116
|
+
*/
|
|
117
|
+
export async function exportManifest(ctx: ManifestContext, output?: string, env = 'dev'): Promise<string | undefined> {
|
|
118
|
+
const { ManifestUtil } = await importManifest(ctx);
|
|
119
|
+
const manifest = await ManifestUtil.buildManifest(ctx);
|
|
120
|
+
|
|
121
|
+
// If in prod mode, only include std modules
|
|
122
|
+
if (/^prod/i.test(env)) {
|
|
123
|
+
manifest.modules = Object.fromEntries(
|
|
124
|
+
Object.values(manifest.modules)
|
|
125
|
+
.filter(x => x.profiles.includes('std'))
|
|
126
|
+
.map(m => [m.name, m])
|
|
127
|
+
);
|
|
128
|
+
// Mark output folder/workspace path as portable
|
|
129
|
+
manifest.outputFolder = '';
|
|
130
|
+
manifest.workspacePath = '';
|
|
131
|
+
}
|
|
132
|
+
if (output) {
|
|
133
|
+
if (!output.endsWith('.json')) {
|
|
134
|
+
output = path.resolve(output, 'manifest.json');
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
await TranspileUtil.writeTextFile(output, JSON.stringify(manifest));
|
|
138
|
+
TranspileUtil.log('manifest', [], 'info', `Wrote manifest ${output}`);
|
|
139
|
+
return output;
|
|
140
|
+
} else {
|
|
141
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export async function launchMain(ctx: ManifestContext): Promise<void> {
|
|
147
|
+
// Rewriting node_path
|
|
148
|
+
const nodeOut = path.resolve(ctx.workspacePath, ctx.outputFolder, 'node_modules');
|
|
149
|
+
const og = process.env.NODE_PATH;
|
|
150
|
+
process.env.NODE_PATH = [nodeOut, og].join(path.delimiter);
|
|
151
|
+
// @ts-expect-error
|
|
152
|
+
Module._initPaths();
|
|
153
|
+
process.env.NODE_PATH = og; // Restore
|
|
154
|
+
|
|
155
|
+
process.env.TRV_MANIFEST = path.resolve(nodeOut, ctx.mainModule);
|
|
156
|
+
|
|
157
|
+
// TODO: Externalize somehow?
|
|
158
|
+
const cliMain = path.join(nodeOut, '@travetto/cli/support/cli.js');
|
|
159
|
+
return await import(cliMain);
|
|
160
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import cp from 'child_process';
|
|
5
|
+
import { createRequire } from 'module';
|
|
6
|
+
|
|
7
|
+
import { DeltaEvent, ManifestContext, ManifestRoot, Package } from '@travetto/manifest';
|
|
8
|
+
|
|
9
|
+
type ModFile = { input: string, output: string, stale: boolean };
|
|
10
|
+
|
|
11
|
+
const SRC_REQ = createRequire(path.resolve('node_modules'));
|
|
12
|
+
const recentStat = (stat: { ctimeMs: number, mtimeMs: number }): number => Math.max(stat.ctimeMs, stat.mtimeMs);
|
|
13
|
+
|
|
14
|
+
export type CompilerLogEvent = [level: 'info' | 'debug' | 'warn', message: string];
|
|
15
|
+
type WithLogger<T> = (log: (...ev: CompilerLogEvent) => void) => Promise<T>;
|
|
16
|
+
type LogConfig = { args?: string[], basic?: boolean };
|
|
17
|
+
const isCompilerLogEvent = (o: unknown): o is CompilerLogEvent => o !== null && o !== undefined && Array.isArray(o);
|
|
18
|
+
|
|
19
|
+
const LEVELS = { warn: true, debug: /^debug$/.test(process.env.TRV_BUILD ?? ''), info: !/^warn$/.test(process.env.TRV_BUILD ?? '') };
|
|
20
|
+
const SCOPE_MAX = 15;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Transpile utilities for launching
|
|
24
|
+
*/
|
|
25
|
+
export class TranspileUtil {
|
|
26
|
+
static #optCache: Record<string, {}> = {};
|
|
27
|
+
|
|
28
|
+
static log(scope: string, args: string[], ...[level, msg]: CompilerLogEvent): void {
|
|
29
|
+
const message = msg.replaceAll(process.cwd(), '.');
|
|
30
|
+
LEVELS[level] && console.debug(new Date().toISOString(), `[${scope.padEnd(SCOPE_MAX, ' ')}]`, ...args, message);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* With logger
|
|
35
|
+
*/
|
|
36
|
+
static withLogger<T>(scope: string, op: WithLogger<T>): Promise<T>;
|
|
37
|
+
static withLogger<T>(scope: string, opts: LogConfig, op: WithLogger<T>): Promise<T>;
|
|
38
|
+
static withLogger<T>(scope: string, opts: LogConfig | WithLogger<T>, op?: WithLogger<T>): Promise<T> {
|
|
39
|
+
const cfg = { basic: true, ...typeof opts === 'function' ? {} : opts };
|
|
40
|
+
const go = typeof opts === 'function' ? opts : op!;
|
|
41
|
+
const log = this.log.bind(null, scope, cfg.args ?? []);
|
|
42
|
+
cfg.basic && log('debug', 'Started');
|
|
43
|
+
return go(log).finally(() => cfg.basic && log('debug', 'Completed'));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Write text file, and ensure folder exists
|
|
48
|
+
*/
|
|
49
|
+
static writeTextFile = (file: string, content: string): Promise<void> =>
|
|
50
|
+
fs.mkdir(path.dirname(file), { recursive: true }).then(() => fs.writeFile(file, content));
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Returns the compiler options
|
|
54
|
+
*/
|
|
55
|
+
static async getCompilerOptions(ctx: ManifestContext): Promise<{}> {
|
|
56
|
+
if (!(ctx.workspacePath in this.#optCache)) {
|
|
57
|
+
let tsconfig = path.resolve(ctx.workspacePath, 'tsconfig.json');
|
|
58
|
+
|
|
59
|
+
if (!await fs.stat(tsconfig).then(_ => true, _ => false)) {
|
|
60
|
+
tsconfig = SRC_REQ.resolve('@travetto/compiler/tsconfig.trv.json');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const ts = (await import('typescript')).default;
|
|
64
|
+
|
|
65
|
+
const { options } = ts.parseJsonSourceFileConfigFileContent(
|
|
66
|
+
ts.readJsonConfigFile(tsconfig, ts.sys.readFile), ts.sys, ctx.workspacePath
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
options.allowJs = true;
|
|
70
|
+
options.resolveJsonModule = true;
|
|
71
|
+
options.sourceRoot = ctx.workspacePath;
|
|
72
|
+
options.rootDir = ctx.workspacePath;
|
|
73
|
+
options.outDir = path.resolve(ctx.workspacePath);
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
options.module = ctx.moduleType === 'commonjs' ? ts.ModuleKind.CommonJS : ts.ModuleKind.ESNext;
|
|
77
|
+
} catch { }
|
|
78
|
+
|
|
79
|
+
this.#optCache[ctx.workspacePath] = options;
|
|
80
|
+
}
|
|
81
|
+
return this.#optCache[ctx.workspacePath];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Output a file, support for ts, js, and package.json
|
|
86
|
+
*/
|
|
87
|
+
static async transpileFile(ctx: ManifestContext, inputFile: string, outputFile: string): Promise<void> {
|
|
88
|
+
if (inputFile.endsWith('.ts') || inputFile.endsWith('.js')) {
|
|
89
|
+
const compilerOut = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules');
|
|
90
|
+
|
|
91
|
+
const text = (await fs.readFile(inputFile, 'utf8'))
|
|
92
|
+
.replace(/from '([.][^']+)'/g, (_, i) => `from '${i.replace(/[.]js$/, '')}.js'`)
|
|
93
|
+
.replace(/from '(@travetto\/(.*?))'/g, (_, i, s) => `from '${path.resolve(compilerOut, `${i}${s.includes('/') ? '.js' : '/__index__.js'}`)}'`);
|
|
94
|
+
|
|
95
|
+
const ts = (await import('typescript')).default;
|
|
96
|
+
const content = ts.transpile(text, await this.getCompilerOptions(ctx), inputFile);
|
|
97
|
+
await this.writeTextFile(outputFile, content);
|
|
98
|
+
} else if (inputFile.endsWith('package.json')) {
|
|
99
|
+
const pkg: Package = JSON.parse(await fs.readFile(inputFile, 'utf8'));
|
|
100
|
+
const main = pkg.main?.replace(/[.]ts$/, '.js');
|
|
101
|
+
const files = pkg.files?.map(x => x.replace('.ts', '.js'));
|
|
102
|
+
|
|
103
|
+
const content = JSON.stringify({ ...pkg, main, type: ctx.moduleType, files }, null, 2);
|
|
104
|
+
await this.writeTextFile(outputFile, content);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Scan directory to find all project sources for comparison
|
|
110
|
+
*/
|
|
111
|
+
static async getModuleSources(ctx: ManifestContext, module: string, seed: string[]): Promise<ModFile[]> {
|
|
112
|
+
const inputFolder = (ctx.mainModule === module) ?
|
|
113
|
+
process.cwd() :
|
|
114
|
+
path.dirname(SRC_REQ.resolve(`${module}/package.json`));
|
|
115
|
+
|
|
116
|
+
const folders = seed.filter(x => !/[.]/.test(x)).map(x => path.resolve(inputFolder, x));
|
|
117
|
+
const files = seed.filter(x => /[.]/.test(x)).map(x => path.resolve(inputFolder, x));
|
|
118
|
+
|
|
119
|
+
while (folders.length) {
|
|
120
|
+
const sub = folders.pop();
|
|
121
|
+
if (!sub) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (const file of await fs.readdir(sub).catch(() => [])) {
|
|
126
|
+
if (file.startsWith('.')) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const resolvedInput = path.resolve(sub, file);
|
|
130
|
+
const stat = await fs.stat(resolvedInput);
|
|
131
|
+
|
|
132
|
+
if (stat.isDirectory()) {
|
|
133
|
+
folders.push(resolvedInput);
|
|
134
|
+
} else if (file.endsWith('.d.ts')) {
|
|
135
|
+
// Do nothing
|
|
136
|
+
} else if (file.endsWith('.ts') || file.endsWith('.js')) {
|
|
137
|
+
files.push(resolvedInput);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const outputFolder = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', module);
|
|
143
|
+
const out: ModFile[] = [];
|
|
144
|
+
for (const input of files) {
|
|
145
|
+
const output = input.replace(inputFolder, outputFolder).replace(/[.]ts$/, '.js');
|
|
146
|
+
const inputTs = await fs.stat(input).then(recentStat, () => 0);
|
|
147
|
+
if (inputTs) {
|
|
148
|
+
const outputTs = await fs.stat(output).then(recentStat, () => 0);
|
|
149
|
+
await fs.mkdir(path.dirname(output), { recursive: true, });
|
|
150
|
+
out.push({ input, output, stale: inputTs > outputTs });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return out;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Run compiler
|
|
159
|
+
*/
|
|
160
|
+
static async runCompiler(ctx: ManifestContext, manifest: ManifestRoot, changed: DeltaEvent[], watch = false): Promise<void> {
|
|
161
|
+
const compiler = path.resolve(ctx.workspacePath, ctx.compilerFolder);
|
|
162
|
+
const main = path.resolve(compiler, 'node_modules', '@travetto/compiler/support/compiler-entry.js');
|
|
163
|
+
const deltaFile = path.resolve(os.tmpdir(), `manifest-delta.${Date.now()}.${Math.random()}.json`);
|
|
164
|
+
|
|
165
|
+
const changedFiles = changed[0]?.file === '*' ? ['*'] : changed.map(ev =>
|
|
166
|
+
path.resolve(manifest.workspacePath, manifest.modules[ev.module].sourceFolder, ev.file)
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
await this.writeTextFile(deltaFile, changedFiles.join('\n'));
|
|
170
|
+
|
|
171
|
+
await this.withLogger('compiler-exec', async log => {
|
|
172
|
+
await new Promise((res, rej) =>
|
|
173
|
+
cp.spawn(process.argv0, [main, deltaFile, `${watch}`], {
|
|
174
|
+
env: {
|
|
175
|
+
...process.env,
|
|
176
|
+
TRV_MANIFEST: path.resolve(ctx.workspacePath, ctx.outputFolder, 'node_modules', ctx.mainModule),
|
|
177
|
+
},
|
|
178
|
+
stdio: [0, 1, 2, 'ipc'],
|
|
179
|
+
})
|
|
180
|
+
.on('message', msg => isCompilerLogEvent(msg) && log(...msg))
|
|
181
|
+
.on('exit', code => (code !== null && code > 0) ? rej() : res(null))
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
package/tsconfig.trv.json
CHANGED
package/bin/transpile.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { ManifestContext, Package } from '@travetto/manifest';
|
|
2
|
-
|
|
3
|
-
declare namespace Transpile {
|
|
4
|
-
type CompileCommand = 'build' | 'watch' | 'clean' | 'manifest';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Writes a package json file
|
|
8
|
-
*/
|
|
9
|
-
function writePackageJson(ctx: ManifestContext, inputFile: string, outputFile: string, transform?: (pkg: Package) => Package): Promise<void>;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Transpiles a file
|
|
13
|
-
*/
|
|
14
|
-
function transpileFile(ctx: ManifestContext, inputFile: string, outputFile: string): Promise<void>;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Write js file
|
|
18
|
-
*/
|
|
19
|
-
function writeJsFile(ctx: ManifestContext, inputFile: string, outputFile: string): Promise<void>;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Build an entire package
|
|
23
|
-
*/
|
|
24
|
-
function buildPackage(ctx: ManifestContext, name: string, sourcePath: string, mainSource: string, extraSource: string[]): Promise<string>;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Get Context for building
|
|
28
|
-
*/
|
|
29
|
-
function getContext(folder?: string): Promise<ManifestContext>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export = Transpile;
|