@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/transpile.js DELETED
@@ -1,227 +0,0 @@
1
- // @ts-check
2
-
3
- const _opts = {};
4
-
5
- /**
6
- * @typedef {import('@travetto/manifest').Package} Pkg
7
- * @typedef {import('@travetto/manifest').ManifestContext} ManifestContext
8
- */
9
-
10
- function $imp(mod) {
11
- try { return require(mod); } catch { return import(mod).then(x => x.default); }
12
- }
13
-
14
- /** @type {() => import('typescript')} */
15
- const $getTs = $imp.bind(null, 'typescript');
16
- /** @type {() => import('fs/promises')} */
17
- const $getFs = $imp.bind(null, 'fs/promises');
18
- /** @type {() => import('path')} */
19
- const $getPath = $imp.bind(null, 'path');
20
- /** @type {() => ({createRequire:(folder:string) => ({ resolve: (file:string)=>string})})} */
21
- const $getModule = $imp.bind(null, 'module');
22
- /** @param {string} x */
23
- const toPosix = x => x.replace(/\\/g, '/');
24
-
25
- /**
26
- * Returns the package.json
27
- * @param {string} inputFolder
28
- * @returns {Promise<Pkg>}
29
- */
30
- async function $getPkg(inputFolder) {
31
- const fs = await $getFs();
32
- const path = await $getPath();
33
- if (!inputFolder.endsWith('.json')) {
34
- inputFolder = path.resolve(inputFolder, 'package.json');
35
- }
36
- return JSON.parse(await fs.readFile(inputFolder, 'utf8'));
37
- }
38
-
39
- /**
40
- * Get workspace root
41
- * @return {Promise<string>}
42
- */
43
- async function $getWorkspaceRoot() {
44
- const path = await $getPath();
45
- const fs = await $getFs();
46
- let folder = process.cwd();
47
- let prevFolder = '';
48
- while (folder !== prevFolder) {
49
- try {
50
- const pkg = await $getPkg(folder);
51
- if (!!pkg.workspaces || !!pkg.travetto?.isolated) {
52
- return folder;
53
- }
54
- } catch { }
55
- if (await fs.stat(path.resolve(folder, '.git')).catch(() => { })) {
56
- break;
57
- }
58
- prevFolder = folder;
59
- folder = path.dirname(folder);
60
- }
61
- return process.cwd();
62
- }
63
-
64
- /**
65
- * Returns the compiler options
66
- * @param {ManifestContext} ctx
67
- * @returns
68
- */
69
- async function $getOpts(ctx) {
70
- if (!(ctx.workspacePath in _opts)) {
71
- const path = await $getPath();
72
- const fs = await $getFs();
73
- const ts = await $getTs();
74
- const mod = await $getModule();
75
- const req = mod.createRequire(`${ctx.workspacePath}/node_modules`);
76
-
77
- const framework = req.resolve('@travetto/compiler/tsconfig.trv.json');
78
- const self = path.resolve(ctx.workspacePath, 'tsconfig.json');
79
- const loc = (await fs.stat(self).catch(() => false)) ? self : framework;
80
- const { options } = ts.parseJsonSourceFileConfigFileContent(
81
- ts.readJsonConfigFile(loc, ts.sys.readFile), ts.sys, ctx.workspacePath
82
- );
83
- options.inlineSourceMap = true;
84
- options.sourceMap = false;
85
- try {
86
- const { type } = await $getPkg(ctx.workspacePath);
87
- if (type) {
88
- options.module = type.toLowerCase() === 'commonjs' ? ts.ModuleKind.CommonJS : ts.ModuleKind.ESNext;
89
- }
90
- } catch { }
91
-
92
- _opts[ctx.workspacePath] = options;
93
- }
94
- return _opts[ctx.workspacePath];
95
- }
96
-
97
- /**
98
- * Writes a package json file
99
- * @param {ManifestContext} ctx
100
- * @param {string} inputFile
101
- * @param {string} outputFile
102
- * @param {(pkg:Pkg) => Pkg} transform
103
- */
104
- async function writePackageJson(ctx, inputFile, outputFile, transform) {
105
- const opts = await $getOpts(ctx);
106
- const ts = await $getTs();
107
- const isEsm = opts.module !== ts.ModuleKind.CommonJS;
108
- let pkg = await $getPkg(inputFile);
109
- pkg = transform?.(pkg) ?? pkg;
110
- pkg.main = pkg.main?.replace(/[.]ts$/, '.js');
111
- pkg.type = isEsm ? 'module' : 'commonjs';
112
- pkg.files = pkg.files?.map(x => x.replace('.ts', '.js'));
113
-
114
- ts.sys.writeFile(outputFile, JSON.stringify(pkg, null, 2));
115
- }
116
-
117
- /**
118
- * Transpiles a file
119
- * @param {ManifestContext} ctx
120
- * @param {string} inputFile
121
- * @param {string} outputFile
122
- */
123
- async function transpileFile(ctx, inputFile, outputFile) {
124
- const ts = await $getTs();
125
- const fs = await $getFs();
126
-
127
- const opts = await $getOpts(ctx);
128
- const content = ts.transpile(await fs.readFile(inputFile, 'utf8'), opts, inputFile)
129
- .replace(/^((?:im|ex)port .*from '[.][^']+)(')/mg, (_, a, b) => `${a}.js${b}`)
130
- .replace(/^(import [^\n]*from '[^.][^\n/]+[/][^\n/]+[/][^\n']+)(')/mg, (_, a, b) => `${a}.js${b}`);
131
-
132
- ts.sys.writeFile(outputFile, content);
133
- }
134
-
135
- /**
136
- * Writes a js file
137
- * @param {ManifestContext} ctx
138
- * @param {string} inputFile
139
- * @param {string} outputFile
140
- */
141
- async function writeJsFile(ctx, inputFile, outputFile) {
142
- const ts = await $getTs();
143
- const fs = await $getFs();
144
-
145
- const opts = await $getOpts(ctx);
146
- const isEsm = opts.module !== ts.ModuleKind.CommonJS;
147
-
148
- let content = await fs.readFile(inputFile, 'utf8');
149
- if (isEsm) {
150
- content = content
151
- .replace(/^(?:async )?function [^$]/mg, a => `export ${a}`)
152
- .replace(/^module.exports.*/mg, '');
153
- }
154
-
155
- await fs.writeFile(outputFile, content, 'utf8');
156
- }
157
-
158
- /**
159
- * Write an entire package
160
- * @param {ManifestContext} ctx
161
- * @param {string} name
162
- * @param {string} sourcePath
163
- * @param {string} mainSource
164
- * @param {string[]} extraSources
165
- */
166
- async function buildPackage(ctx, name, sourcePath, mainSource, extraSources) {
167
- const path = await $getPath();
168
- const fs = await $getFs();
169
-
170
- const files = [mainSource, ...extraSources].map(x => ({ src: x, out: x.replace(/[.]ts$/, '.js') }));
171
- const main = files[0].out;
172
- const outputPath = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', name);
173
-
174
- for (const { src, out } of files) {
175
- const inputFile = path.resolve(sourcePath, src);
176
- const outputFile = path.resolve(outputPath, out);
177
-
178
- const [outStat, inStat] = await Promise.all([
179
- fs.stat(outputFile).catch(() => undefined),
180
- fs.stat(inputFile)
181
- ]);
182
-
183
- if (!outStat || (outStat.mtimeMs < inStat.mtimeMs)) {
184
- await fs.mkdir(path.dirname(outputFile), { recursive: true });
185
-
186
- if (inputFile.endsWith('.ts')) {
187
- await transpileFile(ctx, inputFile, outputFile);
188
- } else if (inputFile.endsWith('.js')) {
189
- await writeJsFile(ctx, inputFile, outputFile);
190
- } else if (inputFile.endsWith('.json')) {
191
- await writePackageJson(ctx, inputFile, outputFile,
192
- (pkg) => ({ ...pkg, files: files.map(x => x.out), name, main }));
193
- }
194
- }
195
- }
196
-
197
- return path.resolve(outputPath, main);
198
- }
199
-
200
- /**
201
- * Gets build context
202
- * @return {Promise<ManifestContext>}
203
- */
204
- async function getContext(folder = process.cwd()) {
205
- const path = await $getPath();
206
-
207
- const workspacePath = path.resolve(await $getWorkspaceRoot());
208
- const mainPath = toPosix(folder);
209
-
210
- const { name: mainModule, workspaces, travetto } = (await $getPkg(mainPath));
211
- const monoRepo = workspacePath !== mainPath || !!workspaces;
212
-
213
- // All relative to workspacePath
214
- const manifestFile = `node_modules/${mainModule}/manifest.json`;
215
-
216
- return {
217
- mainModule,
218
- mainPath,
219
- workspacePath,
220
- monoRepo,
221
- manifestFile,
222
- outputFolder: travetto?.outputFolder ?? '.trv_output',
223
- compilerFolder: '.trv_compiler'
224
- };
225
- }
226
-
227
- module.exports = { transpileFile, writePackageJson, writeJsFile, buildPackage, getContext };
@@ -1,151 +0,0 @@
1
- import path from 'path';
2
- import fs from 'fs/promises';
3
- import cp from 'child_process';
4
-
5
- import type { ManifestState, ManifestContext, ManifestRoot } from '@travetto/manifest';
6
-
7
- import { log, compileIfStale, getProjectSources, addNodePath, importManifest } from './utils';
8
-
9
- const PRECOMPILE_MODS = [
10
- '@travetto/terminal',
11
- '@travetto/manifest',
12
- '@travetto/transformer',
13
- '@travetto/compiler'
14
- ];
15
-
16
- let manifestTemp;
17
-
18
- /**
19
- * Step 0
20
- */
21
- export async function precompile(ctx: ManifestContext): Promise<void> {
22
- for (const mod of PRECOMPILE_MODS) {
23
- await compileIfStale(ctx, `[0] Compiling ${mod}`, await getProjectSources(ctx, mod),);
24
- }
25
- }
26
-
27
- export async function writeManifest(ctx: ManifestContext, manifest: ManifestRoot): Promise<void> {
28
- const { ManifestUtil } = await importManifest(ctx);
29
- return ManifestUtil.writeManifest(ctx, manifest);
30
- }
31
-
32
- async function rewriteManifests(ctx: ManifestContext, state: ManifestState): Promise<void> {
33
- const { ManifestUtil } = await importManifest(ctx);
34
-
35
- // Write out all changed manifests
36
- const { getContext } = await import('../../bin/transpile');
37
-
38
- const dirtyModules = [...Object.entries(state.delta)].filter(x => x[1].length > 0).map(([mod]) => mod);
39
- for (const module of dirtyModules) {
40
- const subCtx = await getContext(state.manifest.modules[module].source);
41
- await ManifestUtil.createAndWriteManifest(subCtx);
42
- }
43
- }
44
-
45
- /**
46
- * Step 1
47
- */
48
- export async function buildManifest(ctx: ManifestContext): Promise<ManifestState> {
49
- log('[1] Manifest Generation');
50
- const { ManifestUtil } = await importManifest(ctx);
51
- return ManifestUtil.produceState(ctx);
52
- }
53
-
54
- function shouldRebuildCompiler({ delta }: ManifestState): { total: boolean, transformers: [string, string][] } {
55
- // Did enough things change to re-stage and build the compiler
56
- const transformersChanged = Object.entries(delta)
57
- .flatMap(([mod, files]) => files.map(x => [mod, x.file]))
58
- .filter((ev): ev is [string, string] => ev[1].startsWith('support/transform'));
59
- const transformerChanged = (delta['@travetto/transformer'] ?? []);
60
- const compilerChanged = delta['@travetto/compiler'] ?? [];
61
-
62
- const changed = transformerChanged.length || transformersChanged.length || compilerChanged.length;
63
- if (changed) {
64
- if (compilerChanged.length) {
65
- log('[2] Compiler source changed @travetto/compiler', compilerChanged);
66
- }
67
- if (transformerChanged.length) {
68
- log('[2] Compiler source changed @travetto/transformer', transformerChanged);
69
- }
70
- if (transformersChanged.length) {
71
- log('[2] Compiler source changed */support/transform', transformersChanged);
72
- }
73
- }
74
- return { total: changed > 0, transformers: transformersChanged };
75
- }
76
-
77
- /**
78
- * Step 2
79
- */
80
- async function buildCompiler(state: ManifestState, ctx: ManifestContext): Promise<void> {
81
- const changed = shouldRebuildCompiler(state);
82
-
83
- if (changed.transformers.length) {
84
- state = await buildManifest(ctx);
85
- let x = 0;
86
- for (const [mod, file] of changed.transformers) {
87
- await compileIfStale(
88
- ctx,
89
- `[2.${x += 1}] ${file} Bootstrapping`,
90
- await getProjectSources(ctx, mod, ['package.json', file])
91
- );
92
- }
93
- }
94
-
95
- log('[2] Compiler Ready');
96
- }
97
-
98
- /**
99
- * Step 4
100
- */
101
- async function compileOutput(state: ManifestState, ctx: ManifestContext, watch?: boolean): Promise<void> {
102
- let changes = Object.values(state.delta).flat();
103
-
104
- // Remove files that should go away
105
- await Promise.all(changes.filter(x => x.type === 'removed')
106
- .map(x => fs.unlink(path.resolve(ctx.workspacePath, ctx.outputFolder, x.file)).catch(() => { })));
107
-
108
- changes = changes.filter(x => x.type !== 'removed');
109
-
110
- const { ManifestUtil } = await importManifest(ctx);
111
- const resolve = ManifestUtil.resolveFile.bind(null, ctx, state.manifest, '@travetto/compiler');
112
-
113
- manifestTemp ??= await ManifestUtil.writeState(state);
114
- const cwd = path.resolve(ctx.workspacePath, ctx.compilerFolder);
115
-
116
- if (changes.length) {
117
- log('[3] Changed Sources', changes);
118
-
119
- // Blocking call, compile only
120
- const res = cp.spawnSync(process.argv0,
121
- [resolve('support/main.output'), manifestTemp],
122
- { cwd, stdio: 'inherit', encoding: 'utf8' }
123
- );
124
-
125
- if (res.status) {
126
- throw new Error(res.stderr);
127
- }
128
-
129
- await rewriteManifests(ctx, state);
130
- }
131
-
132
- if (watch) {
133
- // Rewrite state with updated manifest
134
- const newState = await ManifestUtil.produceState(ctx);
135
- manifestTemp = await ManifestUtil.writeState(newState);
136
-
137
- // Run with watching
138
- cp.spawnSync(process.argv0,
139
- [resolve('support/main.output'), manifestTemp, 'true'], { cwd, stdio: 'inherit' }
140
- );
141
- }
142
- }
143
-
144
- export async function compile(ctx: ManifestContext, watch?: boolean): Promise<ManifestState> {
145
- await precompile(ctx); // Step 0
146
- const state = await buildManifest(ctx); // Step 1
147
- await buildCompiler(state, ctx); // Step 2
148
- await compileOutput(state, ctx, watch); // Step 3
149
- await addNodePath(path.resolve(ctx.workspacePath, ctx.outputFolder));
150
- return state;
151
- }
@@ -1,116 +0,0 @@
1
- import fs from 'fs/promises';
2
-
3
- import path from 'path';
4
- import { type Stats } from 'fs';
5
- import { createRequire } from 'module';
6
-
7
- import type { ManifestContext, ManifestUtil } from '@travetto/manifest';
8
-
9
- import { transpileFile, writePackageJson } from '../../bin/transpile';
10
-
11
- const req = createRequire(`${process.cwd()}/node_modules`);
12
-
13
- type ModFile = { input: string, output: string, stale: boolean };
14
-
15
- const SOURCE_SEED = ['package.json', 'index.ts', '__index__.ts', 'src', 'support', 'bin'];
16
-
17
- export const IS_DEBUG = /\b([*]|build)\b/.test(process.env.DEBUG ?? '');
18
-
19
- const resolveImport = (lib: string): string => req.resolve(lib);
20
- const recentStat = (stat: Stats): number => Math.max(stat.ctimeMs, stat.mtimeMs);
21
-
22
- /**
23
- * Common logging support
24
- */
25
- export const log = IS_DEBUG ?
26
- (...args: unknown[]): void => console.debug(new Date().toISOString(), ...args) :
27
- (): void => { };
28
-
29
- /**
30
- * Scan directory to find all project sources for comparison
31
- */
32
- export async function getProjectSources(
33
- ctx: ManifestContext, module: string, seed: string[] = SOURCE_SEED
34
- ): Promise<ModFile[]> {
35
- const inputFolder = (ctx.mainModule === module) ?
36
- process.cwd() :
37
- path.dirname(resolveImport(`${module}/package.json`));
38
-
39
- const folders = seed.filter(x => !/[.]/.test(x)).map(x => path.resolve(inputFolder, x));
40
- const files = seed.filter(x => /[.]/.test(x)).map(x => path.resolve(inputFolder, x));
41
-
42
- while (folders.length) {
43
- const sub = folders.pop();
44
- if (!sub) {
45
- continue;
46
- }
47
-
48
- for (const file of await fs.readdir(sub).catch(() => [])) {
49
- if (file.startsWith('.')) {
50
- continue;
51
- }
52
- const resolvedInput = path.resolve(sub, file);
53
- const stat = await fs.stat(resolvedInput);
54
-
55
- if (stat.isDirectory()) {
56
- folders.push(resolvedInput);
57
- } else if (file.endsWith('.d.ts')) {
58
- // Do nothing
59
- } else if (file.endsWith('.ts') || file.endsWith('.js')) {
60
- files.push(resolvedInput);
61
- }
62
- }
63
- }
64
-
65
- const outputFolder = path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', module);
66
- const out: ModFile[] = [];
67
- for (const input of files) {
68
- const output = input.replace(inputFolder, outputFolder).replace(/[.]ts$/, '.js');
69
- const inputTs = await fs.stat(input).then(recentStat, () => 0);
70
- if (inputTs) {
71
- const outputTs = await fs.stat(output).then(recentStat, () => 0);
72
- await fs.mkdir(path.dirname(output), { recursive: true, });
73
- out.push({ input, output, stale: inputTs > outputTs });
74
- }
75
- }
76
-
77
- return out;
78
- }
79
-
80
- /**
81
- * Recompile folder if stale
82
- */
83
- export async function compileIfStale(ctx: ManifestContext, prefix: string, files: ModFile[]): Promise<void> {
84
- try {
85
- if (files.some(f => f.stale)) {
86
- log(`${prefix} Starting`);
87
- for (const file of files.filter(x => x.stale)) {
88
- if (file.input.endsWith('package.json')) {
89
- await writePackageJson(ctx, file.input, file.output);
90
- } else {
91
- await transpileFile(ctx, file.input, file.output);
92
- }
93
- }
94
- } else {
95
- log(`${prefix} Skipped`);
96
- }
97
- } catch (err) {
98
- console.error(err);
99
- }
100
- }
101
-
102
- /**
103
- * Add node path at runtime
104
- */
105
- export async function addNodePath(folder: string): Promise<void> {
106
- process.env.NODE_PATH = [`${folder}/node_modules`, process.env.NODE_PATH].join(path.delimiter);
107
- const { Module } = await import('module');
108
- // @ts-expect-error
109
- Module._initPaths();
110
- }
111
-
112
- /**
113
- * Import the manifest utils once compiled
114
- */
115
- export const importManifest = (ctx: ManifestContext): Promise<{ ManifestUtil: typeof ManifestUtil }> =>
116
- import(path.resolve(ctx.workspacePath, ctx.compilerFolder, 'node_modules', '@travetto', 'manifest', '__index__.js'));
@@ -1,11 +0,0 @@
1
- import { readFileSync } from 'fs';
2
- import { install } from 'source-map-support';
3
-
4
- import { ManifestState } from '@travetto/manifest';
5
-
6
- import { Compiler } from '../src/compiler';
7
-
8
- install();
9
- const [manifestState, watch] = process.argv.slice(2);
10
- const state: ManifestState = JSON.parse(readFileSync(manifestState, 'utf8'));
11
- new Compiler().init(state).run(watch === 'true');