@travetto/manifest 4.0.0-rc.1 → 4.0.0-rc.3

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/context.js CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  /**
4
4
  * @typedef {import('../src/types/package').Package & { path:string }} Pkg
5
- * @typedef {Pkg & { mono: boolean, manager: 'yarn'|'npm', resolve: (file:string) => string}} Workspace
5
+ * @typedef {Pkg & { mono: boolean, manager: 'yarn'|'npm', resolve: (file:string) => string, stripRoot: (file:string)=>string}} Workspace
6
6
  * @typedef {import('../src/types/context').ManifestContext} ManifestContext
7
7
  */
8
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
8
+ import { existsSync, readFileSync } from 'node:fs';
9
9
  import path from 'node:path';
10
10
  import { createRequire } from 'node:module';
11
11
 
@@ -79,6 +79,7 @@ function $resolveWorkspace(base = process.cwd()) {
79
79
  type: pkg.type,
80
80
  manager: existsSync(path.resolve(pkg.path, 'yarn.lock')) ? 'yarn' : 'npm',
81
81
  resolve: createRequire(`${pkg.path}/node_modules`).resolve.bind(null),
82
+ stripRoot: (full) => full === pkg.path ? '' : full.replace(`${pkg.path}/`, ''),
82
83
  mono: !!pkg.workspaces || (!pkg.travetto?.build?.isolated && !!prevPkg) // Workspaces or nested projects
83
84
  };
84
85
  }
