@travetto/manifest 3.4.0-rc.3 → 4.0.0-rc.0

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 ArcSine Technologies
3
+ Copyright (c) 2023 ArcSine Technologies
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -35,7 +35,7 @@ During the compilation process, it is helpful to know how the output content dif
35
35
  ## Class and Function Metadata
36
36
  For the framework to work properly, metadata needs to be collected about files, classes and functions to uniquely identify them, with support for detecting changes during live reloads. To achieve this, every `class` is decorated with an additional field of `Ⲑid`. `Ⲑid` represents a computed id that is tied to the file/class combination.
37
37
 
38
- `Ⲑid` is used heavily throughout the framework for determining which classes are owned by the framework, and being able to lookup the needed data from the [RootIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/root-index.ts#L11) using the `getFunctionMetadata` method.
38
+ `Ⲑid` is used heavily throughout the framework for determining which classes are owned by the framework, and being able to lookup the needed data from the [RuntimeIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/runtime.ts#L11) using the `getFunctionMetadata` method.
39
39
 
40
40
  **Code: Test Class**
41
41
  ```typescript
@@ -50,10 +50,10 @@ export class TestClass {
50
50
  Object.defineProperty(exports, "__esModule", { value: true });
51
51
  exports.TestClass = void 0;
52
52
  const tslib_1 = require("tslib");
53
- const Ⲑ_root_index_1 = tslib_1.__importStar(require("@travetto/manifest/src/root-index.js"));
53
+ const Ⲑ_runtime_1 = tslib_1.__importStar(require("@travetto/manifest/src/runtime.js"));
54
54
  var ᚕf = "@travetto/manifest/doc/test-class.js";
55
55
  class TestClass {
56
- static Ⲑinit = Ⲑ_root_index_1.RootIndex.registerFunction(TestClass, ᚕf, 197152026, { doStuff: { hash: 51337554 } }, false, false);
56
+ static Ⲑinit = Ⲑ_runtime_1.RuntimeIndex.registerFunction(TestClass, ᚕf, 197152026, { doStuff: { hash: 51337554 } }, false, false);
57
57
  async doStuff() { }
58
58
  }
59
59
  exports.TestClass = TestClass;
@@ -92,19 +92,25 @@ By default, all paths within the framework are assumed to be in a POSIX style, a
92
92
  ```typescript
93
93
  {
94
94
  "generated": 1868155200000,
95
- "workspacePath": "<generated>",
96
- "monoRepo": true,
97
- "packageManager": "npm",
98
- "moduleType": "commonjs",
99
- "outputFolder": ".trv/output",
100
- "toolFolder": ".trv/tool",
101
- "compilerFolder": ".trv/compiler",
102
- "compilerUrl": "http://127.0.0.1:26803",
103
- "frameworkVersion": "x.x.x",
104
- "mainModule": "@travetto/manifest",
105
- "mainFolder": "module/manifest",
106
- "version": "x.x.x",
107
- "description": "Support for project indexing, manifesting, along with file watching",
95
+ "workspace": {
96
+ "name": "@travetto/mono-repo",
97
+ "path": "<generated>",
98
+ "mono": true,
99
+ "manager": "npm",
100
+ "type": "commonjs"
101
+ },
102
+ "build": {
103
+ "compilerFolder": ".trv/compiler",
104
+ "compilerUrl": "http://127.0.0.1:26803",
105
+ "compilerModuleFolder": "module/compiler",
106
+ "outputFolder": ".trv/output"
107
+ },
108
+ "main": {
109
+ "name": "@travetto/manifest",
110
+ "folder": "module/manifest",
111
+ "version": "x.x.x",
112
+ "description": "Support for project indexing, manifesting, along with file watching"
113
+ },
108
114
  "modules": {
109
115
  "@travetto/manifest": {
110
116
  "main": true,
@@ -136,7 +142,7 @@ By default, all paths within the framework are assumed to be in a POSIX style, a
136
142
  ],
137
143
  "test": [
138
144
  [ "test/path.ts", "ts", 1868155200000, "test" ],
139
- [ "test/root-index.ts", "ts", 1868155200000, "test" ]
145
+ [ "test/runtime.ts", "ts", 1868155200000, "test" ]
140
146
  ],
141
147
  "test/fixtures": [
142
148
  [ "test/fixtures/simple.ts", "fixture", 1868155200000, "test" ]
@@ -148,13 +154,13 @@ By default, all paths within the framework are assumed to be in a POSIX style, a
148
154
  [ "src/delta.ts", "ts", 1868155200000 ],
149
155
  [ "src/dependencies.ts", "ts", 1868155200000 ],
150
156
  [ "src/file.ts", "ts", 1868155200000 ],
157
+ [ "src/global.d.ts", "typings", 1868155200000 ],
151
158
  [ "src/manifest-index.ts", "ts", 1868155200000 ],
152
159
  [ "src/module.ts", "ts", 1868155200000 ],
153
160
  [ "src/package.ts", "ts", 1868155200000 ],
154
161
  [ "src/path.ts", "ts", 1868155200000 ],
155
- [ "src/root-index.ts", "ts", 1868155200000 ],
162
+ [ "src/runtime.ts", "ts", 1868155200000 ],
156
163
  [ "src/types.ts", "ts", 1868155200000 ],
157
- [ "src/typings.d.ts", "typings", 1868155200000 ],
158
164
  [ "src/util.ts", "ts", 1868155200000 ]
159
165
  ],
160
166
  "bin": [
package/__index__.ts CHANGED
@@ -1,10 +1,10 @@
1
- /// <reference path="./src/typings.d.ts" />
1
+ /// <reference path="./src/global.d.ts" />
2
2
 
3
3
  export * from './src/path';
4
4
  export * from './src/module';
5
5
  export * from './src/delta';
6
6
  export * from './src/manifest-index';
7
- export * from './src/root-index';
7
+ export * from './src/runtime';
8
8
  export * from './src/package';
9
9
  export * from './src/util';
10
10
  export * from './src/file';
package/bin/context.js CHANGED
@@ -5,9 +5,9 @@
5
5
  * @typedef {Pkg & { mono: boolean, manager: 'yarn'|'npm', resolve: (file:string) => string}} Workspace
6
6
  * @typedef {import('../src/types').ManifestContext} ManifestContext
7
7
  */
8
- import fs from 'fs/promises';
9
- import path from 'path';
10
- import { createRequire } from 'module';
8
+ import fs from 'node:fs/promises';
9
+ import path from 'node:path';
10
+ import { createRequire } from 'node:module';
11
11
 
12
12
  /** @type {Record<string, Workspace>} */ const WS_ROOT = {};
13
13
  const TOOL_FOLDER = '.trv/tool';
@@ -59,7 +59,7 @@ async function $resolveWorkspace(base = process.cwd()) {
59
59
  [prev, prevPkg] = [folder, pkg];
60
60
  pkg = await $readPackage(folder) ?? pkg;
61
61
  if (
62
- (pkg && (!!pkg.workspaces || !!pkg.travetto?.isolated)) || // if we have a monorepo root, or we are isolated
62
+ (pkg && (!!pkg.workspaces || !!pkg.travetto?.build?.isolated)) || // if we have a monorepo root, or we are isolated
63
63
  await fs.stat(path.resolve(folder, '.git')).catch(() => { }) // we made it to the source repo root
64
64
  ) {
65
65
  break;
@@ -73,9 +73,11 @@ async function $resolveWorkspace(base = process.cwd()) {
73
73
 
74
74
  return WS_ROOT[base] = {
75
75
  ...pkg,
76
+ name: pkg.name ?? 'untitled',
77
+ type: pkg.type,
76
78
  manager: await fs.stat(path.resolve(pkg.path, 'yarn.lock')).catch(() => { }) ? 'yarn' : 'npm',
77
79
  resolve: createRequire(`${pkg.path}/node_modules`).resolve.bind(null),
78
- mono: !!pkg.workspaces || (!pkg.travetto?.isolated && !!prevPkg) // Workspaces or nested projects
80
+ mono: !!pkg.workspaces || (!pkg.travetto?.build?.isolated && !!prevPkg) // Workspaces or nested projects
79
81
  };
80
82
  }
81
83
 
@@ -84,18 +86,15 @@ async function $resolveWorkspace(base = process.cwd()) {
84
86
  * @param {Workspace} ws
85
87
  */
86
88
  async function $getCompilerUrl(ws) {
87
- let out = ws.travetto?.compilerUrl;
88
- if (!out) {
89
- const file = path.resolve(ws.path, ws.travetto?.toolFolder ?? TOOL_FOLDER, 'compiler.url');
90
- // eslint-disable-next-line no-bitwise
91
- const port = (Math.abs([...file].reduce((a, b) => (a * 33) ^ b.charCodeAt(0), 5381)) % 29000) + 20000;
92
- out = `http://localhost:${port}`;
93
- try { await fs.stat(file); } catch {
94
- await fs.mkdir(path.dirname(file), { recursive: true });
95
- await fs.writeFile(file, out, 'utf8');
96
- }
89
+ const file = path.resolve(ws.path, TOOL_FOLDER, 'build.compilerUrl');
90
+ // eslint-disable-next-line no-bitwise
91
+ const port = (Math.abs([...file].reduce((a, b) => (a * 33) ^ b.charCodeAt(0), 5381)) % 29000) + 20000;
92
+ const out = `http://localhost:${port}`;
93
+ try { await fs.stat(file); } catch {
94
+ await fs.mkdir(path.dirname(file), { recursive: true });
95
+ await fs.writeFile(file, out, 'utf8');
97
96
  }
98
- return out.replace('localhost', '127.0.0.1');
97
+ return out;
99
98
  }
100
99
 
101
100
  /**
@@ -107,7 +106,7 @@ async function $resolveModule(workspace, folder) {
107
106
  let mod;
108
107
  if (!folder && process.env.TRV_MODULE) {
109
108
  mod = process.env.TRV_MODULE;
110
- if (/[.](t|j)s$/.test(mod)) { // Rewrite from file to module
109
+ if (/[.](t|j)sx?$/.test(mod)) { // Rewrite from file to module
111
110
  process.env.TRV_MODULE = mod = await $findPackage(path.dirname(mod))
112
111
  .then(v => v.name, () => '');
113
112
  }
@@ -136,26 +135,28 @@ async function $resolveModule(workspace, folder) {
136
135
  */
137
136
  export async function getManifestContext(folder) {
138
137
  const workspace = await $resolveWorkspace(folder);
139
-
140
- const [mod, framework, compilerUrl] = await Promise.all([
141
- $resolveModule(workspace, folder),
142
- $readPackage(workspace.resolve('@travetto/manifest/package.json')),
143
- $getCompilerUrl(workspace),
144
- ]);
138
+ const mod = await $resolveModule(workspace, folder);
139
+ const build = workspace.travetto?.build ?? {};
145
140
 
146
141
  return {
147
- workspacePath: workspace.path,
148
- monoRepo: workspace.mono,
149
- packageManager: workspace.manager,
150
- moduleType: workspace.type ?? 'commonjs',
151
- outputFolder: workspace.travetto?.outputFolder ?? OUTPUT_FOLDER,
152
- toolFolder: workspace.travetto?.toolFolder ?? TOOL_FOLDER,
153
- compilerFolder: workspace.travetto?.compilerFolder ?? COMPILER_FOLDER,
154
- compilerUrl,
155
- frameworkVersion: framework?.version ?? '1.0.0',
156
- mainModule: mod.name ?? 'untitled',
157
- mainFolder: mod.path === workspace.path ? '' : mod.path.replace(`${workspace.path}/`, ''),
158
- version: mod.version,
159
- description: mod.description
142
+ workspace: {
143
+ name: workspace.name,
144
+ path: workspace.path,
145
+ mono: workspace.mono,
146
+ manager: workspace.manager,
147
+ type: workspace.type ?? 'commonjs'
148
+ },
149
+ build: {
150
+ compilerFolder: build.compilerFolder ?? COMPILER_FOLDER,
151
+ compilerUrl: build.compilerUrl ?? await $getCompilerUrl(workspace),
152
+ compilerModuleFolder: path.dirname(workspace.resolve('@travetto/compiler/package.json')).replace(`${workspace.path}/`, ''),
153
+ outputFolder: build.outputFolder ?? OUTPUT_FOLDER,
154
+ },
155
+ main: {
156
+ name: mod.name ?? 'untitled',
157
+ folder: mod.path === workspace.path ? '' : mod.path.replace(`${workspace.path}/`, ''),
158
+ version: mod.version,
159
+ description: mod.description
160
+ }
160
161
  };
161
162
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/manifest",
3
- "version": "3.4.0-rc.3",
3
+ "version": "4.0.0-rc.0",
4
4
  "description": "Support for project indexing, manifesting, along with file watching",
5
5
  "keywords": [
6
6
  "path",
@@ -32,7 +32,9 @@
32
32
  },
33
33
  "travetto": {
34
34
  "displayName": "Manifest",
35
- "docBaseUrl": "https://github.com/travetto/travetto/tree/main"
35
+ "doc": {
36
+ "baseUrl": "https://github.com/travetto/travetto/tree/main"
37
+ }
36
38
  },
37
39
  "publishConfig": {
38
40
  "access": "public"
package/src/delta.ts CHANGED
@@ -9,7 +9,7 @@ import { path } from './path';
9
9
 
10
10
  type DeltaEventType = 'added' | 'changed' | 'removed' | 'missing' | 'dirty';
11
11
  type DeltaModule = ManifestModuleCore & { files: Record<string, ManifestModuleFile> };
12
- export type DeltaEvent = { file: string, type: DeltaEventType, module: string };
12
+ export type DeltaEvent = { file: string, type: DeltaEventType, module: string, sourceFile: string };
13
13
 
14
14
  const VALID_SOURCE_FOLDERS = new Set<ManifestModuleFolderType>(['bin', 'src', 'test', 'support', '$index', '$package', 'doc']);
15
15
  const VALID_SOURCE_TYPE = new Set<ManifestModuleFileType>(['js', 'ts', 'package-json']);
@@ -30,9 +30,9 @@ export class ManifestDeltaUtil {
30
30
  const out: DeltaEvent[] = [];
31
31
 
32
32
  const add = (file: string, type: DeltaEvent['type']): unknown =>
33
- out.push({ file, module: left.name, type });
33
+ out.push({ file, module: left.name, type, sourceFile: path.resolve(ctx.workspace.path, left.sourceFolder, file) });
34
34
 
35
- const root = `${ctx.workspacePath}/${ctx.outputFolder}/${left.outputFolder}`;
35
+ const root = path.resolve(ctx.workspace.path, ctx.build.outputFolder, left.outputFolder);
36
36
  const right = new Set(
37
37
  (await ManifestModuleUtil.scanFolder(root, left.main))
38
38
  .filter(x => {
@@ -88,14 +88,14 @@ export class ManifestDeltaUtil {
88
88
  /**
89
89
  * Produce delta between manifest root and the output folder
90
90
  */
91
- static async produceDelta(ctx: ManifestContext, manifest: ManifestRoot): Promise<DeltaEvent[]> {
91
+ static async produceDelta(manifest: ManifestRoot): Promise<DeltaEvent[]> {
92
92
  const deltaLeft = Object.fromEntries(
93
93
  Object.values(manifest.modules)
94
94
  .map(m => [m.name, { ...m, files: this.#flattenModuleFiles(m) }])
95
95
  );
96
96
 
97
97
  const out: DeltaEvent[] = [];
98
- const outputFolder = path.resolve(ctx.workspacePath, ctx.outputFolder);
98
+ const outputFolder = path.resolve(manifest.workspace.path, manifest.build.outputFolder);
99
99
 
100
100
  for (const lMod of Object.values(deltaLeft)) {
101
101
  out.push(...await this.#deltaModules(manifest, outputFolder, lMod));
@@ -1,20 +1,14 @@
1
1
  import { PackageUtil } from './package';
2
2
  import { path } from './path';
3
- import { ManifestContext, ManifestModuleRole, PackageVisitor, PackageVisitReq, Package } from './types';
3
+ import { ManifestContext, ManifestModuleRole, PackageVisitor, PackageVisitReq, Package, ManifestDepCore } from './types';
4
4
 
5
- export type ModuleDep = {
5
+ export type ModuleDep = ManifestDepCore & {
6
6
  pkg: Package;
7
- version: string;
8
- name: string;
9
- main?: boolean;
10
- mainSource?: boolean;
11
- local?: boolean;
12
- internal?: boolean;
7
+ mainLike?: boolean;
13
8
  sourcePath: string;
14
9
  childSet: Set<string>;
15
10
  parentSet: Set<string>;
16
11
  roleSet: Set<ManifestModuleRole>;
17
- prod: boolean;
18
12
  topLevel?: boolean;
19
13
  };
20
14
 
@@ -23,47 +17,36 @@ export type ModuleDep = {
23
17
  */
24
18
  export class ModuleDependencyVisitor implements PackageVisitor<ModuleDep> {
25
19
 
26
- /**
27
- * Get main patterns for detecting if a module should be treated as main
28
- */
29
- static getMainPatterns(mainModule: string, mergeModules: string[]): RegExp[] {
30
- const groups: Record<string, string[]> = { [mainModule]: [] };
31
- for (const el of mergeModules) {
32
- if (el.includes('/')) {
33
- const [grp, sub] = el.split('/');
34
- (groups[`${grp}/`] ??= []).push(sub);
35
- } else {
36
- (groups[el] ??= []);
37
- }
38
- }
39
-
40
- return Object.entries(groups)
41
- .map(([root, subs]) => subs.length ? `${root}(${subs.join('|')})` : root)
42
- .map(x => new RegExp(`^${x.replace(/[*]/g, '.*?')}$`));
43
- }
44
-
45
20
  constructor(public ctx: ManifestContext) {
46
- this.#mainSourcePath = path.resolve(this.ctx.workspacePath, this.ctx.mainFolder);
21
+ this.#mainSourcePath = path.resolve(this.ctx.workspace.path, this.ctx.main.folder);
47
22
  }
48
23
 
49
- #mainPatterns: RegExp[] = [];
24
+ #mainLikeModules = new Set<string>();
50
25
  #mainSourcePath: string;
51
26
 
27
+ /**
28
+ * Main source path for searching
29
+ */
30
+ get rootPath(): string {
31
+ return this.#mainSourcePath;
32
+ }
33
+
52
34
  /**
53
35
  * Initialize visitor, and provide global dependencies
54
36
  */
55
37
  async init(req: PackageVisitReq<ModuleDep>): Promise<PackageVisitReq<ModuleDep>[]> {
56
38
  const pkg = PackageUtil.readPackage(req.sourcePath);
57
- const workspacePkg = PackageUtil.readPackage(this.ctx.workspacePath);
39
+ const workspacePkg = PackageUtil.readPackage(this.ctx.workspace.path);
58
40
  const workspaceModules = pkg.workspaces?.length ? (await PackageUtil.resolveWorkspaces(this.ctx, req.sourcePath)) : [];
59
41
 
60
- this.#mainPatterns = ModuleDependencyVisitor.getMainPatterns(pkg.name, [
61
- ...pkg.travetto?.mainSource ?? [],
42
+ this.#mainLikeModules = new Set([
43
+ pkg.name,
44
+ ...Object.entries(pkg.travetto?.build?.withModules ?? []).filter(x => x[1] === 'main').map(x => x[0]),
62
45
  // Add workspace folders, for tests and docs
63
46
  ...workspaceModules.map(x => x.name)
64
47
  ]);
65
48
 
66
- const globals = (workspacePkg.travetto?.globalModules ?? [])
49
+ const globals = Object.keys(workspacePkg.travetto?.build?.withModules ?? [])
67
50
  .map(name => PackageUtil.packageReq<ModuleDep>(PackageUtil.resolvePackagePath(name), name in (workspacePkg.dependencies ?? {}), true));
68
51
 
69
52
  const workspaceModuleDeps = workspaceModules
@@ -87,13 +70,13 @@ export class ModuleDependencyVisitor implements PackageVisitor<ModuleDep> {
87
70
  create(req: PackageVisitReq<ModuleDep>): ModuleDep {
88
71
  const { pkg, sourcePath } = req;
89
72
  const { name, version } = pkg;
90
- const main = name === this.ctx.mainModule;
91
- const mainSource = main || this.#mainPatterns.some(x => x.test(name));
73
+ const main = name === this.ctx.main.name;
74
+ const mainLike = main || this.#mainLikeModules.has(name);
92
75
  const internal = pkg.private === true;
93
- const local = internal || mainSource || !sourcePath.includes('node_modules');
76
+ const local = internal || mainLike || !sourcePath.includes('node_modules');
94
77
 
95
- const dep = {
96
- name, version, sourcePath, main, mainSource, local, internal, pkg: req.pkg,
78
+ const dep: ModuleDep = {
79
+ name, version, sourcePath, main, mainLike, local, internal, pkg: req.pkg,
97
80
  parentSet: new Set([]), childSet: new Set([]), roleSet: new Set([]), prod: req.prod, topLevel: req.topLevel
98
81
  };
99
82
 
@@ -105,7 +88,7 @@ export class ModuleDependencyVisitor implements PackageVisitor<ModuleDep> {
105
88
  */
106
89
  visit(req: PackageVisitReq<ModuleDep>, dep: ModuleDep): void {
107
90
  const { parent } = req;
108
- if (parent && dep.name !== this.ctx.mainModule) {
91
+ if (parent && dep.name !== this.ctx.main.name) {
109
92
  dep.parentSet.add(parent.name);
110
93
  parent.childSet.add(dep.name);
111
94
  }
@@ -120,17 +103,18 @@ export class ModuleDependencyVisitor implements PackageVisitor<ModuleDep> {
120
103
  mapping.set(el.name, { parent: new Set(el.parentSet), child: new Set(el.childSet), el });
121
104
  }
122
105
 
123
- const main = mapping.get(this.ctx.mainModule)!;
106
+ const main = mapping.get(this.ctx.main.name)!;
124
107
 
125
108
  // Visit all direct dependencies and mark
126
109
  for (const { el } of mapping.values()) {
127
- if (el.topLevel) {
110
+ if (!main.child.has(el.name)) { // Not a direct descendent
111
+ el.prod = false;
112
+ }
113
+ if (main.child.has(el.name) || (el.topLevel && el !== main.el)) { // Direct descendant
128
114
  el.roleSet = new Set(el.pkg.travetto?.roles ?? []);
129
115
  if (!el.roleSet.size) {
130
116
  el.roleSet.add('std');
131
117
  }
132
- } else if (!main.child.has(el.name)) { // Not a direct descendent
133
- el.prod = false;
134
118
  }
135
119
  }
136
120
 
package/src/file.ts CHANGED
@@ -1,6 +1,6 @@
1
- import os from 'os';
2
- import fs from 'fs/promises';
3
- import { readFileSync } from 'fs';
1
+ import os from 'node:os';
2
+ import fs from 'node:fs/promises';
3
+ import { readFileSync } from 'node:fs';
4
4
 
5
5
  import { path } from './path';
6
6
  import type { ManifestContext } from './types';
@@ -48,8 +48,8 @@ export class ManifestFileUtil {
48
48
  ctx = 'manifest' in ctx ? ctx.manifest : ctx;
49
49
  const parts = [rel];
50
50
  if (moduleSpecific) {
51
- parts.unshift('node_modules', ctx.mainModule);
51
+ parts.unshift('node_modules', ctx.main.name);
52
52
  }
53
- return path.resolve(ctx.workspacePath, ctx.toolFolder, ...parts);
53
+ return path.resolve(ctx.workspace.path, '.trv/tool', ...parts);
54
54
  }
55
55
  }
@@ -77,14 +77,14 @@ export class ManifestIndex {
77
77
  const { manifest, file } = ManifestUtil.readManifestSync(manifestInput);
78
78
  this.#manifest = manifest;
79
79
  this.#manifestFile = file;
80
- this.#outputRoot = path.resolve(this.#manifest.workspacePath, this.#manifest.outputFolder);
80
+ this.#outputRoot = path.resolve(this.#manifest.workspace.path, this.#manifest.build.outputFolder);
81
81
  this.#index();
82
82
  }
83
83
 
84
84
  #moduleFiles(m: ManifestModule, files: ManifestModuleFile[]): IndexedFile[] {
85
85
  return files.map(([f, type, ts, role = 'std']) => {
86
86
  const isSource = type === 'ts' || type === 'js';
87
- const sourceFile = path.resolve(this.#manifest.workspacePath, m.sourceFolder, f);
87
+ const sourceFile = path.resolve(this.#manifest.workspace.path, m.sourceFolder, f);
88
88
  const js = isSource ? ManifestModuleUtil.sourceToOutputExt(f) : f;
89
89
  const outputFile = this.#resolveOutput(m.outputFolder, js);
90
90
  const modImport = `${m.name}/${js}`;
@@ -109,7 +109,7 @@ export class ManifestIndex {
109
109
  .map(m => ({
110
110
  ...m,
111
111
  outputPath: this.#resolveOutput(m.outputFolder),
112
- sourcePath: path.resolve(this.#manifest.workspacePath, m.sourceFolder),
112
+ sourcePath: path.resolve(this.#manifest.workspace.path, m.sourceFolder),
113
113
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
114
114
  files: Object.fromEntries(
115
115
  Object.entries(m.files).map(([folder, files]) => [folder, this.#moduleFiles(m, files ?? [])])
package/src/module.ts CHANGED
@@ -1,4 +1,4 @@
1
- import fs from 'fs/promises';
1
+ import fs from 'node:fs/promises';
2
2
 
3
3
  import { path } from './path';
4
4
  import {
@@ -26,6 +26,9 @@ const INDEX_FILES = new Set(
26
26
  )
27
27
  );
28
28
 
29
+ const STD_TOP_FOLDERS = new Set(['src', 'bin', 'support']);
30
+ const STD_TOP_FILES = new Set([...INDEX_FILES, 'package.json']);
31
+
29
32
  export class ManifestModuleUtil {
30
33
 
31
34
  static #scanCache: Record<string, string[]> = {};
@@ -44,8 +47,8 @@ export class ManifestModuleUtil {
44
47
  /**
45
48
  * Simple file scanning
46
49
  */
47
- static async scanFolder(folder: string, mainSource = false): Promise<string[]> {
48
- if (!mainSource && folder in this.#scanCache) {
50
+ static async scanFolder(folder: string, mainLike = false): Promise<string[]> {
51
+ if (!mainLike && folder in this.#scanCache) {
49
52
  return this.#scanCache[folder];
50
53
  }
51
54
 
@@ -53,8 +56,6 @@ export class ManifestModuleUtil {
53
56
  return [];
54
57
  }
55
58
 
56
- const topFolders = new Set(mainSource ? [] : ['src', 'bin', 'support']);
57
- const topFiles = new Set(mainSource ? [] : [...INDEX_FILES, 'package.json']);
58
59
  const out: string[] = [];
59
60
 
60
61
  const stack: [string, number][] = [[folder, 0]];
@@ -72,20 +73,21 @@ export class ManifestModuleUtil {
72
73
  }
73
74
 
74
75
  for (const sub of await fs.readdir(top)) {
76
+ const valid = !sub.startsWith('.') && (depth > 0 || mainLike);
75
77
  const stat = await fs.stat(`${top}/${sub}`);
76
78
  if (stat.isFile()) {
77
- if (!sub.startsWith('.') && (depth > 0 || !topFiles.size || topFiles.has(sub))) {
79
+ if (valid || STD_TOP_FILES.has(sub)) {
78
80
  out.push(`${top}/${sub}`);
79
81
  }
80
82
  } else {
81
- if (!sub.includes('node_modules') && !sub.startsWith('.') && (depth > 0 || !topFolders.size || topFolders.has(sub))) {
83
+ if (!sub.includes('node_modules') && (valid || STD_TOP_FOLDERS.has(sub))) {
82
84
  stack.push([`${top}/${sub}`, depth + 1]);
83
85
  }
84
86
  }
85
87
  }
86
88
  }
87
89
 
88
- if (!mainSource) {
90
+ if (!mainLike) {
89
91
  this.#scanCache[folder] = out;
90
92
  }
91
93
 
@@ -176,11 +178,11 @@ export class ManifestModuleUtil {
176
178
  * Visit a module and describe files, and metadata
177
179
  */
178
180
  static async describeModule(ctx: ManifestContext, dep: ModuleDep): Promise<ManifestModule> {
179
- const { main, mainSource, local, name, version, sourcePath, roleSet, prod, parentSet, internal } = dep;
181
+ const { main, mainLike, local, name, version, sourcePath, roleSet, prod, parentSet, internal } = dep;
180
182
 
181
183
  const files: ManifestModule['files'] = {};
182
184
 
183
- for (const file of await this.scanFolder(sourcePath, mainSource)) {
185
+ for (const file of await this.scanFolder(sourcePath, mainLike)) {
184
186
  // Group by top folder
185
187
  const moduleFile = file.replace(`${sourcePath}/`, '');
186
188
  const entry = await this.transformFile(moduleFile, file);
@@ -188,17 +190,19 @@ export class ManifestModuleUtil {
188
190
  (files[key] ??= []).push(entry);
189
191
  }
190
192
 
191
- // Refine non-main source
192
- if (!mainSource) {
193
+ // Refine non-main source, remove anything in root that is source (doesn't include $index)
194
+ if (!mainLike) {
193
195
  files.$root = files.$root?.filter(([file, type]) => type !== 'ts');
194
196
  }
195
197
 
196
198
  const roles = [...roleSet ?? []].sort();
197
199
  const parents = [...parentSet].sort();
198
200
  const outputFolder = `node_modules/${name}`;
199
- const sourceFolder = sourcePath === ctx.workspacePath ? '' : sourcePath.replace(`${ctx.workspacePath}/`, '');
201
+ const sourceFolder = sourcePath === ctx.workspace.path ? '' : sourcePath.replace(`${ctx.workspace.path}/`, '');
200
202
 
201
- const res = { main, name, version, local, internal, sourceFolder, outputFolder, roles, parents, prod, files };
203
+ const res: ManifestModule = {
204
+ main, name, version, local, internal, sourceFolder, outputFolder, roles, parents, prod, files
205
+ };
202
206
  return res;
203
207
  }
204
208
 
@@ -207,8 +211,7 @@ export class ManifestModuleUtil {
207
211
  */
208
212
  static async produceModules(ctx: ManifestContext): Promise<Record<string, ManifestModule>> {
209
213
  const visitor = new ModuleDependencyVisitor(ctx);
210
- const mainPath = path.resolve(ctx.workspacePath, ctx.mainFolder);
211
- const declared = await PackageUtil.visitPackages(mainPath, visitor);
214
+ const declared = await PackageUtil.visitPackages(visitor);
212
215
  const sorted = [...declared].sort((a, b) => a.name.localeCompare(b.name));
213
216
  const modules = await Promise.all(sorted.map(x => this.describeModule(ctx, x)));
214
217
  return Object.fromEntries(modules.map(m => [m.name, m]));
package/src/package.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { createRequire } from 'module';
2
- import { execSync } from 'child_process';
1
+ import { createRequire } from 'node:module';
2
+ import { execSync } from 'node:child_process';
3
3
 
4
- import { ManifestContext, Package, PackageVisitor, PackageVisitReq, PackageWorkspaceEntry } from './types';
4
+ import type { ManifestContext, NodePackageManager, Package, PackageVisitor, PackageVisitReq, PackageWorkspaceEntry } from './types';
5
5
  import { path } from './path';
6
6
  import { ManifestFileUtil } from './file';
7
7
 
@@ -10,7 +10,7 @@ import { ManifestFileUtil } from './file';
10
10
  */
11
11
  export class PackageUtil {
12
12
 
13
- static #req = createRequire(path.resolve('node_modules'));
13
+ static #resolvers: Record<string, (imp: string) => string> = {};
14
14
  static #cache: Record<string, Package> = {};
15
15
  static #workspaces: Record<string, PackageWorkspaceEntry[]> = {};
16
16
 
@@ -21,15 +21,13 @@ export class PackageUtil {
21
21
  }
22
22
 
23
23
  /**
24
- * Clear out cached package file reads
24
+ * Resolve import given a manifest context
25
25
  */
26
- static clearCache(): void {
27
- this.#cache = {};
28
- this.#workspaces = {};
26
+ static resolveImport(imp: string, root?: string): string {
27
+ const loc = path.resolve(root ?? '.', 'node_modules');
28
+ return (this.#resolvers[loc] ??= createRequire(loc).resolve.bind(null))(imp);
29
29
  }
30
30
 
31
- static resolveImport = (library: string): string => this.#req.resolve(library);
32
-
33
31
  /**
34
32
  * Resolve version path, if file: url
35
33
  */
@@ -44,12 +42,12 @@ export class PackageUtil {
44
42
  /**
45
43
  * Find package.json folder for a given dependency
46
44
  */
47
- static resolvePackagePath(name: string): string {
45
+ static resolvePackagePath(name: string, root?: string): string {
48
46
  try {
49
- return path.dirname(this.resolveImport(`${name}/package.json`));
47
+ return path.dirname(this.resolveImport(`${name}/package.json`, root));
50
48
  } catch {
51
49
  try {
52
- const resolved = this.resolveImport(name);
50
+ const resolved = this.resolveImport(name, root);
53
51
  return path.join(resolved.split(name)[0], name);
54
52
  } catch { }
55
53
  }
@@ -107,14 +105,9 @@ export class PackageUtil {
107
105
  /**
108
106
  * Visit packages with ability to track duplicates
109
107
  */
110
- static async visitPackages<T>(
111
- rootOrPath: PackageVisitReq<T> | string,
112
- visitor: PackageVisitor<T>
113
- ): Promise<Set<T>> {
108
+ static async visitPackages<T>(visitor: PackageVisitor<T>): Promise<Set<T>> {
114
109
 
115
- const root = typeof rootOrPath === 'string' ?
116
- this.packageReq<T>(rootOrPath, false, true) :
117
- rootOrPath;
110
+ const root = this.packageReq<T>(visitor.rootPath, false, true);
118
111
 
119
112
  const seen = new Map<string, T>();
120
113
  const queue: PackageVisitReq<T>[] = [...await visitor.init?.(root) ?? [], root];
@@ -155,12 +148,12 @@ export class PackageUtil {
155
148
  */
156
149
  static async resolveWorkspaces(ctx: ManifestContext, rootPath: string): Promise<PackageWorkspaceEntry[]> {
157
150
  if (!this.#workspaces[rootPath]) {
158
- const cache = path.resolve(ctx.workspacePath, ctx.outputFolder, 'workspaces.json');
151
+ const cache = path.resolve(ctx.workspace.path, ctx.build.outputFolder, 'workspaces.json');
159
152
  try {
160
153
  return await ManifestFileUtil.readAsJson(cache);
161
154
  } catch (err) {
162
155
  let out: PackageWorkspaceEntry[];
163
- switch (ctx.packageManager) {
156
+ switch (ctx.workspace.manager) {
164
157
  case 'npm': {
165
158
  const res = await this.#exec<{ location: string, name: string }[]>(rootPath, 'npm query .workspace');
166
159
  out = res.map(d => ({ sourcePath: d.location, name: d.name }));
@@ -180,4 +173,16 @@ export class PackageUtil {
180
173
  }
181
174
  return this.#workspaces[rootPath];
182
175
  }
176
+
177
+ /**
178
+ * Get an install command for a given npm module
179
+ */
180
+ static getInstallCommand(ctx: { workspace: { manager: NodePackageManager } }, pkg: string, prod = false): string {
181
+ let install: string;
182
+ switch (ctx.workspace.manager) {
183
+ case 'npm': install = `npm i ${prod ? '' : '--save-dev '}${pkg}`; break;
184
+ case 'yarn': install = `yarn add ${prod ? '' : '--dev '}${pkg}`; break;
185
+ }
186
+ return install;
187
+ }
183
188
  }
package/src/path.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type * as pathMod from 'path';
2
- import { extname, dirname, basename, resolve, join } from 'path/posix';
3
- import { sep, resolve as nativeResolve, join as nativeJoin } from 'path';
1
+ import type * as pathMod from 'node:path';
2
+ import { extname, dirname, basename, resolve, join } from 'node:path/posix';
3
+ import { sep, resolve as nativeResolve, join as nativeJoin } from 'node:path';
4
4
 
5
5
  /**
6
6
  * Converts a given file name by replace all slashes, with forward slashes
@@ -1,6 +1,6 @@
1
1
  import { path } from './path';
2
2
  import { IndexedModule, ManifestIndex } from './manifest-index';
3
- import { FunctionMetadata, ManifestContext } from './types';
3
+ import { FunctionMetadata, ManifestContext, ManifestModule } from './types';
4
4
 
5
5
  const METADATA = Symbol.for('@travetto/manifest:metadata');
6
6
  type Metadated = { [METADATA]: FunctionMetadata };
@@ -8,7 +8,7 @@ type Metadated = { [METADATA]: FunctionMetadata };
8
8
  /**
9
9
  * Extended manifest index geared for application execution
10
10
  */
11
- class $RootIndex extends ManifestIndex {
11
+ class $RuntimeIndex extends ManifestIndex {
12
12
 
13
13
  #metadata = new Map<string, FunctionMetadata>();
14
14
 
@@ -20,13 +20,6 @@ class $RootIndex extends ManifestIndex {
20
20
  this.init(`${this.outputRoot}/node_modules/${module}`);
21
21
  }
22
22
 
23
- /**
24
- * Determines if the manifest root is the root for a monorepo
25
- */
26
- isMonoRepoRoot(): boolean {
27
- return !!this.manifest.monoRepo && !this.manifest.mainFolder;
28
- }
29
-
30
23
  /**
31
24
  * Get internal id from file name and optionally, class name
32
25
  */
@@ -36,29 +29,11 @@ class $RootIndex extends ManifestIndex {
36
29
  return clsName ? `${id}○${clsName}` : id;
37
30
  }
38
31
 
39
- /**
40
- * Get main module name
41
- */
42
- get mainModuleName(): string {
43
- return this.manifest.mainModule;
44
- }
45
-
46
32
  /**
47
33
  * Get main module for manifest
48
34
  */
49
35
  get mainModule(): IndexedModule {
50
- return this.getModule(this.mainModuleName)!;
51
- }
52
-
53
- /**
54
- * Digest manifest
55
- */
56
- manifestDigest(): Pick<ManifestContext, 'mainModule' | 'frameworkVersion' | 'version'> {
57
- return {
58
- mainModule: this.manifest.mainModule,
59
- frameworkVersion: this.manifest.frameworkVersion,
60
- version: this.manifest.version,
61
- };
36
+ return this.getModule(this.manifest.main.name)!;
62
37
  }
63
38
 
64
39
  /**
@@ -102,16 +77,50 @@ class $RootIndex extends ManifestIndex {
102
77
  const id = clsId === undefined ? '' : typeof clsId === 'string' ? clsId : clsId.Ⲑid;
103
78
  return this.#metadata.get(id);
104
79
  }
105
- }
106
80
 
107
- let index: $RootIndex | undefined;
81
+ /**
82
+ * Resolve module path to folder, with support for main module and monorepo support
83
+ */
84
+ resolveModulePath(modulePath: string): string {
85
+ const main = this.manifest.main.name;
86
+ const workspace = this.manifest.workspace.path;
87
+ const [base, sub] = modulePath
88
+ .replace(/^(@@?)(#|$)/g, (_, v, r) => `${v === '@' ? main : workspace}${r}`)
89
+ .split('#');
90
+ return path.resolve(this.hasModule(base) ? this.getModule(base)!.sourcePath : base, sub ?? '.');
91
+ }
92
+
93
+ /**
94
+ * Get manifest module by name
95
+ */
96
+ getManifestModule(mod: string): ManifestModule {
97
+ return this.manifest.modules[mod];
98
+ }
108
99
 
109
- try {
110
- index = new $RootIndex(process.env.TRV_MANIFEST!);
111
- } catch (err) {
112
- if (/prod/i.test(process.env.NODE_ENV ?? '')) {
113
- throw err;
100
+ /**
101
+ * Get manifest modules
102
+ */
103
+ getManifestModules(): ManifestModule[] {
104
+ return Object.values(this.manifest.modules);
114
105
  }
115
106
  }
116
107
 
117
- export const RootIndex: $RootIndex = index!;
108
+ export const RuntimeIndex = new $RuntimeIndex(process.env.TRV_MANIFEST!);
109
+
110
+ const build = <T extends object>(inp: T, props: (keyof ManifestContext)[]): T & ManifestContext => {
111
+ for (const prop of props) {
112
+ Object.defineProperty(inp, prop, { configurable: false, get: () => RuntimeIndex.manifest[prop] });
113
+ }
114
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
115
+ return inp as T & ManifestContext;
116
+ };
117
+
118
+ export const RuntimeContext = build({
119
+ /**
120
+ * Produce a workspace relative path
121
+ * @param rel The relative path
122
+ */
123
+ workspaceRelative(...rel: string[]): string {
124
+ return path.resolve(RuntimeIndex.manifest.workspace.path, ...rel);
125
+ }
126
+ }, ['main', 'workspace']);
package/src/types.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export type NodeModuleType = 'module' | 'commonjs';
2
+ export type NodePackageManager = 'yarn' | 'npm';
2
3
 
3
4
  export type ManifestModuleFileType = 'typings' | 'ts' | 'js' | 'json' | 'package-json' | 'unknown' | 'fixture' | 'md';
4
5
  export type ManifestModuleFolderType =
@@ -10,17 +11,19 @@ export type ManifestModuleFolderType =
10
11
  export type ManifestModuleRole = 'std' | 'test' | 'doc' | 'compile' | 'build';
11
12
 
12
13
  export type ManifestModuleFile = [string, ManifestModuleFileType, number] | [string, ManifestModuleFileType, number, ManifestModuleRole];
13
- export type ManifestModuleCore = {
14
+ export type ManifestDepCore = {
14
15
  name: string;
15
16
  main?: boolean;
16
17
  local?: boolean;
17
18
  version: string;
19
+ prod: boolean;
20
+ internal?: boolean;
21
+ };
22
+ export type ManifestModuleCore = ManifestDepCore & {
18
23
  sourceFolder: string;
19
24
  outputFolder: string;
20
- prod: boolean;
21
25
  roles: ManifestModuleRole[];
22
26
  parents: string[];
23
- internal?: boolean;
24
27
  };
25
28
 
26
29
  export type ManifestModule = ManifestModuleCore & {
@@ -28,19 +31,38 @@ export type ManifestModule = ManifestModuleCore & {
28
31
  };
29
32
 
30
33
  export type ManifestContext = {
31
- mainModule: string;
32
- mainFolder: string;
33
- workspacePath: string;
34
- outputFolder: string;
35
- toolFolder: string;
36
- compilerFolder: string;
37
- monoRepo?: boolean;
38
- moduleType: NodeModuleType;
39
- packageManager: 'yarn' | 'npm';
40
- frameworkVersion: string;
41
- description?: string;
42
- version: string;
43
- compilerUrl: string;
34
+ workspace: {
35
+ /** Workspace path for module */
36
+ path: string;
37
+ /** The module name for the workspace root */
38
+ name: string;
39
+ /** Is the workspace a monorepo? */
40
+ mono?: boolean;
41
+ /** The module type of the workspace */
42
+ type: NodeModuleType;
43
+ /** The package manager of the workspace */
44
+ manager: NodePackageManager;
45
+ };
46
+ build: {
47
+ /** Compiler folder, relative to workspace */
48
+ compilerFolder: string;
49
+ /** Compiler module folder */
50
+ compilerModuleFolder: string;
51
+ /** URL for the compiler server */
52
+ compilerUrl: string;
53
+ /** Code output folder, relative to workspace */
54
+ outputFolder: string;
55
+ };
56
+ main: {
57
+ /** Main module for manifest */
58
+ name: string;
59
+ /** Folder, relative to workspace for main module */
60
+ folder: string;
61
+ /** Description of the main module */
62
+ description?: string;
63
+ /** Version of the main module */
64
+ version: string;
65
+ };
44
66
  };
45
67
 
46
68
  export type ManifestRoot = ManifestContext & {
@@ -76,19 +98,18 @@ export type Package = {
76
98
  peerDependenciesMeta?: Record<string, { optional?: boolean }>;
77
99
  optionalDependencies?: Record<string, string>;
78
100
  travetto?: {
79
- isolated?: boolean;
80
101
  displayName?: string;
81
102
  roles?: ManifestModuleRole[];
82
- globalModules?: string[];
83
- mainSource?: string[];
84
- docOutput?: string[];
85
- docRoot?: string;
86
- docBaseUrl?: string;
87
- docOutputs?: string[];
88
- outputFolder?: string;
89
- toolFolder?: string;
90
- compilerFolder?: string;
91
- compilerUrl?: string;
103
+ doc?: {
104
+ output?: string[];
105
+ root?: string;
106
+ baseUrl?: string;
107
+ outputs?: string[];
108
+ };
109
+ build?: Partial<ManifestContext['build']> & {
110
+ isolated?: boolean;
111
+ withModules?: Record<string, 'main' | true>;
112
+ };
92
113
  };
93
114
  workspaces?: string[];
94
115
  private?: boolean;
@@ -99,6 +120,7 @@ type OrProm<T> = T | Promise<T>;
99
120
 
100
121
  export type PackageVisitReq<T> = { pkg: Package, prod: boolean, sourcePath: string, parent?: T, topLevel?: boolean };
101
122
  export type PackageVisitor<T> = {
123
+ rootPath: string;
102
124
  init?(req: PackageVisitReq<T>): OrProm<undefined | void | PackageVisitReq<T>[]>;
103
125
  valid?(req: PackageVisitReq<T>): boolean;
104
126
  create(req: PackageVisitReq<T>): OrProm<T>;
package/src/util.ts CHANGED
@@ -2,6 +2,7 @@ import { path } from './path';
2
2
  import { ManifestContext, ManifestRoot } from './types';
3
3
  import { ManifestModuleUtil } from './module';
4
4
  import { ManifestFileUtil } from './file';
5
+ import { PackageUtil } from './package';
5
6
 
6
7
  const MANIFEST_FILE = 'manifest.json';
7
8
 
@@ -9,15 +10,6 @@ const MANIFEST_FILE = 'manifest.json';
9
10
  * Manifest utils
10
11
  */
11
12
  export class ManifestUtil {
12
- /**
13
- * Build a manifest context
14
- * @param folder
15
- */
16
- static async buildContext(folder?: string): Promise<ManifestContext> {
17
- const { getManifestContext } = await import('../bin/context.js');
18
- return getManifestContext(folder);
19
- }
20
-
21
13
  /**
22
14
  * Produce manifest in memory
23
15
  */
@@ -41,9 +33,11 @@ export class ManifestUtil {
41
33
  .filter(x => x.prod)
42
34
  .map(m => [m.name, m])
43
35
  ),
44
- // Mark output folder/workspace path as portable
45
- outputFolder: '',
46
- workspacePath: '',
36
+ build: {
37
+ ...manifest.build,
38
+ // Mark output folder/workspace path as portable
39
+ outputFolder: '$$PRODUCTION$$',
40
+ }
47
41
  };
48
42
  }
49
43
 
@@ -59,10 +53,10 @@ export class ManifestUtil {
59
53
  file = path.resolve(file, MANIFEST_FILE);
60
54
  }
61
55
  const manifest: ManifestRoot = ManifestFileUtil.readAsJsonSync(file);
62
- // Support packaged environments, by allowing empty outputFolder
63
- if (!manifest.outputFolder) {
64
- manifest.outputFolder = path.cwd();
65
- manifest.workspacePath = path.cwd();
56
+ // Support packaged environments, by allowing empty manifest.build.outputFolder
57
+ if (manifest.build.outputFolder === '$$PRODUCTION$$') {
58
+ manifest.build.outputFolder = path.cwd();
59
+ manifest.workspace.path = path.cwd();
66
60
  }
67
61
  return { manifest, file };
68
62
  }
@@ -70,10 +64,10 @@ export class ManifestUtil {
70
64
  /**
71
65
  * Write manifest for a given context, return location
72
66
  */
73
- static writeManifest(ctx: ManifestContext, manifest: ManifestRoot): Promise<string> {
74
- return ManifestFileUtil.bufferedFileWrite(
75
- path.resolve(ctx.workspacePath, ctx.outputFolder, 'node_modules', ctx.mainModule, MANIFEST_FILE),
76
- JSON.stringify(manifest)
67
+ static writeManifest(manifest: ManifestRoot): Promise<string> {
68
+ return this.writeManifestToFile(
69
+ path.resolve(manifest.workspace.path, manifest.build.outputFolder, 'node_modules', manifest.main.name),
70
+ manifest
77
71
  );
78
72
  }
79
73
 
@@ -91,11 +85,34 @@ export class ManifestUtil {
91
85
  }
92
86
 
93
87
  /**
94
- * Rewrite manifest for a given folder
88
+ * Produce the manifest context for the workspace module
95
89
  */
96
- static async rewriteManifest(source: string): Promise<void> {
97
- const subCtx = await this.buildContext(source);
98
- const subManifest = await this.buildManifest(subCtx);
99
- await this.writeManifest(subCtx, subManifest);
90
+ static getWorkspaceContext(ctx: ManifestContext): ManifestContext {
91
+ return ctx.workspace.mono ? {
92
+ ...ctx,
93
+ main: {
94
+ name: ctx.workspace.name,
95
+ folder: '',
96
+ version: '0.0.0',
97
+ }
98
+ } : ctx;
99
+ }
100
+
101
+ /**
102
+ * Produce the manifest context for a given module module
103
+ */
104
+ static getModuleContext(ctx: ManifestContext, folder: string): ManifestContext {
105
+ const modPath = path.resolve(ctx.workspace.path, folder);
106
+ const pkg = PackageUtil.readPackage(modPath);
107
+
108
+ return {
109
+ ...ctx,
110
+ main: {
111
+ name: pkg.name,
112
+ folder,
113
+ version: pkg.version,
114
+ description: pkg.description
115
+ }
116
+ };
100
117
  }
101
118
  }
@@ -9,16 +9,16 @@ const MANIFEST_MOD = '@travetto/manifest';
9
9
  const MANIFEST_IDX = `${MANIFEST_MOD}/__index__`;
10
10
  const ENTRY_POINT = 'support/entry';
11
11
 
12
- const ROOT_IDX_IMPORT = `${MANIFEST_MOD}/src/root-index`;
13
- const ROOT_IDX_CLS = 'RootIndex';
12
+ const RUNTIME_IDX_IMPORT = `${MANIFEST_MOD}/src/runtime`;
13
+ const RUNTIME_IDX_CLS = 'RuntimeIndex';
14
14
 
15
15
  const methods = Symbol.for(`${MANIFEST_MOD}:methods`);
16
16
  const cls = Symbol.for(`${MANIFEST_MOD}:class`);
17
17
  const fn = Symbol.for(`${MANIFEST_MOD}:function`);
18
- const rootIdx = Symbol.for(`${MANIFEST_MOD}:rootIndex`);
18
+ const runtimeIdx = Symbol.for(`${MANIFEST_MOD}:runtimeIndex`);
19
19
 
20
20
  interface MetadataInfo {
21
- [rootIdx]?: Import;
21
+ [runtimeIdx]?: Import;
22
22
  [methods]?: {
23
23
  [key: string]: { hash: number };
24
24
  };
@@ -72,8 +72,8 @@ export class RegisterTransformer {
72
72
  return node;
73
73
  }
74
74
 
75
- state[rootIdx] ??= state.importFile(ROOT_IDX_IMPORT);
76
- const ident = state.createAccess(state[rootIdx].ident, ROOT_IDX_CLS);
75
+ state[runtimeIdx] ??= state.importFile(RUNTIME_IDX_IMPORT);
76
+ const ident = state.createAccess(state[runtimeIdx].ident, RUNTIME_IDX_CLS);
77
77
 
78
78
  const name = node.name?.escapedText.toString() ?? '';
79
79
 
@@ -117,8 +117,8 @@ export class RegisterTransformer {
117
117
 
118
118
  if (ts.isFunctionDeclaration(node) && node.name && node.parent && ts.isSourceFile(node.parent)) {
119
119
  // If we have a class like function
120
- state[rootIdx] ??= state.importFile(ROOT_IDX_IMPORT);
121
- const ident = state.createAccess(state[rootIdx].ident, ROOT_IDX_CLS);
120
+ state[runtimeIdx] ??= state.importFile(RUNTIME_IDX_IMPORT);
121
+ const ident = state.createAccess(state[runtimeIdx].ident, RUNTIME_IDX_CLS);
122
122
  const meta = state.factory.createCallExpression(
123
123
  state.createAccess(ident, 'registerFunction'),
124
124
  [],
File without changes