@travetto/manifest 4.0.0-rc.0 → 4.0.0-rc.2
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 +13 -8
- package/__index__.ts +4 -1
- package/bin/context.d.ts +1 -1
- package/bin/context.js +39 -30
- package/package.json +1 -1
- package/src/delta.ts +10 -9
- package/src/dependencies.ts +123 -97
- package/src/file.ts +1 -21
- package/src/manifest-index.ts +46 -54
- package/src/module.ts +22 -37
- package/src/package.ts +19 -90
- package/src/runtime.ts +19 -2
- package/src/types/common.ts +20 -0
- package/src/types/context.ts +40 -0
- package/src/types/manifest.ts +79 -0
- package/src/types/package.ts +56 -0
- package/src/util.ts +70 -15
- package/src/types.ts +0 -140
package/src/manifest-index.ts
CHANGED
|
@@ -1,36 +1,11 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
|
|
1
3
|
import { ManifestModuleUtil } from './module';
|
|
2
4
|
import { path } from './path';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
ManifestModule, ManifestModuleCore, ManifestModuleFile,
|
|
6
|
-
ManifestModuleFileType, ManifestModuleFolderType, ManifestModuleRole, ManifestRoot
|
|
7
|
-
} from './types';
|
|
8
|
-
|
|
9
5
|
import { ManifestUtil } from './util';
|
|
10
6
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
module?: (module: IndexedModule) => boolean;
|
|
14
|
-
file?: (file: IndexedFile) => boolean;
|
|
15
|
-
sourceOnly?: boolean;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type IndexedFile = {
|
|
19
|
-
id: string;
|
|
20
|
-
import: string;
|
|
21
|
-
module: string;
|
|
22
|
-
sourceFile: string;
|
|
23
|
-
outputFile: string;
|
|
24
|
-
relativeFile: string;
|
|
25
|
-
role: ManifestModuleRole;
|
|
26
|
-
type: ManifestModuleFileType;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export type IndexedModule = ManifestModuleCore & {
|
|
30
|
-
sourcePath: string;
|
|
31
|
-
outputPath: string;
|
|
32
|
-
files: Record<ManifestModuleFolderType, IndexedFile[]>;
|
|
33
|
-
};
|
|
7
|
+
import type { ManifestModuleFolderType } from './types/common';
|
|
8
|
+
import type { ManifestModule, ManifestRoot, ManifestModuleFile, IndexedModule, IndexedFile, FindConfig } from './types/manifest';
|
|
34
9
|
|
|
35
10
|
const TypedObject: {
|
|
36
11
|
keys<T = unknown, K extends keyof T = keyof T>(o: T): K[];
|
|
@@ -43,7 +18,7 @@ const TypedObject: {
|
|
|
43
18
|
*/
|
|
44
19
|
export class ManifestIndex {
|
|
45
20
|
|
|
46
|
-
#
|
|
21
|
+
#arbitraryLookup?: (parts: string[]) => ManifestModule | undefined;
|
|
47
22
|
#manifest: ManifestRoot;
|
|
48
23
|
#modules: IndexedModule[];
|
|
49
24
|
#modulesByName: Record<string, IndexedModule> = {};
|
|
@@ -69,14 +44,8 @@ export class ManifestIndex {
|
|
|
69
44
|
return this.#outputRoot;
|
|
70
45
|
}
|
|
71
46
|
|
|
72
|
-
get manifestFile(): string {
|
|
73
|
-
return this.#manifestFile;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
47
|
init(manifestInput: string): void {
|
|
77
|
-
|
|
78
|
-
this.#manifest = manifest;
|
|
79
|
-
this.#manifestFile = file;
|
|
48
|
+
this.#manifest = ManifestUtil.readManifestSync(manifestInput);
|
|
80
49
|
this.#outputRoot = path.resolve(this.#manifest.workspace.path, this.#manifest.build.outputFolder);
|
|
81
50
|
this.#index();
|
|
82
51
|
}
|
|
@@ -104,12 +73,14 @@ export class ManifestIndex {
|
|
|
104
73
|
this.#outputToEntry.clear();
|
|
105
74
|
this.#importToEntry.clear();
|
|
106
75
|
this.#sourceToEntry.clear();
|
|
76
|
+
this.#arbitraryLookup = undefined;
|
|
107
77
|
|
|
108
78
|
this.#modules = Object.values(this.#manifest.modules)
|
|
109
79
|
.map(m => ({
|
|
110
80
|
...m,
|
|
111
81
|
outputPath: this.#resolveOutput(m.outputFolder),
|
|
112
82
|
sourcePath: path.resolve(this.#manifest.workspace.path, m.sourceFolder),
|
|
83
|
+
children: new Set(),
|
|
113
84
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
114
85
|
files: Object.fromEntries(
|
|
115
86
|
Object.entries(m.files).map(([folder, files]) => [folder, this.#moduleFiles(m, files ?? [])])
|
|
@@ -128,6 +99,13 @@ export class ManifestIndex {
|
|
|
128
99
|
}
|
|
129
100
|
this.#modulesByName = Object.fromEntries(this.#modules.map(x => [x.name, x]));
|
|
130
101
|
this.#modulesByFolder = Object.fromEntries(this.#modules.map(x => [x.sourceFolder, x]));
|
|
102
|
+
|
|
103
|
+
// Store child information
|
|
104
|
+
for (const mod of this.#modules) {
|
|
105
|
+
for (const p of mod.parents) {
|
|
106
|
+
this.#modulesByName[p]?.children.add(mod.name);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
131
109
|
}
|
|
132
110
|
|
|
133
111
|
/**
|
|
@@ -138,11 +116,11 @@ export class ManifestIndex {
|
|
|
138
116
|
}
|
|
139
117
|
|
|
140
118
|
/**
|
|
141
|
-
* Get all
|
|
119
|
+
* Get all workspace modules
|
|
142
120
|
* @returns
|
|
143
121
|
*/
|
|
144
|
-
|
|
145
|
-
return this.#modules.filter(x => x.
|
|
122
|
+
getWorkspaceModules(): IndexedModule[] {
|
|
123
|
+
return this.#modules.filter(x => x.workspace);
|
|
146
124
|
}
|
|
147
125
|
|
|
148
126
|
/**
|
|
@@ -237,12 +215,9 @@ export class ManifestIndex {
|
|
|
237
215
|
/**
|
|
238
216
|
* Build module list from an expression list (e.g. `@travetto/rest,-@travetto/log)
|
|
239
217
|
*/
|
|
240
|
-
getModuleList(mode: '
|
|
218
|
+
getModuleList(mode: 'workspace' | 'all', exprList: string = ''): Set<string> {
|
|
241
219
|
const allMods = Object.keys(this.#manifest.modules);
|
|
242
|
-
const active = new Set<string>(
|
|
243
|
-
mode === 'local' ? this.getLocalModules().map(x => x.name) :
|
|
244
|
-
(mode === 'all' ? allMods : [])
|
|
245
|
-
);
|
|
220
|
+
const active = new Set<string>(mode === 'workspace' ? this.getWorkspaceModules().map(x => x.name) : allMods);
|
|
246
221
|
|
|
247
222
|
for (const expr of exprList.split(/\s*,\s*/g)) {
|
|
248
223
|
const [, neg, mod] = expr.match(/(-|[+])?([^+\- ]+)$/) ?? [];
|
|
@@ -257,21 +232,38 @@ export class ManifestIndex {
|
|
|
257
232
|
}
|
|
258
233
|
|
|
259
234
|
/**
|
|
260
|
-
* Get all modules (transitively)
|
|
235
|
+
* Get all modules, parents or children, (transitively) of the provided root, in a DFS fashion
|
|
261
236
|
*/
|
|
262
|
-
getDependentModules(root: IndexedModule):
|
|
237
|
+
getDependentModules(root: IndexedModule | string, field: 'parents' | 'children'): IndexedModule[] {
|
|
263
238
|
const seen = new Set<string>();
|
|
264
|
-
const out =
|
|
265
|
-
const toProcess = [root.name];
|
|
239
|
+
const out: IndexedModule[] = [];
|
|
240
|
+
const toProcess = [typeof root === 'string' ? root : root.name];
|
|
266
241
|
while (toProcess.length) {
|
|
267
242
|
const next = toProcess.shift()!;
|
|
268
|
-
if (seen.has(next)) {
|
|
269
|
-
|
|
243
|
+
if (!seen.has(next)) {
|
|
244
|
+
seen.add(next);
|
|
245
|
+
const mod = this.getModule(next)!;
|
|
246
|
+
toProcess.push(...mod[field]);
|
|
247
|
+
if (next !== this.#manifest.main.name) { // Do not include self
|
|
248
|
+
out.push(mod);
|
|
249
|
+
}
|
|
270
250
|
}
|
|
271
|
-
const mod = this.getModule(next)!;
|
|
272
|
-
toProcess.push(...mod.parents);
|
|
273
|
-
out.add(mod);
|
|
274
251
|
}
|
|
275
252
|
return out;
|
|
276
253
|
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Find the module for an arbitrary source file, if it falls under a given workspace module
|
|
257
|
+
*/
|
|
258
|
+
findModuleForArbitraryFile(file: string): ManifestModule | undefined {
|
|
259
|
+
const base = this.#manifest.workspace.path;
|
|
260
|
+
const lookup = this.#arbitraryLookup ??= ManifestUtil.lookupTrie(
|
|
261
|
+
Object.values(this.#manifest.modules),
|
|
262
|
+
x => x.sourceFolder.split('/'),
|
|
263
|
+
sub =>
|
|
264
|
+
!existsSync(path.resolve(base, ...sub, 'package.json')) &&
|
|
265
|
+
!existsSync(path.resolve(base, ...sub, '.git'))
|
|
266
|
+
);
|
|
267
|
+
return lookup(file.replace(`${base}/`, '').split('/'));
|
|
268
|
+
}
|
|
277
269
|
}
|
package/src/module.ts
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
|
|
3
3
|
import { path } from './path';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from './types';
|
|
10
|
-
import { ModuleDep, ModuleDependencyVisitor } from './dependencies';
|
|
11
|
-
import { PackageUtil } from './package';
|
|
4
|
+
import { PackageModuleVisitor } from './dependencies';
|
|
5
|
+
|
|
6
|
+
import type { ManifestModuleFileType, ManifestModuleRole, ManifestModuleFolderType } from './types/common';
|
|
7
|
+
import type { ManifestModuleFile, ManifestModule, PackageModule } from './types/manifest';
|
|
8
|
+
import type { ManifestContext } from './types/context';
|
|
12
9
|
|
|
13
10
|
const EXT_MAPPING: Record<string, ManifestModuleFileType> = {
|
|
14
11
|
'.js': 'js',
|
|
@@ -47,9 +44,10 @@ export class ManifestModuleUtil {
|
|
|
47
44
|
/**
|
|
48
45
|
* Simple file scanning
|
|
49
46
|
*/
|
|
50
|
-
static async scanFolder(folder: string,
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
static async scanFolder(folder: string, full = false): Promise<string[]> {
|
|
48
|
+
const key = `${folder}|${full}`;
|
|
49
|
+
if (key in this.#scanCache) {
|
|
50
|
+
return this.#scanCache[key];
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
if (!await fs.stat(folder).catch(() => false)) {
|
|
@@ -73,7 +71,7 @@ export class ManifestModuleUtil {
|
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
for (const sub of await fs.readdir(top)) {
|
|
76
|
-
const valid = !sub.startsWith('.') && (depth > 0 ||
|
|
74
|
+
const valid = !sub.startsWith('.') && (depth > 0 || full);
|
|
77
75
|
const stat = await fs.stat(`${top}/${sub}`);
|
|
78
76
|
if (stat.isFile()) {
|
|
79
77
|
if (valid || STD_TOP_FILES.has(sub)) {
|
|
@@ -87,11 +85,7 @@ export class ManifestModuleUtil {
|
|
|
87
85
|
}
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
this.#scanCache[folder] = out;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return out;
|
|
88
|
+
return this.#scanCache[key] = out;
|
|
95
89
|
}
|
|
96
90
|
|
|
97
91
|
/**
|
|
@@ -177,12 +171,13 @@ export class ManifestModuleUtil {
|
|
|
177
171
|
/**
|
|
178
172
|
* Visit a module and describe files, and metadata
|
|
179
173
|
*/
|
|
180
|
-
static async describeModule(ctx: ManifestContext,
|
|
181
|
-
const {
|
|
174
|
+
static async describeModule(ctx: ManifestContext, mod: PackageModule): Promise<ManifestModule> {
|
|
175
|
+
const { state, ...rest } = mod;
|
|
176
|
+
const sourcePath = path.resolve(ctx.workspace.path, rest.sourceFolder);
|
|
182
177
|
|
|
183
178
|
const files: ManifestModule['files'] = {};
|
|
184
179
|
|
|
185
|
-
for (const file of await this.scanFolder(sourcePath,
|
|
180
|
+
for (const file of await this.scanFolder(sourcePath, rest.main)) {
|
|
186
181
|
// Group by top folder
|
|
187
182
|
const moduleFile = file.replace(`${sourcePath}/`, '');
|
|
188
183
|
const entry = await this.transformFile(moduleFile, file);
|
|
@@ -190,30 +185,20 @@ export class ManifestModuleUtil {
|
|
|
190
185
|
(files[key] ??= []).push(entry);
|
|
191
186
|
}
|
|
192
187
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const roles = [...roleSet ?? []].sort();
|
|
199
|
-
const parents = [...parentSet].sort();
|
|
200
|
-
const outputFolder = `node_modules/${name}`;
|
|
201
|
-
const sourceFolder = sourcePath === ctx.workspace.path ? '' : sourcePath.replace(`${ctx.workspace.path}/`, '');
|
|
202
|
-
|
|
203
|
-
const res: ManifestModule = {
|
|
204
|
-
main, name, version, local, internal, sourceFolder, outputFolder, roles, parents, prod, files
|
|
188
|
+
return {
|
|
189
|
+
...rest,
|
|
190
|
+
roles: [...state.roleSet].sort(),
|
|
191
|
+
parents: [...state.parentSet].sort(),
|
|
192
|
+
files
|
|
205
193
|
};
|
|
206
|
-
return res;
|
|
207
194
|
}
|
|
208
195
|
|
|
209
196
|
/**
|
|
210
197
|
* Produce all modules for a given manifest folder, adding in some given modules when developing framework
|
|
211
198
|
*/
|
|
212
199
|
static async produceModules(ctx: ManifestContext): Promise<Record<string, ManifestModule>> {
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const sorted = [...declared].sort((a, b) => a.name.localeCompare(b.name));
|
|
216
|
-
const modules = await Promise.all(sorted.map(x => this.describeModule(ctx, x)));
|
|
200
|
+
const pkgs = await new PackageModuleVisitor(ctx).visit();
|
|
201
|
+
const modules = await Promise.all([...pkgs].map(x => this.describeModule(ctx, x)));
|
|
217
202
|
return Object.fromEntries(modules.map(m => [m.name, m]));
|
|
218
203
|
}
|
|
219
204
|
|
package/src/package.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
2
|
import { execSync } from 'node:child_process';
|
|
3
3
|
|
|
4
|
-
import type { ManifestContext, NodePackageManager, Package, PackageVisitor, PackageVisitReq, PackageWorkspaceEntry } from './types';
|
|
5
4
|
import { path } from './path';
|
|
6
5
|
import { ManifestFileUtil } from './file';
|
|
7
6
|
|
|
7
|
+
import { PackagePath, type Package, type PackageWorkspaceEntry } from './types/package';
|
|
8
|
+
import type { ManifestContext } from './types/context';
|
|
9
|
+
import type { NodePackageManager } from './types/common';
|
|
10
|
+
|
|
8
11
|
/**
|
|
9
12
|
* Utilities for querying, traversing and reading package.json files.
|
|
10
13
|
*/
|
|
@@ -31,9 +34,9 @@ export class PackageUtil {
|
|
|
31
34
|
/**
|
|
32
35
|
* Resolve version path, if file: url
|
|
33
36
|
*/
|
|
34
|
-
static resolveVersionPath(
|
|
37
|
+
static resolveVersionPath(root: Package, ver: string): string | undefined {
|
|
35
38
|
if (ver.startsWith('file:')) {
|
|
36
|
-
return path.resolve(
|
|
39
|
+
return path.resolve(this.getPackagePath(root), ver.replace('file:', ''));
|
|
37
40
|
} else {
|
|
38
41
|
return;
|
|
39
42
|
}
|
|
@@ -54,31 +57,6 @@ export class PackageUtil {
|
|
|
54
57
|
throw new Error(`Unable to resolve: ${name}`);
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
/**
|
|
58
|
-
* Build a package visit req
|
|
59
|
-
*/
|
|
60
|
-
static packageReq<T>(sourcePath: string, prod: boolean, topLevel?: boolean): PackageVisitReq<T> {
|
|
61
|
-
return { pkg: this.readPackage(sourcePath), sourcePath, prod, topLevel };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Extract all dependencies from a package
|
|
66
|
-
*/
|
|
67
|
-
static getAllDependencies<T = unknown>(modulePath: string, local: boolean): PackageVisitReq<T>[] {
|
|
68
|
-
const pkg = this.readPackage(modulePath);
|
|
69
|
-
const children: Record<string, PackageVisitReq<T>> = {};
|
|
70
|
-
for (const [deps, prod] of [
|
|
71
|
-
[pkg.dependencies, true],
|
|
72
|
-
...(local ? [[pkg.devDependencies, false] as const] : []),
|
|
73
|
-
] as const) {
|
|
74
|
-
for (const [name, version] of Object.entries(deps ?? {})) {
|
|
75
|
-
const depPath = this.resolveVersionPath(modulePath, version) ?? this.resolvePackagePath(name);
|
|
76
|
-
children[`${name}#${version}`] = this.packageReq<T>(depPath, prod, false);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return Object.values(children).sort((a, b) => a.pkg.name.localeCompare(b.pkg.name));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
60
|
/**
|
|
83
61
|
* Read a package.json from a given folder
|
|
84
62
|
*/
|
|
@@ -92,86 +70,37 @@ export class PackageUtil {
|
|
|
92
70
|
|
|
93
71
|
res.name ??= 'untitled'; // If a package.json (root-only) is missing a name, allows for npx execution
|
|
94
72
|
|
|
73
|
+
res[PackagePath] = modulePath;
|
|
95
74
|
return res;
|
|
96
75
|
}
|
|
97
76
|
|
|
98
77
|
/**
|
|
99
|
-
*
|
|
100
|
-
*/
|
|
101
|
-
static importPackage(moduleName: string): Package {
|
|
102
|
-
return this.readPackage(this.resolvePackagePath(moduleName));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Visit packages with ability to track duplicates
|
|
78
|
+
* Get the package path
|
|
107
79
|
*/
|
|
108
|
-
static
|
|
109
|
-
|
|
110
|
-
const root = this.packageReq<T>(visitor.rootPath, false, true);
|
|
111
|
-
|
|
112
|
-
const seen = new Map<string, T>();
|
|
113
|
-
const queue: PackageVisitReq<T>[] = [...await visitor.init?.(root) ?? [], root];
|
|
114
|
-
const out = new Set<T>();
|
|
115
|
-
|
|
116
|
-
while (queue.length) {
|
|
117
|
-
const req = queue.pop();
|
|
118
|
-
|
|
119
|
-
if (!req || (visitor.valid && !visitor.valid(req))) {
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const key = req.sourcePath;
|
|
124
|
-
if (seen.has(key)) {
|
|
125
|
-
await visitor.visit?.(req, seen.get(key)!);
|
|
126
|
-
} else {
|
|
127
|
-
const dep = await visitor.create(req);
|
|
128
|
-
out.add(dep);
|
|
129
|
-
await visitor.visit?.(req, dep);
|
|
130
|
-
seen.set(key, dep);
|
|
131
|
-
const children = this.getAllDependencies<T>(
|
|
132
|
-
req.sourcePath,
|
|
133
|
-
// We consider a module local if its not in the node_modules
|
|
134
|
-
!req.sourcePath.includes('node_modules') && (
|
|
135
|
-
// And its the root or we are in a monorepo
|
|
136
|
-
root.sourcePath === req.sourcePath ||
|
|
137
|
-
!!root.pkg.workspaces
|
|
138
|
-
)
|
|
139
|
-
);
|
|
140
|
-
queue.push(...children.map(x => ({ ...x, parent: dep })));
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return (await visitor.complete?.(out)) ?? out;
|
|
80
|
+
static getPackagePath(pkg: Package): string {
|
|
81
|
+
return pkg[PackagePath];
|
|
144
82
|
}
|
|
145
83
|
|
|
146
84
|
/**
|
|
147
85
|
* Find workspace values from rootPath
|
|
148
86
|
*/
|
|
149
|
-
static async resolveWorkspaces(ctx: ManifestContext
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
} catch (err) {
|
|
87
|
+
static async resolveWorkspaces(ctx: ManifestContext): Promise<PackageWorkspaceEntry[]> {
|
|
88
|
+
const rootPath = ctx.workspace.path;
|
|
89
|
+
const cache = path.resolve(rootPath, ctx.build.outputFolder, 'workspaces.json');
|
|
90
|
+
return this.#workspaces[rootPath] ??= await ManifestFileUtil.readAsJson<PackageWorkspaceEntry[]>(cache)
|
|
91
|
+
.catch(async () => {
|
|
155
92
|
let out: PackageWorkspaceEntry[];
|
|
156
93
|
switch (ctx.workspace.manager) {
|
|
94
|
+
case 'yarn':
|
|
157
95
|
case 'npm': {
|
|
158
96
|
const res = await this.#exec<{ location: string, name: string }[]>(rootPath, 'npm query .workspace');
|
|
159
|
-
out = res.map(d => ({
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
case 'yarn': {
|
|
163
|
-
const res = await this.#exec<Record<string, { location: string }>>(rootPath, 'npm query .workspace');
|
|
164
|
-
out = Object.entries(res).map(([name, { location }]) => ({ sourcePath: location, name }));
|
|
97
|
+
out = res.map(d => ({ path: path.resolve(ctx.workspace.path, d.location), name: d.name }));
|
|
165
98
|
break;
|
|
166
99
|
}
|
|
167
100
|
}
|
|
168
|
-
|
|
169
|
-
this.#workspaces[rootPath] = out;
|
|
170
|
-
|
|
171
101
|
await ManifestFileUtil.bufferedFileWrite(cache, out);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
return this.#workspaces[rootPath];
|
|
102
|
+
return out;
|
|
103
|
+
});
|
|
175
104
|
}
|
|
176
105
|
|
|
177
106
|
/**
|
package/src/runtime.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { path } from './path';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { ManifestIndex } from './manifest-index';
|
|
3
|
+
|
|
4
|
+
import type { FunctionMetadata } from './types/common';
|
|
5
|
+
import type { IndexedModule, ManifestModule } from './types/manifest';
|
|
6
|
+
import type { ManifestContext } from './types/context';
|
|
4
7
|
|
|
5
8
|
const METADATA = Symbol.for('@travetto/manifest:metadata');
|
|
6
9
|
type Metadated = { [METADATA]: FunctionMetadata };
|
|
@@ -122,5 +125,19 @@ export const RuntimeContext = build({
|
|
|
122
125
|
*/
|
|
123
126
|
workspaceRelative(...rel: string[]): string {
|
|
124
127
|
return path.resolve(RuntimeIndex.manifest.workspace.path, ...rel);
|
|
128
|
+
},
|
|
129
|
+
/**
|
|
130
|
+
* Produce a workspace path for tooling, with '@' being replaced by node_module/name folder
|
|
131
|
+
* @param rel The relative path
|
|
132
|
+
*/
|
|
133
|
+
toolPath(...rel: string[]): string {
|
|
134
|
+
rel = rel.flatMap(x => x === '@' ? ['node_modules', RuntimeIndex.manifest.main.name] : [x]);
|
|
135
|
+
return path.resolve(RuntimeIndex.manifest.workspace.path, RuntimeIndex.manifest.build.toolFolder, ...rel);
|
|
136
|
+
},
|
|
137
|
+
/**
|
|
138
|
+
* Are we running from a mono-root?
|
|
139
|
+
*/
|
|
140
|
+
get monoRoot(): boolean {
|
|
141
|
+
return !!RuntimeIndex.manifest.workspace.mono && !RuntimeIndex.manifest.main.folder;
|
|
125
142
|
}
|
|
126
143
|
}, ['main', 'workspace']);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type NodeModuleType = 'module' | 'commonjs';
|
|
2
|
+
export type NodePackageManager = 'yarn' | 'npm';
|
|
3
|
+
|
|
4
|
+
export type ManifestModuleFileType = 'typings' | 'ts' | 'js' | 'json' | 'package-json' | 'unknown' | 'fixture' | 'md';
|
|
5
|
+
export type ManifestModuleFolderType =
|
|
6
|
+
'$root' | '$index' | '$package' |
|
|
7
|
+
'src' | 'bin' | 'support' | 'resources' | 'test' | 'doc' |
|
|
8
|
+
'test/fixtures' | 'support/fixtures' | 'support/resources' |
|
|
9
|
+
'$other' | '$transformer';
|
|
10
|
+
|
|
11
|
+
export type ManifestModuleRole = 'std' | 'test' | 'doc' | 'compile' | 'build';
|
|
12
|
+
|
|
13
|
+
export type FunctionMetadata = {
|
|
14
|
+
id: string;
|
|
15
|
+
source: string;
|
|
16
|
+
hash?: number;
|
|
17
|
+
methods?: Record<string, { hash: number }>;
|
|
18
|
+
synthetic?: boolean;
|
|
19
|
+
abstract?: boolean;
|
|
20
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { NodeModuleType, NodePackageManager } from './common';
|
|
2
|
+
|
|
3
|
+
export type ManifestContext = {
|
|
4
|
+
workspace: {
|
|
5
|
+
/** Workspace path for module */
|
|
6
|
+
path: string;
|
|
7
|
+
/** The module name for the workspace root */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Is the workspace a monorepo? */
|
|
10
|
+
mono?: boolean;
|
|
11
|
+
/** The module type of the workspace */
|
|
12
|
+
type: NodeModuleType;
|
|
13
|
+
/** The package manager of the workspace */
|
|
14
|
+
manager: NodePackageManager;
|
|
15
|
+
/** The default env name */
|
|
16
|
+
defaultEnv: string;
|
|
17
|
+
};
|
|
18
|
+
build: {
|
|
19
|
+
/** Compiler folder, relative to workspace */
|
|
20
|
+
compilerFolder: string;
|
|
21
|
+
/** Compiler module folder */
|
|
22
|
+
compilerModuleFolder: string;
|
|
23
|
+
/** URL for the compiler server */
|
|
24
|
+
compilerUrl: string;
|
|
25
|
+
/** Code output folder, relative to workspace */
|
|
26
|
+
outputFolder: string;
|
|
27
|
+
/** Location of development-time tool output */
|
|
28
|
+
toolFolder: string;
|
|
29
|
+
};
|
|
30
|
+
main: {
|
|
31
|
+
/** Main module for manifest */
|
|
32
|
+
name: string;
|
|
33
|
+
/** Folder, relative to workspace for main module */
|
|
34
|
+
folder: string;
|
|
35
|
+
/** Description of the main module */
|
|
36
|
+
description?: string;
|
|
37
|
+
/** Version of the main module */
|
|
38
|
+
version: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { ManifestModuleFileType, ManifestModuleFolderType, ManifestModuleRole } from './common';
|
|
2
|
+
import type { ManifestContext } from './context';
|
|
3
|
+
import { Package } from './package';
|
|
4
|
+
|
|
5
|
+
export type ManifestModuleFile = [string, ManifestModuleFileType, number] | [string, ManifestModuleFileType, number, ManifestModuleRole];
|
|
6
|
+
|
|
7
|
+
export type ManifestDepCore = {
|
|
8
|
+
/** Package name */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Package version */
|
|
11
|
+
version: string;
|
|
12
|
+
/** Is this the main module */
|
|
13
|
+
main?: boolean;
|
|
14
|
+
/** Is this a module that is part of the workspace */
|
|
15
|
+
workspace?: boolean;
|
|
16
|
+
/** Should this module be deployed to prod? */
|
|
17
|
+
prod: boolean;
|
|
18
|
+
/** Is the module intended to be published? */
|
|
19
|
+
internal?: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ManifestModuleCore = ManifestDepCore & {
|
|
23
|
+
sourceFolder: string;
|
|
24
|
+
outputFolder: string;
|
|
25
|
+
roles: ManifestModuleRole[];
|
|
26
|
+
parents: string[];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type ManifestModule = ManifestModuleCore & {
|
|
30
|
+
files: Partial<Record<ManifestModuleFolderType, ManifestModuleFile[]>>;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type ManifestRoot = ManifestContext & {
|
|
34
|
+
generated: number;
|
|
35
|
+
modules: Record<string, ManifestModule>;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type FindConfig = {
|
|
39
|
+
folder?: (folder: ManifestModuleFolderType) => boolean;
|
|
40
|
+
module?: (module: IndexedModule) => boolean;
|
|
41
|
+
file?: (file: IndexedFile) => boolean;
|
|
42
|
+
sourceOnly?: boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type IndexedFile = {
|
|
46
|
+
id: string;
|
|
47
|
+
import: string;
|
|
48
|
+
module: string;
|
|
49
|
+
sourceFile: string;
|
|
50
|
+
outputFile: string;
|
|
51
|
+
relativeFile: string;
|
|
52
|
+
role: ManifestModuleRole;
|
|
53
|
+
type: ManifestModuleFileType;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type IndexedModule = ManifestModuleCore & {
|
|
57
|
+
sourcePath: string;
|
|
58
|
+
outputPath: string;
|
|
59
|
+
files: Record<ManifestModuleFolderType, IndexedFile[]>;
|
|
60
|
+
children: Set<string>;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** Module dependency, used in dependency visiting */
|
|
64
|
+
export type PackageModule = Omit<ManifestModule, 'files' | 'parents' | 'roles'> & {
|
|
65
|
+
state: {
|
|
66
|
+
/** Role root? */
|
|
67
|
+
roleRoot?: boolean;
|
|
68
|
+
/** Travetto package info */
|
|
69
|
+
travetto?: Package['travetto'];
|
|
70
|
+
/** Prod dependencies */
|
|
71
|
+
prodDeps: Set<string>;
|
|
72
|
+
/** Set of parent package names */
|
|
73
|
+
parentSet: Set<string>;
|
|
74
|
+
/** Set of child package names */
|
|
75
|
+
childSet: Set<string>;
|
|
76
|
+
/** Defined roles for a given module */
|
|
77
|
+
roleSet: Set<ManifestModuleRole>;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ManifestModuleRole, NodeModuleType } from './common';
|
|
2
|
+
import type { ManifestContext } from './context';
|
|
3
|
+
|
|
4
|
+
export const PackagePath = Symbol.for('@travetto/manifest:package-path');
|
|
5
|
+
|
|
6
|
+
export type Package = {
|
|
7
|
+
[PackagePath]: string;
|
|
8
|
+
name: string;
|
|
9
|
+
type?: NodeModuleType;
|
|
10
|
+
version: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
license?: string;
|
|
13
|
+
repository?: {
|
|
14
|
+
url: string;
|
|
15
|
+
directory?: string;
|
|
16
|
+
};
|
|
17
|
+
author?: {
|
|
18
|
+
email?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
};
|
|
21
|
+
main: string;
|
|
22
|
+
homepage?: string;
|
|
23
|
+
files?: string[];
|
|
24
|
+
bin?: Record<string, string>;
|
|
25
|
+
scripts?: Record<string, string>;
|
|
26
|
+
engines?: Record<string, string>;
|
|
27
|
+
keywords?: string[];
|
|
28
|
+
|
|
29
|
+
dependencies?: Record<string, string>;
|
|
30
|
+
devDependencies?: Record<string, string>;
|
|
31
|
+
peerDependencies?: Record<string, string>;
|
|
32
|
+
peerDependenciesMeta?: Record<string, { optional?: boolean }>;
|
|
33
|
+
optionalDependencies?: Record<string, string>;
|
|
34
|
+
travetto?: {
|
|
35
|
+
displayName?: string;
|
|
36
|
+
roles?: ManifestModuleRole[];
|
|
37
|
+
doc?: {
|
|
38
|
+
output?: string[];
|
|
39
|
+
root?: string;
|
|
40
|
+
baseUrl?: string;
|
|
41
|
+
outputs?: string[];
|
|
42
|
+
};
|
|
43
|
+
defaultEnv?: string;
|
|
44
|
+
build?: Partial<ManifestContext['build']> & {
|
|
45
|
+
isolated?: boolean;
|
|
46
|
+
withModules?: Record<string, 'main' | true>;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
workspaces?: string[];
|
|
50
|
+
private?: boolean;
|
|
51
|
+
publishConfig?: { access?: 'restricted' | 'public' };
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type PackageDepType = 'dependencies' | 'devDependencies' | 'optionalDependencies' | 'peerDependencies';
|
|
55
|
+
|
|
56
|
+
export type PackageWorkspaceEntry = { name: string, path: string };
|