@@ -86,18 +87,11 @@ function $resolveWorkspace(base = process.cwd()) {
86
87
  /**
87
88
  * Get Compiler url
88
89
  * @param {Workspace} ws
89
- * @param {string} toolFolder
90
90
  */
91
- function $getCompilerUrl(ws, toolFolder) {
92
- const file = path.resolve(ws.path, toolFolder, 'build.compilerUrl');
91
+ function $getCompilerUrl(ws) {
93
92
  // eslint-disable-next-line no-bitwise
94
- const port = (Math.abs([...file].reduce((a, b) => (a * 33) ^ b.charCodeAt(0), 5381)) % 29000) + 20000;
95
- const out = `http://localhost:${port}`;
96
- if (!existsSync(file)) {
97
- mkdirSync(path.dirname(file), { recursive: true });
98
- writeFileSync(file, out, 'utf8');
99
- }
100
- return out;
93
+ const port = (Math.abs([...ws.path].reduce((a, b) => (a * 33) ^ b.charCodeAt(0), 5381)) % 29000) + 20000;
94
+ return `http://localhost:${port}`;
101
95
  }
102
96
 
103
97
  /**
@@ -156,14 +150,14 @@ export function getManifestContext(folder) {
156
150
  },
157
151
  build: {
158
152
  compilerFolder: build.compilerFolder ?? COMPILER_FOLDER,
159
- compilerUrl: build.compilerUrl ?? $getCompilerUrl(workspace, toolFolder),
160
- compilerModuleFolder: path.dirname(workspace.resolve('@travetto/compiler/package.json')).replace(`${workspace.path}/`, ''),
153
+ compilerUrl: build.compilerUrl ?? $getCompilerUrl(workspace),
154
+ compilerModuleFolder: workspace.stripRoot(path.dirname(workspace.resolve('@travetto/compiler/package.json'))),
161
155
  outputFolder: build.outputFolder ?? OUTPUT_FOLDER,
162
156
  toolFolder
163
157
  },
164
158
  main: {
165
159
  name: mod.name ?? 'untitled',
166
- folder: mod.path === workspace.path ? '' : mod.path.replace(`${workspace.path}/`, ''),
160
+ folder: workspace.stripRoot(mod.path),
167
161
  version: mod.version,
168
162
  description: mod.description
169
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/manifest",
3
- "version": "4.0.0-rc.1",
3
+ "version": "4.0.0-rc.3",
4
4
  "description": "Support for project indexing, manifesting, along with file watching",
5
5
  "keywords": [
6
6
  "path",
@@ -1,16 +1,27 @@
1
1
  import { PackageUtil } from './package';
2
2
  import { path } from './path';
3
3
 
4
- import type { Package, PackageDepType, PackageVisitReq, PackageVisitor } from './types/package';
4
+ import type { Package, PackageDepType } from './types/package';
5
5
  import type { ManifestContext } from './types/context';
6
6
  import type { PackageModule } from './types/manifest';
7
7
 
8
- type CreateOpts = Partial<Pick<PackageModule, 'main' | 'workspace' | 'prod'>> & { roleRoot?: boolean };
8
+ type CreateOpts = Partial<Pick<PackageModule, 'main' | 'workspace' | 'prod'>> & { roleRoot?: boolean, parent?: PackageModule };
9
+
10
+ type Req = {
11
+ /** Request package */
12
+ pkg: Package;
13
+ /** Children to visit */
14
+ children: Record<string, string>;
15
+ /** Value */
16
+ value: PackageModule;
17
+ /** Parent */
18
+ parent?: PackageModule;
19
+ };
9
20
 
10
21
  /**
11
22
  * Used for walking dependencies for collecting modules for the manifest
12
23
  */
13
- export class PackageModuleVisitor implements PackageVisitor<PackageModule> {
24
+ export class PackageModuleVisitor {
14
25
 
15
26
  constructor(public ctx: ManifestContext) {
16
27
  this.#mainSourcePath = path.resolve(this.ctx.workspace.path, this.ctx.main.folder);
@@ -23,9 +34,8 @@ export class PackageModuleVisitor implements PackageVisitor<PackageModule> {
23
34
  /**
24
35
  * Initialize visitor, and provide global dependencies
25
36
  */
26
- async init(): Promise<Iterable<PackageVisitReq<PackageModule>>> {
27
- const mainPkg = PackageUtil.readPackage(this.#mainSourcePath);
28
- const mainReq = this.create(mainPkg, { main: true, workspace: true, roleRoot: true, prod: true });
37
+ async init(): Promise<Iterable<Req>> {
38
+ const mainReq = this.#create(this.#mainSourcePath, { main: true, workspace: true, roleRoot: true, prod: true });
29
39
  const globals = [mainReq];
30
40
  this.#workspaceModules = new Map(
31
41
  (await PackageUtil.resolveWorkspaces(this.ctx)).map(x => [x.name, x.path])
@@ -34,33 +44,26 @@ export class PackageModuleVisitor implements PackageVisitor<PackageModule> {
34
44
  // Treat all workspace modules as main modules
35
45
  if (this.ctx.workspace.mono && !this.ctx.main.folder) {
36
46
  for (const [, loc] of this.#workspaceModules) {
37
- const depPkg = PackageUtil.readPackage(loc);
38
- globals.push(this.create(depPkg, { main: true, workspace: true, roleRoot: true }));
47
+ globals.push(this.#create(loc, { main: true, workspace: true, roleRoot: true, parent: mainReq.value }));
39
48
  }
40
49
  } else {
41
50
  // If we have 'withModules' at workspace root
42
51
  const root = PackageUtil.readPackage(this.ctx.workspace.path);
43
52
  for (const [name, type] of Object.entries(root.travetto?.build?.withModules ?? {})) {
44
- const depPkg = PackageUtil.readPackage(PackageUtil.resolvePackagePath(name));
45
- globals.push(this.create(depPkg, { main: type === 'main', workspace: true }));
53
+ globals.push(this.#create(PackageUtil.resolvePackagePath(name),
54
+ { main: type === 'main', workspace: true, parent: mainReq.value }
55
+ ));
46
56
  }
47
57
  }
48
58
 
49
- return globals.map((x, i) => i === 0 ? x : { ...x, parent: mainReq.value });
50
- }
51
-
52
- /**
53
- * Is valid dependency for searching
54
- */
55
- valid({ value: node }: PackageVisitReq<PackageModule>): boolean {
56
- return node.workspace || !!node.state.travetto; // Workspace or travetto module
59
+ return globals;
57
60
  }
58
61
 
59
62
  /**
60
63
  * Build a package module
61
64
  */
62
- create(pkg: Package, { main, workspace, prod = false, roleRoot = false }: CreateOpts = {}): PackageVisitReq<PackageModule> {
63
- const sourcePath = PackageUtil.getPackagePath(pkg);
65
+ #create(sourcePath: string, { main, workspace, prod = false, roleRoot = false, parent }: CreateOpts = {}): Req {
66
+ const pkg = PackageUtil.readPackage(sourcePath);
64
67
  const value = this.#cache[sourcePath] ??= {
65
68
  main,
66
69
  prod,
@@ -78,24 +81,13 @@ export class PackageModuleVisitor implements PackageVisitor<PackageModule> {
78
81
 
79
82
  const deps: PackageDepType[] = ['dependencies', ...(value.main ? ['devDependencies'] as const : [])];
80
83
  const children = Object.fromEntries(deps.flatMap(x => Object.entries(pkg[x] ?? {})));
81
- return { pkg, value, children };
82
- }
83
-
84
- /**
85
- * Visit dependency
86
- */
87
- visit({ value: mod, parent }: PackageVisitReq<PackageModule>): void {
88
- if (mod.name === this.ctx.main.name) { return; } // Skip root
89
- if (parent) {
90
- mod.state.parentSet.add(parent.name);
91
- parent.state.childSet.add(mod.name);
92
- }
84
+ return { pkg, value, children, parent };
93
85
  }
94
86
 
95
87
  /**
96
88
  * Propagate prod, role information through graph
97
89
  */
98
- async complete(mods: Iterable<PackageModule>): Promise<PackageModule[]> {
90
+ async #complete(mods: Iterable<PackageModule>): Promise<PackageModule[]> {
99
91
  const mapping = new Map([...mods].map(el => [el.name, { parent: new Set(el.state.parentSet), el }]));
100
92
 
101
93
  // All first-level dependencies should have role filled in (for propagation)
@@ -144,4 +136,40 @@ export class PackageModuleVisitor implements PackageVisitor<PackageModule> {
144
136
 
145
137
  return [...mods].sort((a, b) => a.name.localeCompare(b.name));
146
138
  }
139
+
140
+
141
+ /**
142
+ * Visit packages with ability to track duplicates
143
+ */
144
+ async visit(): Promise<Iterable<PackageModule>> {
145
+ const seen = new Set<PackageModule>();
146
+ const queue = [...await this.init()];
147
+
148
+ while (queue.length) {
149
+ const { value: node, parent, children, pkg } = queue.shift()!; // Visit initial set first
150
+ if (!node || (!node.workspace && !node.state.travetto)) {
151
+ continue;
152
+ }
153
+
154
+ // Track parentage
155
+ if (node.name !== this.ctx.main.name && parent) {
156
+ node.state.parentSet.add(parent.name);
157
+ parent.state.childSet.add(node.name);
158
+ }
159
+
160
+ if (seen.has(node)) {
161
+ continue;
162
+ } else {
163
+ seen.add(node);
164
+ }
165
+
166
+ const next = Object.entries(children)
167
+ .map(([n, v]) => PackageUtil.resolveVersionPath(pkg, v) ?? PackageUtil.resolvePackagePath(n))
168
+ .map(loc => this.#create(loc, { parent: node }));
169
+
170
+ queue.push(...next);
171
+ }
172
+
173
+ return await this.#complete(seen);
174
+ }
147
175
  }
package/src/module.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import fs from 'node:fs/promises';
2
2
 
3
3
  import { path } from './path';
4
- import { PackageUtil } from './package';
5
4
  import { PackageModuleVisitor } from './dependencies';
6
5
 
7
6
  import type { ManifestModuleFileType, ManifestModuleRole, ManifestModuleFolderType } from './types/common';
@@ -198,7 +197,7 @@ export class ManifestModuleUtil {
198
197
  * Produce all modules for a given manifest folder, adding in some given modules when developing framework
199
198
  */
200
199
  static async produceModules(ctx: ManifestContext): Promise<Record<string, ManifestModule>> {
201
- const pkgs = await PackageUtil.visitPackages(new PackageModuleVisitor(ctx));
200
+ const pkgs = await new PackageModuleVisitor(ctx).visit();
202
201
  const modules = await Promise.all([...pkgs].map(x => this.describeModule(ctx, x)));
203
202
  return Object.fromEntries(modules.map(m => [m.name, m]));
204
203
  }
package/src/package.ts CHANGED
@@ -4,7 +4,7 @@ import { execSync } from 'node:child_process';
4
4
  import { path } from './path';
5
5
  import { ManifestFileUtil } from './file';
6
6
 
7
- import { PackagePath, type Package, type PackageVisitor, type PackageWorkspaceEntry } from './types/package';
7
+ import { PackagePath, type Package, type PackageWorkspaceEntry } from './types/package';
8
8
  import type { ManifestContext } from './types/context';
9
9
  import type { NodePackageManager } from './types/common';
10
10
 
@@ -81,38 +81,6 @@ export class PackageUtil {
81
81
  return pkg[PackagePath];
82
82
  }
83
83
 
84
- /**
85
- * Visit packages with ability to track duplicates
86
- */
87
- static async visitPackages<T>(visitor: PackageVisitor<T>): Promise<Iterable<T>> {
88
- const seen = new Set<T>();
89
- const queue = [...await visitor.init()];
90
-
91
- while (queue.length) {
92
- const node = queue.shift()!; // Visit initial set first
93
-
94
- if (!visitor.valid(node)) {
95
- continue;
96
- }
97
-
98
- visitor.visit(node);
99
-
100
- if (seen.has(node.value)) {
101
- continue;
102
- } else {
103
- seen.add(node.value);
104
- }
105
-
106
- const children = Object.entries(node.children)
107
- .map(([n, v]) => this.readPackage(this.resolveVersionPath(node.pkg, v) ?? this.resolvePackagePath(n)))
108
- .map(pkg => ({ ...visitor.create(pkg), parent: node.value }));
109
-
110
- queue.push(...children);
111
- }
112
-
113
- return await visitor.complete(seen);
114
- }
115
-
116
84
  /**
117
85
  * Find workspace values from rootPath
118
86
  */
package/src/runtime.ts CHANGED
@@ -126,6 +126,13 @@ export const RuntimeContext = build({
126
126
  workspaceRelative(...rel: string[]): string {
127
127
  return path.resolve(RuntimeIndex.manifest.workspace.path, ...rel);
128
128
  },
129
+ /**
130
+ * Strip off the workspace path from a file
131
+ * @param full A full path
132
+ */
133
+ stripWorkspacePath(full: string): string {
134
+ return full === RuntimeIndex.manifest.workspace.path ? '' : full.replace(`${RuntimeIndex.manifest.workspace.path}/`, '');
135
+ },
129
136
  /**
130
137
  * Produce a workspace path for tooling, with '@' being replaced by node_module/name folder
131
138
  * @param rel The relative path
@@ -44,6 +44,7 @@ export type Package = {
44
44
  build?: Partial<ManifestContext['build']> & {
45
45
  isolated?: boolean;
46
46
  withModules?: Record<string, 'main' | true>;
47
+ watchIgnores?: string[];
47
48
  };
48
49
  };
49
50
  workspaces?: string[];
@@ -53,23 +54,4 @@ export type Package = {
53
54
 
54
55
  export type PackageDepType = 'dependencies' | 'devDependencies' | 'optionalDependencies' | 'peerDependencies';
55
56
 
56
- export type PackageVisitReq<T> = {
57
- /** Request package */
58
- pkg: Package;
59
- /** Children to visit */
60
- children: Record<string, string>;
61
- /** Value */
62
- value: T;
63
- /** Parent */
64
- parent?: T;
65
- };
66
-
67
- export type PackageVisitor<T> = {
68
- create(pkg: Package): PackageVisitReq<T>;
69
- init(): Promise<Iterable<PackageVisitReq<T>>>;
70
- valid(req: PackageVisitReq<T>): boolean;
71
- visit(req: PackageVisitReq<T>): void;
72
- complete(values: Iterable<T>): Promise<Iterable<T>>;
73
- };
74
-
75
57
  export type PackageWorkspaceEntry = { name: string, path: string };
@@ -7,7 +7,6 @@ import {
7
7
 
8
8
  const MANIFEST_MOD = '@travetto/manifest';
9
9
  const MANIFEST_IDX = `${MANIFEST_MOD}/__index__`;
10
- const ENTRY_POINT = 'support/entry';
11
10
 
12
11
  const RUNTIME_IDX_IMPORT = `${MANIFEST_MOD}/src/runtime`;
13
12
  const RUNTIME_IDX_CLS = 'RuntimeIndex';
@@ -32,9 +31,7 @@ interface MetadataInfo {
32
31
  export class RegisterTransformer {
33
32
 
34
33
  static #valid({ importName: imp }: TransformerState): boolean {
35
- return !imp.startsWith(MANIFEST_MOD) ?
36
- !imp.includes(ENTRY_POINT) :
37
- !(/[/](src|support)[/]/.test(imp) || imp === MANIFEST_IDX);
34
+ return !imp.startsWith(MANIFEST_MOD) || !(/[/](src|support)[/]/.test(imp) || imp === MANIFEST_IDX);
38
35
  }
39
36
 
40
37
  /**