@travetto/compiler 3.0.0-rc.11 → 3.0.0-rc.13
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 +50 -64
- package/package.json +7 -6
- package/src/compiler.ts +83 -85
- package/src/state.ts +50 -64
- package/src/util.ts +23 -82
- package/support/compiler-entry.ts +2 -0
- package/support/launcher.ts +159 -0
- package/support/transpile.ts +176 -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,
|
|
@@ -71,15 +79,15 @@ export class CompilerUtil {
|
|
|
71
79
|
* @param text
|
|
72
80
|
* @returns
|
|
73
81
|
*/
|
|
74
|
-
static rewritePackageJSON(manifest: ManifestRoot, text: string
|
|
82
|
+
static rewritePackageJSON(manifest: ManifestRoot, text: string): 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
|
-
pkg.type =
|
|
90
|
+
pkg.type = manifest.moduleType;
|
|
83
91
|
for (const key of ['devDependencies', 'dependencies', 'peerDependencies'] as const) {
|
|
84
92
|
if (key in pkg) {
|
|
85
93
|
for (const dep of Object.keys(pkg[key] ?? {})) {
|
|
@@ -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,159 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import type { ManifestContext } from '@travetto/manifest';
|
|
5
|
+
import { TranspileUtil } from './transpile';
|
|
6
|
+
|
|
7
|
+
const SOURCE_SEED = ['package.json', 'index.ts', '__index__.ts', 'src', 'support', 'bin'];
|
|
8
|
+
const PRECOMPILE_MODS = ['@travetto/terminal', '@travetto/manifest', '@travetto/transformer', '@travetto/compiler'];
|
|
9
|
+
|
|
10
|
+
const importManifest = (ctx: ManifestContext): Promise<typeof import('@travetto/manifest')> =>
|
|
11
|
+
import(path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', '@travetto/manifest/__index__.js'));
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Recompile folder if stale
|
|
15
|
+
*/
|
|
16
|
+
async function compileIfStale(ctx: ManifestContext, scope: string, mod: string, seed: string[]): Promise<string[]> {
|
|
17
|
+
const files = await TranspileUtil.getModuleSources(ctx, mod, seed);
|
|
18
|
+
const changes = files.filter(x => x.stale).map(x => x.input);
|
|
19
|
+
const out: string[] = [];
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
await TranspileUtil.withLogger(scope, async log => {
|
|
23
|
+
if (files.some(f => f.stale)) {
|
|
24
|
+
log('debug', 'Starting');
|
|
25
|
+
for (const file of files.filter(x => x.stale)) {
|
|
26
|
+
await TranspileUtil.transpileFile(ctx, file.input, file.output);
|
|
27
|
+
}
|
|
28
|
+
if (changes.length) {
|
|
29
|
+
out.push(...changes.map(x => `${mod}/${x}`));
|
|
30
|
+
log('debug', `Source changed: ${changes.join(', ')}`);
|
|
31
|
+
}
|
|
32
|
+
log('debug', 'Completed');
|
|
33
|
+
} else {
|
|
34
|
+
log('debug', 'Skipped');
|
|
35
|
+
}
|
|
36
|
+
}, false, [mod]);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error(err);
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Run the compiler
|
|
45
|
+
*/
|
|
46
|
+
async function compile(ctx: ManifestContext, op?: 'watch' | 'build'): Promise<void> {
|
|
47
|
+
let changes = 0;
|
|
48
|
+
|
|
49
|
+
await TranspileUtil.withLogger('precompile', async () => {
|
|
50
|
+
for (const mod of PRECOMPILE_MODS) {
|
|
51
|
+
changes += (await compileIfStale(ctx, 'precompile', mod, SOURCE_SEED)).length;
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const { ManifestUtil, ManifestDeltaUtil } = await importManifest(ctx);
|
|
56
|
+
|
|
57
|
+
const manifest = await TranspileUtil.withLogger('manifest', async () => ManifestUtil.buildManifest(ctx));
|
|
58
|
+
|
|
59
|
+
await TranspileUtil.withLogger('transformers', async () => {
|
|
60
|
+
for (const mod of Object.values(manifest.modules).filter(m => m.files.$transformer?.length)) {
|
|
61
|
+
changes += (await compileIfStale(ctx, 'transformers', mod.name, ['package.json', ...mod.files.$transformer!.map(x => x[0])])).length;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const delta = await TranspileUtil.withLogger('delta', async log => {
|
|
66
|
+
if (changes) {
|
|
67
|
+
log('debug', 'Skipping, everything changed');
|
|
68
|
+
return [{ type: 'changed', file: '*', module: ctx.mainModule } as const];
|
|
69
|
+
} else {
|
|
70
|
+
return ManifestDeltaUtil.produceDelta(ctx, manifest);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (changes) {
|
|
75
|
+
await TranspileUtil.withLogger('reset', async log => {
|
|
76
|
+
await fs.rm(path.resolve(ctx.workspacePath, ctx.outputFolder), { recursive: true, force: true });
|
|
77
|
+
log('info', 'Clearing output due to compiler changes');
|
|
78
|
+
}, false);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Write manifest
|
|
82
|
+
await TranspileUtil.withLogger('manifest', async log => {
|
|
83
|
+
await ManifestUtil.writeManifest(ctx, manifest);
|
|
84
|
+
log('debug', `Wrote manifest ${ctx.mainModule}`);
|
|
85
|
+
|
|
86
|
+
// Update all manifests
|
|
87
|
+
if (delta.length && ctx.monoRepo && !ctx.mainFolder) {
|
|
88
|
+
const names: string[] = [];
|
|
89
|
+
const mods = Object.values(manifest.modules).filter(x => x.local && x.name !== ctx.mainModule);
|
|
90
|
+
for (const mod of mods) {
|
|
91
|
+
await ManifestUtil.rewriteManifest(path.resolve(ctx.workspacePath, mod.sourceFolder));
|
|
92
|
+
names.push(mod.name);
|
|
93
|
+
}
|
|
94
|
+
log('debug', `Changes triggered ${delta.map(x => `${x.type}:${x.module}:${x.file}`)}`);
|
|
95
|
+
log('debug', `Rewrote monorepo manifests [changes=${delta.length}] ${names.join(', ')}`);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await TranspileUtil.withLogger('compile', async log => {
|
|
100
|
+
const changed = delta.filter(x => x.type === 'added' || x.type === 'changed');
|
|
101
|
+
log('debug', `Started action=${op} changed=${changed.map(x => `${x.module}/${x.file}`)}`);
|
|
102
|
+
if (changed.length || op === 'watch') {
|
|
103
|
+
await TranspileUtil.runCompiler(ctx, manifest, changed, op === 'watch');
|
|
104
|
+
log('debug', 'Finished');
|
|
105
|
+
} else {
|
|
106
|
+
log('debug', 'Skipped');
|
|
107
|
+
}
|
|
108
|
+
}, false);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Export manifests
|
|
113
|
+
*/
|
|
114
|
+
async function exportManifest(ctx: ManifestContext, output?: string, env = 'dev'): Promise<void> {
|
|
115
|
+
const { ManifestUtil } = await importManifest(ctx);
|
|
116
|
+
const manifest = await ManifestUtil.buildManifest(ctx);
|
|
117
|
+
|
|
118
|
+
// If in prod mode, only include std modules
|
|
119
|
+
if (/^prod/i.test(env)) {
|
|
120
|
+
manifest.modules = Object.fromEntries(
|
|
121
|
+
Object.values(manifest.modules)
|
|
122
|
+
.filter(x => x.profiles.includes('std'))
|
|
123
|
+
.map(m => [m.name, m])
|
|
124
|
+
);
|
|
125
|
+
// Mark output folder/workspace path as portable
|
|
126
|
+
manifest.outputFolder = '';
|
|
127
|
+
manifest.workspacePath = '';
|
|
128
|
+
}
|
|
129
|
+
if (output) {
|
|
130
|
+
if (!output.endsWith('.json')) {
|
|
131
|
+
output = path.resolve(output, 'manifest.json');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
await TranspileUtil.writeTextFile(output, JSON.stringify(manifest));
|
|
135
|
+
TranspileUtil.log('manifest', [], 'info', `Wrote manifest ${output}`);
|
|
136
|
+
} else {
|
|
137
|
+
console.log(JSON.stringify(manifest, null, 2));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Launch
|
|
143
|
+
*/
|
|
144
|
+
export async function launch(ctx: ManifestContext, op?: 'build' | 'watch' | 'manifest', args: (string | undefined)[] = []): Promise<void> {
|
|
145
|
+
if (op !== 'manifest') {
|
|
146
|
+
await compile(ctx, op);
|
|
147
|
+
}
|
|
148
|
+
switch (op) {
|
|
149
|
+
case 'manifest': return exportManifest(ctx, ...args);
|
|
150
|
+
case 'build': return TranspileUtil.log('build', [], 'info', 'Successfully built');
|
|
151
|
+
case undefined: {
|
|
152
|
+
// TODO: Externalize somehow?
|
|
153
|
+
const outputPath = path.resolve(ctx.workspacePath, ctx.outputFolder);
|
|
154
|
+
process.env.TRV_MANIFEST = path.resolve(outputPath, 'node_modules', ctx.mainModule);
|
|
155
|
+
const cliMain = path.join(outputPath, 'node_modules', '@travetto/cli/support/cli.js');
|
|
156
|
+
return import(cliMain);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
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
|
+
export type CompilerLogEvent = [level: 'info' | 'debug' | 'warn', message: string];
|
|
10
|
+
type ModFile = { input: string, output: string, stale: boolean };
|
|
11
|
+
type WithLogger<T> = (log: (...ev: CompilerLogEvent) => void) => Promise<T>;
|
|
12
|
+
|
|
13
|
+
const OPT_CACHE: Record<string, import('typescript').CompilerOptions> = {};
|
|
14
|
+
const SRC_REQ = createRequire(path.resolve('node_modules'));
|
|
15
|
+
const LEVELS = { warn: true, debug: /^debug$/.test(process.env.TRV_BUILD ?? ''), info: !/^warn$/.test(process.env.TRV_BUILD ?? '') };
|
|
16
|
+
const SCOPE_MAX = 15;
|
|
17
|
+
const RECENT_STAT = (stat: { ctimeMs: number, mtimeMs: number }): number => Math.max(stat.ctimeMs, stat.mtimeMs);
|
|
18
|
+
const IS_LOG_EV = (o: unknown): o is CompilerLogEvent => o !== null && o !== undefined && Array.isArray(o);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Transpile utilities for launching
|
|
22
|
+
*/
|
|
23
|
+
export class TranspileUtil {
|
|
24
|
+
/**
|
|
25
|
+
* Log message with filtering by level
|
|
26
|
+
*/
|
|
27
|
+
static log(scope: string, args: string[], ...[level, msg]: CompilerLogEvent): void {
|
|
28
|
+
const message = msg.replaceAll(process.cwd(), '.');
|
|
29
|
+
LEVELS[level] && console.debug(new Date().toISOString(), `[${scope.padEnd(SCOPE_MAX, ' ')}]`, ...args, message);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* With logger
|
|
34
|
+
*/
|
|
35
|
+
static withLogger<T>(scope: string, op: WithLogger<T>, basic = true, args: string[] = []): Promise<T> {
|
|
36
|
+
const log = this.log.bind(null, scope, args);
|
|
37
|
+
basic && log('debug', 'Started');
|
|
38
|
+
return op(log).finally(() => basic && log('debug', 'Completed'));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Write text file, and ensure folder exists
|
|
43
|
+
*/
|
|
44
|
+
static writeTextFile = (file: string, content: string): Promise<void> =>
|
|
45
|
+
fs.mkdir(path.dirname(file), { recursive: true }).then(() => fs.writeFile(file, content));
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns the compiler options
|
|
49
|
+
*/
|
|
50
|
+
static async getCompilerOptions(ctx: ManifestContext): Promise<{}> {
|
|
51
|
+
if (!(ctx.workspacePath in OPT_CACHE)) {
|
|
52
|
+
let tsconfig = path.resolve(ctx.workspacePath, 'tsconfig.json');
|
|
53
|
+
|
|
54
|
+
if (!await fs.stat(tsconfig).then(_ => true, _ => false)) {
|
|
55
|
+
tsconfig = SRC_REQ.resolve('@travetto/compiler/tsconfig.trv.json');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const ts = (await import('typescript')).default;
|
|
59
|
+
|
|
60
|
+
const { options } = ts.parseJsonSourceFileConfigFileContent(
|
|
61
|
+
ts.readJsonConfigFile(tsconfig, ts.sys.readFile), ts.sys, ctx.workspacePath
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
OPT_CACHE[ctx.workspacePath] = {
|
|
65
|
+
...options,
|
|
66
|
+
allowJs: true,
|
|
67
|
+
resolveJsonModule: true,
|
|
68
|
+
sourceRoot: ctx.workspacePath,
|
|
69
|
+
rootDir: ctx.workspacePath,
|
|
70
|
+
outDir: path.resolve(ctx.workspacePath),
|
|
71
|
+
module: ctx.moduleType === 'commonjs' ? ts.ModuleKind.CommonJS : ts.ModuleKind.ESNext,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return OPT_CACHE[ctx.workspacePath];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Output a file, support for ts, js, and package.json
|
|
79
|
+
*/
|
|
80
|
+
static async transpileFile(ctx: ManifestContext, inputFile: string, outputFile: string): Promise<void> {
|
|
81
|
+
if (inputFile.endsWith('.ts') || inputFile.endsWith('.js')) {
|
|
82
|
+
const compilerOut = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules');
|
|
83
|
+
|
|
84
|
+
const text = (await fs.readFile(inputFile, 'utf8'))
|
|
85
|
+
.replace(/from '([.][^']+)'/g, (_, i) => `from '${i.replace(/[.]js$/, '')}.js'`)
|
|
86
|
+
.replace(/from '(@travetto\/(.*?))'/g, (_, i, s) => `from '${path.resolve(compilerOut, `${i}${s.includes('/') ? '.js' : '/__index__.js'}`)}'`);
|
|
87
|
+
|
|
88
|
+
const ts = (await import('typescript')).default;
|
|
89
|
+
const content = ts.transpile(text, await this.getCompilerOptions(ctx), inputFile);
|
|
90
|
+
await this.writeTextFile(outputFile, content);
|
|
91
|
+
} else if (inputFile.endsWith('package.json')) {
|
|
92
|
+
const pkg: Package = JSON.parse(await fs.readFile(inputFile, 'utf8'));
|
|
93
|
+
const main = pkg.main?.replace(/[.]ts$/, '.js');
|
|
94
|
+
const files = pkg.files?.map(x => x.replace('.ts', '.js'));
|
|
95
|
+
|
|
96
|
+
const content = JSON.stringify({ ...pkg, main, type: ctx.moduleType, files }, null, 2);
|
|
97
|
+
await this.writeTextFile(outputFile, content);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Scan directory to find all project sources for comparison
|
|
103
|
+
*/
|
|
104
|
+
static async getModuleSources(ctx: ManifestContext, module: string, seed: string[]): Promise<ModFile[]> {
|
|
105
|
+
const inputFolder = (ctx.mainModule === module) ?
|
|
106
|
+
process.cwd() :
|
|
107
|
+
path.dirname(SRC_REQ.resolve(`${module}/package.json`));
|
|
108
|
+
|
|
109
|
+
const folders = seed.filter(x => !/[.]/.test(x)).map(x => path.resolve(inputFolder, x));
|
|
110
|
+
const files = seed.filter(x => /[.]/.test(x)).map(x => path.resolve(inputFolder, x));
|
|
111
|
+
|
|
112
|
+
while (folders.length) {
|
|
113
|
+
const sub = folders.pop();
|
|
114
|
+
if (!sub) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (const file of await fs.readdir(sub).catch(() => [])) {
|
|
119
|
+
if (file.startsWith('.')) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const resolvedInput = path.resolve(sub, file);
|
|
123
|
+
const stat = await fs.stat(resolvedInput);
|
|
124
|
+
|
|
125
|
+
if (stat.isDirectory()) {
|
|
126
|
+
folders.push(resolvedInput);
|
|
127
|
+
} else if (file.endsWith('.d.ts')) {
|
|
128
|
+
// Do nothing
|
|
129
|
+
} else if (file.endsWith('.ts') || file.endsWith('.js')) {
|
|
130
|
+
files.push(resolvedInput);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const outputFolder = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', module);
|
|
136
|
+
const out: ModFile[] = [];
|
|
137
|
+
for (const input of files) {
|
|
138
|
+
const output = input.replace(inputFolder, outputFolder).replace(/[.]ts$/, '.js');
|
|
139
|
+
const inputTs = await fs.stat(input).then(RECENT_STAT, () => 0);
|
|
140
|
+
if (inputTs) {
|
|
141
|
+
const outputTs = await fs.stat(output).then(RECENT_STAT, () => 0);
|
|
142
|
+
await fs.mkdir(path.dirname(output), { recursive: true, });
|
|
143
|
+
out.push({ input, output, stale: inputTs > outputTs });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Run compiler
|
|
152
|
+
*/
|
|
153
|
+
static async runCompiler(ctx: ManifestContext, manifest: ManifestRoot, changed: DeltaEvent[], watch = false): Promise<void> {
|
|
154
|
+
const compiler = path.resolve(ctx.workspacePath, ctx.compilerFolder);
|
|
155
|
+
const main = path.resolve(compiler, 'node_modules', '@travetto/compiler/support/compiler-entry.js');
|
|
156
|
+
const deltaFile = path.resolve(os.tmpdir(), `manifest-delta.${Date.now()}.${Math.random()}.json`);
|
|
157
|
+
|
|
158
|
+
const changedFiles = changed[0]?.file === '*' ? ['*'] : changed.map(ev =>
|
|
159
|
+
path.resolve(manifest.workspacePath, manifest.modules[ev.module].sourceFolder, ev.file)
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
await this.writeTextFile(deltaFile, changedFiles.join('\n'));
|
|
163
|
+
|
|
164
|
+
await this.withLogger('compiler-exec', log => new Promise((res, rej) =>
|
|
165
|
+
cp.spawn(process.argv0, [main, deltaFile, `${watch}`], {
|
|
166
|
+
env: {
|
|
167
|
+
...process.env,
|
|
168
|
+
TRV_MANIFEST: path.resolve(ctx.workspacePath, ctx.outputFolder, 'node_modules', ctx.mainModule),
|
|
169
|
+
},
|
|
170
|
+
stdio: [0, 1, 2, 'ipc'],
|
|
171
|
+
})
|
|
172
|
+
.on('message', msg => IS_LOG_EV(msg) && log(...msg))
|
|
173
|
+
.on('exit', code => (code !== null && code > 0) ? rej() : res(null))
|
|
174
|
+
)).finally(() => fs.unlink(deltaFile));
|
|
175
|
+
}
|
|
176
|
+
}
|
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;
|