@travetto/compiler 5.0.16 → 5.0.18

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/README.md CHANGED
@@ -21,7 +21,7 @@ This module expands upon the [Typescript](https://typescriptlang.org) compiler,
21
21
  Beyond the [Typescript](https://typescriptlang.org) compiler functionality, the module provides the primary entry point into the development process.
22
22
 
23
23
  ## CLI
24
- The compiler cli, [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L4) is the entry point for compilation-related operations. It has the ability to check for active builds, and ongoing watch operations to ensure only one process is building at a time. Within the framework, regardless of mono-repo or not, the compilation always targets the entire project. With the efficient caching behavior, this leads to generally a minimal overhead but allows for centralization of all operations.
24
+ The compiler cli, [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L20) is the entry point for compilation-related operations. It has the ability to check for active builds, and ongoing watch operations to ensure only one process is building at a time. Within the framework, regardless of mono-repo or not, the compilation always targets the entire project. With the efficient caching behavior, this leads to generally a minimal overhead but allows for centralization of all operations.
25
25
 
26
26
  The compiler cli supports the following operations:
27
27
  * `start|watch` - Run the compiler in watch mode
@@ -87,4 +87,4 @@ The compiler will move through the following phases on a given compilation execu
87
87
  * `Invoke Compiler` - Run [Typescript](https://typescriptlang.org) compiler with the aforementioned enhancements
88
88
 
89
89
  ### Bootstrapping
90
- Given that the framework is distributed as [Typescript](https://typescriptlang.org) only files, there is a bootstrapping problem that needs to be mitigated. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L4) entrypoint, along with a small context utility in [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching") are the only [Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript) files needed to run the project. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L4) entry point will compile `@travetto/compiler/support/*` files as the set that is used at startup. These files are also accessible to the compiler as they get re-compiled after the fact.
90
+ Given that the framework is distributed as [Typescript](https://typescriptlang.org) only files, there is a bootstrapping problem that needs to be mitigated. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L20) entrypoint, along with a small context utility in [Manifest](https://github.com/travetto/travetto/tree/main/module/manifest#readme "Support for project indexing, manifesting, along with file watching") are the only [Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript) files needed to run the project. The [trvc](https://github.com/travetto/travetto/tree/main/module/compiler/bin/trvc.js#L20) entry point will compile `@travetto/compiler/support/*` files as the set that is used at startup. These files are also accessible to the compiler as they get re-compiled after the fact.
@@ -0,0 +1,81 @@
1
+ // @ts-check
2
+ /* eslint-disable no-undef */
3
+ const { stat, readFile, writeFile, mkdir, rm, readdir } = require('node:fs/promises');
4
+ const path = require('node:path');
5
+
6
+ const COMP_MOD = '@travetto/compiler';
7
+
8
+ async function writeIfStale(src = '', dest = '', transform = async (x = '') => x) {
9
+ const [srcStat, destStat] = await Promise.all([src, dest].map(x => stat(`${x}`).then(z => z.mtimeMs, () => 0)));
10
+
11
+ if (!destStat || destStat < srcStat) {
12
+ const text = src ? await readFile(src, 'utf8') : '';
13
+ await mkdir(path.dirname(dest), { recursive: true });
14
+ await writeFile(dest, await transform(text), 'utf8');
15
+ }
16
+ }
17
+
18
+ async function transpile(content = '', esm = true, full = true) {
19
+ const ts = (await import('typescript')).default;
20
+ return ts.transpile(content, {
21
+ target: ts.ScriptTarget.ES2022,
22
+ module: esm ? ts.ModuleKind.ESNext : ts.ModuleKind.CommonJS,
23
+ ...(full ? { esModuleInterop: true, allowSyntheticDefaultImports: true } : {})
24
+ });
25
+ }
26
+
27
+ async function getContext() {
28
+ const ctxSrc = require.resolve('@travetto/manifest/src/context.ts');
29
+ const ctxDest = path.resolve(__dirname, 'gen.context.mjs');
30
+ await writeIfStale(ctxSrc, ctxDest, content => transpile(content, true, false));
31
+ const ctx = await import(ctxDest).then((/** @type {import('@travetto/manifest/src/context')} */ v) => v.getManifestContext());
32
+
33
+ const srcPath = path.resolve.bind(path, ctx.workspace.path, ctx.build.compilerModuleFolder);
34
+ const destPath = (file = '', mod = COMP_MOD) => {
35
+ const base = path.resolve(ctx.workspace.path, ctx.build.compilerFolder, mod, file);
36
+ return `${base}${file.includes('.') ? '' : file.includes('/') ? '.ts' : '/__index__.ts'}`.replace('.ts', '.js');
37
+ };
38
+
39
+ return {
40
+ packageType: ctx.workspace.type,
41
+ srcPath,
42
+ destPath,
43
+ tsconfig: path.resolve(ctx.workspace.path, 'tsconfig.json'),
44
+ cleanImports: (t = '') => t
45
+ .replace(/from '([.][^']+)'/g, (_, i) => `from '${i.replace(/[.]js$/, '')}.js'`)
46
+ .replace(/from '(@travetto\/[^/']+)([/][^']+)?'/g, (_, mod, modFile) => `from '${destPath(modFile, mod)}'`),
47
+ loadMain: () => import(destPath('support/entry.main.ts'))
48
+ .then((/** @type {import('../support/entry.main')} */ v) => v.main(ctx)),
49
+ supportFiles: () => readdir(srcPath('support'), { recursive: true, encoding: 'utf8' })
50
+ .then(v => v.filter(f => f.endsWith('.ts')).map(j => `support/${j}`))
51
+ };
52
+ }
53
+
54
+ /** @template T */
55
+ async function load(/** @type {(ops: import('../support/entry.main').Operations) => T} */ cb) {
56
+ const ctx = await getContext();
57
+
58
+ try {
59
+ await writeIfStale('', ctx.tsconfig,
60
+ async () => JSON.stringify({ extends: `${COMP_MOD}/tsconfig.trv.json` }, null, 2));
61
+
62
+ await writeIfStale(ctx.srcPath('package.json'), ctx.destPath('package.json'),
63
+ async text => JSON.stringify({ ...JSON.parse(text || '{}'), type: ctx.packageType }, null, 2));
64
+
65
+ await Promise.all((await ctx.supportFiles()).map(f =>
66
+ writeIfStale(ctx.srcPath(f), ctx.destPath(f),
67
+ t => transpile(t, ctx.packageType === 'module').then(ctx.cleanImports))));
68
+
69
+ process.setSourceMapsEnabled(true); // Ensure source map during compilation/development
70
+ process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS ?? ''} --enable-source-maps`; // Ensure it passes to children
71
+ const res = await ctx.loadMain();
72
+ // @ts-ignore
73
+ try { module.enableCompileCache(); } catch { }
74
+ return cb(res);
75
+ } catch (err) {
76
+ await rm(ctx.srcPath('.'), { recursive: true, force: true });
77
+ throw err;
78
+ }
79
+ }
80
+
81
+ module.exports = { load };
@@ -1,9 +1,11 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { createRequire } from 'node:module';
4
+ // eslint-disable-next-line no-bitwise
4
5
  const toPort = (pth) => (Math.abs([...pth].reduce((a, b) => (a * 33) ^ b.charCodeAt(0), 5381)) % 29000) + 20000;
5
6
  const toPosix = (pth) => pth.replaceAll('\\', '/');
6
7
  const readPackage = (file) => ({ ...JSON.parse(readFileSync(file, 'utf8')), path: toPosix(path.dirname(file)) });
8
+ /** Find package */
7
9
  function findPackage(base, pred) {
8
10
  let folder = `${base}/.`;
9
11
  let prev;
@@ -13,14 +15,18 @@ function findPackage(base, pred) {
13
15
  folder = path.dirname(folder);
14
16
  const folderPkg = path.resolve(folder, 'package.json');
15
17
  pkg = existsSync(folderPkg) ? readPackage(folderPkg) : pkg;
16
- } while (prev !== folder &&
17
- !pred(pkg) &&
18
- !existsSync(path.resolve(folder, '.git')));
18
+ } while (prev !== folder && // Not at root
19
+ !pred(pkg) && // Matches criteria
20
+ !existsSync(path.resolve(folder, '.git')) // Not at source root
21
+ );
19
22
  if (!pkg) {
20
23
  throw new Error('Could not find a package.json');
21
24
  }
22
25
  return pkg;
23
26
  }
27
+ /**
28
+ * Gets build context
29
+ */
24
30
  export function getManifestContext(root = process.cwd()) {
25
31
  const workspace = findPackage(root, pkg => !!pkg?.workspaces || !!pkg?.travetto?.build?.isolated);
26
32
  const build = workspace.travetto?.build ?? {};
package/bin/trvc.js CHANGED
@@ -1,45 +1,39 @@
1
1
  #!/usr/bin/env node
2
+ const help = `
3
+ npx trvc [command]
2
4
 
3
- // @ts-check
4
- const { getEntry } = require('./common.js');
5
+ Available Commands:
6
+ * start|watch - Run the compiler in watch mode
7
+ * stop - Stop the compiler if running
8
+ * restart - Restart the compiler in watch mode
9
+ * build - Ensure the project is built and upto date
10
+ * clean - Clean out the output and compiler caches
11
+ * info - Retrieve the compiler information, if running
12
+ * event <log|progress|state> - Watch events in realtime as newline delimited JSON
13
+ * exec <file> [...args] - Allow for compiling and executing an entrypoint file
14
+ * manifest --prod [output] - Generate the project manifest
15
+ `;
5
16
 
6
- const help = () => [
7
- 'npx trvc [command]',
8
- '',
9
- 'Available Commands:',
10
- ' * start|watch - Run the compiler in watch mode',
11
- ' * stop - Stop the compiler if running',
12
- ' * restart - Restart the compiler in watch mode',
13
- ' * build - Ensure the project is built and upto date',
14
- ' * clean - Clean out the output and compiler caches',
15
- ' * info - Retrieve the compiler information, if running',
16
- ' * event <log|progress|state> - Watch events in realtime as newline delimited JSON',
17
- ' * exec <file> [...args] - Allow for compiling and executing an entrypoint file',
18
- ' * manifest --prod [output] - Generate the project manifest',
19
- ].join('\n');
17
+ const toJson = (/** @type {number} */ depth) => v => process.stdout.write(`${JSON.stringify(v, undefined, depth)}\n`) ||
18
+ new Promise(r => process.stdout.once('drain', r));
20
19
 
21
- getEntry().then(async (ops) => {
20
+ require('./entry.common.js').load(ops => {
22
21
  const [op, ...all] = process.argv.slice(2);
23
22
  const args = all.filter(x => !x.startsWith('-'));
24
- const flags = all.filter(x => x.startsWith('-'));
25
23
 
26
24
  switch (op) {
27
25
  case undefined:
28
- case 'help': return console.log(`\n${help()}\n`);
29
- case 'restart': return ops.restart();
30
- case 'stop': return ops.stop();
31
- case 'info': return ops.info().then(v => console.log(JSON.stringify(v, null, 2)));
32
- case 'event': return ops.events(args[0], v => {
33
- if (!process.stdout.write(`${JSON.stringify(v)}\n`)) {
34
- return new Promise(r => process.stdout.once('drain', r));
35
- }
36
- });
26
+ case 'help': return console.log(help);
27
+ case 'info': return ops.info().then(toJson(2));
28
+ case 'event': return ops.events(args[0], toJson(0));
29
+ case 'manifest': return ops.manifest(args[0], all.some(x => x === '--prod'));
30
+ case 'exec': return ops.exec(args[0], all.slice(1));
31
+ case 'build': return ops.build();
37
32
  case 'clean': return ops.clean();
38
- case 'manifest': return ops.manifest(args[0], flags.some(x => x === '--prod'));
39
- case 'exec': return ops.getLoader().then(v => v(args[0], all.slice(1)));
40
33
  case 'start':
41
34
  case 'watch': return ops.watch();
42
- case 'build': return ops.build();
43
- default: console.error(`Unknown trvc operation: ${op}\n`); return console.error(help());
35
+ case 'stop': return ops.stop();
36
+ case 'restart': return ops.restart();
37
+ default: console.error(`\nUnknown trvc operation: ${op}\n${help}`);
44
38
  }
45
39
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/compiler",
3
- "version": "5.0.16",
3
+ "version": "5.0.18",
4
4
  "description": "The compiler infrastructure for the Travetto framework",
5
5
  "keywords": [
6
6
  "compiler",
@@ -28,17 +28,13 @@
28
28
  "url": "https://github.com/travetto/travetto.git",
29
29
  "directory": "module/compiler"
30
30
  },
31
- "engines": {
32
- "node": ">=22.0.0"
33
- },
34
31
  "dependencies": {
35
- "@parcel/watcher": "^2.4.1",
36
- "@travetto/manifest": "^5.0.9",
37
- "@travetto/transformer": "^5.0.10",
38
- "@types/node": "^22.7.9"
32
+ "@parcel/watcher": "^2.5.0",
33
+ "@travetto/manifest": "^5.0.11",
34
+ "@travetto/transformer": "^5.0.12"
39
35
  },
40
36
  "peerDependencies": {
41
- "@travetto/cli": "^5.0.15"
37
+ "@travetto/cli": "^5.0.18"
42
38
  },
43
39
  "peerDependenciesMeta": {
44
40
  "@travetto/cli": {
package/src/compiler.ts CHANGED
@@ -69,7 +69,7 @@ export class Compiler {
69
69
  process.exitCode = 1;
70
70
  if (err) {
71
71
  EventUtil.sendEvent('log', { level: 'error', message: err.toString(), time: Date.now() });
72
- log.error('Shutting down due to failure', err.message);
72
+ log.error('Shutting down due to failure', err.stack);
73
73
  }
74
74
  break;
75
75
  }
@@ -103,7 +103,7 @@ export class Compiler {
103
103
 
104
104
  for (const file of files) {
105
105
  const err = await emitter(file);
106
- const imp = file.replace(/.*node_modules\//, '');
106
+ const imp = file.includes('node_modules/') ? file.split('node_modules/')[1] : file;
107
107
  yield { file: imp, i: i += 1, err, total: files.length };
108
108
  if ((Date.now() - lastSent) > 50) { // Limit to 1 every 50ms
109
109
  lastSent = Date.now();
package/src/watch.ts CHANGED
@@ -61,7 +61,7 @@ export class CompilerWatcher {
61
61
  const mod = entry?.module ?? this.#state.manifestIndex.findModuleForArbitraryFile(file);
62
62
  if (mod && action === 'create' && !entry) {
63
63
  const modRoot = mod.sourceFolder || this.#root;
64
- const moduleFile = file.includes(modRoot) ? file.split(`${modRoot}/`)[1] : file;
64
+ const moduleFile = file.includes(`${modRoot}/`) ? file.split(`${modRoot}/`)[1] : file;
65
65
  entry = this.#state.registerInput(mod, moduleFile);
66
66
  }
67
67
  return { entry, file: entry?.sourceFile ?? file, action };
@@ -11,7 +11,6 @@ import { CompilerRunner } from './server/runner';
11
11
  import { CompilerClient } from './server/client';
12
12
  import { CommonUtil } from './util';
13
13
 
14
-
15
14
  // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
16
15
  export const main = (ctx: ManifestContext) => {
17
16
  const client = new CompilerClient(ctx, Log.scoped('client'));
@@ -91,21 +90,19 @@ export const main = (ctx: ManifestContext) => {
91
90
  await compile('watch');
92
91
  },
93
92
 
94
- /** Build and return a loader */
95
- async getLoader(): Promise<(mod: string, args?: string[]) => Promise<unknown>> {
93
+ /** Set arguments and import module */
94
+ async exec(mod: string, args?: string[]): Promise<unknown> {
96
95
  Log.initLevel('none');
97
96
  if (!(await client.isWatching())) { // Short circuit if we can
98
97
  Log.initLevel('error');
99
98
  await compile('build');
100
99
  }
101
100
 
102
- return (mod, args) => {
103
- process.env.TRV_MANIFEST = CommonUtil.resolveWorkspace(ctx, ctx.build.outputFolder, 'node_modules', ctx.main.name); // Setup for running
104
- if (args) {
105
- process.argv = [process.argv0, mod, ...args];
106
- }
107
- return import(CommonUtil.resolveWorkspace(ctx, ctx.build.outputFolder, 'node_modules', mod)); // Return function to run import on a module
108
- };
101
+ process.env.TRV_MANIFEST = CommonUtil.resolveWorkspace(ctx, ctx.build.outputFolder, 'node_modules', ctx.main.name); // Setup for running
102
+ if (args) {
103
+ process.argv = [process.argv0, mod, ...args];
104
+ }
105
+ return import(CommonUtil.resolveWorkspace(ctx, ctx.build.outputFolder, 'node_modules', mod)); // Return function to run import on a module
109
106
  },
110
107
 
111
108
  /** Manifest entry point */
@@ -115,4 +112,6 @@ export const main = (ctx: ManifestContext) => {
115
112
  }
116
113
  };
117
114
  return ops;
118
- };
115
+ };
116
+
117
+ export type Operations = ReturnType<typeof main>;
package/support/log.ts CHANGED
@@ -69,7 +69,6 @@ export class Logger implements LogConfig, LogShape {
69
69
  error(message: string, ...args: unknown[]): void { return this.render({ level: 'error', message, args }); }
70
70
  }
71
71
 
72
-
73
72
  class $RootLogger extends Logger {
74
73
  #logProgress?: boolean;
75
74
 
package/bin/common.js DELETED
@@ -1,101 +0,0 @@
1
- // @ts-check
2
- const { statSync, readFileSync, writeFileSync, mkdirSync, readdirSync, existsSync, rmSync } = require('node:fs');
3
- const path = require('node:path');
4
-
5
- /** @typedef {import('@travetto/manifest').ManifestContext} Ctx */
6
-
7
- const TS_EXT = /[.]tsx?$/;
8
-
9
- const getAge = (/** @type {{mtimeMs:number, ctimeMs:number}} */ st) => Math.max(st.mtimeMs, st.ctimeMs);
10
-
11
- const modPath = (/** @type {Ctx} */ ctx, mod, file) => {
12
- const base = path.resolve(ctx.workspace.path, ctx.build.compilerFolder, 'node_modules', mod, file);
13
- return `${base}${file.includes('.') ? '' : file.includes('/') ? '.ts' : '/__index__.ts'}`.replace(TS_EXT, '.js');
14
- };
15
-
16
- const needsWriting = (/** @type {string} */ src, /** @type {string} */ dest) =>
17
- !existsSync(dest) || getAge(statSync(dest)) < getAge(statSync(src));
18
-
19
- const getTarget = (/** @type {Ctx} */ ctx, file = '') => ({
20
- dest: modPath(ctx, '@travetto/compiler', file),
21
- src: path.resolve(ctx.workspace.path, ctx.build.compilerModuleFolder, file),
22
- async writeIfStale(/** @type {(text:string)=>(string|Promise<string>)}*/ transform) {
23
- if (needsWriting(this.src, this.dest)) {
24
- const text = readFileSync(this.src, 'utf8');
25
- mkdirSync(path.dirname(this.dest), { recursive: true });
26
- writeFileSync(this.dest, await transform(text), 'utf8');
27
- }
28
- }
29
- });
30
-
31
- const getTranspiler = async (/** @type {Ctx} */ ctx) => {
32
- const ts = (await import('typescript')).default;
33
- const module = ctx.workspace.type === 'module' ? ts.ModuleKind.ESNext : ts.ModuleKind.CommonJS;
34
- return (content = '') =>
35
- ts.transpile(content, { target: ts.ScriptTarget.ES2022, module, esModuleInterop: true, allowSyntheticDefaultImports: true })
36
- .replace(/from '([.][^']+)'/g, (_, i) => `from '${i.replace(/[.]js$/, '')}.js'`)
37
- .replace(/from '(@travetto\/[^/']+)([/][^']+)?'/g, (_, mod, file) => `from '${modPath(ctx, mod, file)}'`);
38
- };
39
-
40
- async function getEntry() {
41
- process.setSourceMapsEnabled(true); // Ensure source map during compilation/development
42
- process.env.NODE_OPTIONS = `${process.env.NODE_OPTIONS ?? ''} --enable-source-maps`; // Ensure it passes to children
43
-
44
- // eslint-disable-next-line no-undef
45
- const manifestJs = path.resolve(__dirname, 'manifest-context.mjs');
46
- const loc = require.resolve('@travetto/manifest').replace(/__index__.*/, 'src/context.ts');
47
-
48
- // Compile if needed
49
- if (needsWriting(loc, manifestJs)) {
50
- const ts = (await import('typescript')).default;
51
- const text = ts.transpile(readFileSync(loc, 'utf8'), {
52
- target: ts.ScriptTarget.ES2022,
53
- module: ts.ModuleKind.ESNext,
54
- removeComments: true
55
- }, manifestJs);
56
- writeFileSync(manifestJs, text, 'utf8');
57
- }
58
-
59
- // Load module on demand
60
- /** @type {import('@travetto/manifest/src/context')} */
61
- const { getManifestContext } = await import(manifestJs);
62
-
63
- /** @type {Ctx} */
64
- const ctx = getManifestContext();
65
- const target = getTarget.bind(null, ctx);
66
-
67
- // Setup Tsconfig
68
- const tsconfig = path.resolve(ctx.workspace.path, 'tsconfig.json');
69
- existsSync(tsconfig) || writeFileSync(tsconfig,
70
- JSON.stringify({ extends: '@travetto/compiler/tsconfig.trv.json' }), 'utf8');
71
-
72
- // Compile support folder
73
- await target('package.json').writeIfStale(text =>
74
- JSON.stringify(Object.assign(JSON.parse(text), { type: ctx.workspace.type }), null, 2)
75
- );
76
-
77
- let transpile;
78
- for (const file of readdirSync(target('support').src, { recursive: true, encoding: 'utf8' })) {
79
- if (TS_EXT.test(file)) {
80
- await target(`support/${file}`).writeIfStale(async (text) =>
81
- (transpile ??= await getTranspiler(ctx))(text)
82
- );
83
- }
84
- }
85
-
86
- // Load
87
- try {
88
- // @ts-ignore
89
- try { await import('node:module').then(v => v.enableCompileCache()); } catch { }
90
-
91
- /** @type {import('../support/entry.trvc')} */
92
- const res = await import(target('support/entry.trvc.ts').dest);
93
- return await res.main(ctx);
94
- } catch (err) {
95
- rmSync(target('.').dest, { recursive: true, force: true });
96
- throw err;
97
- }
98
- }
99
-
100
- // eslint-disable-next-line no-undef
101
- module.exports = { getEntry };