@travetto/manifest 3.4.0 → 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 +1 -1
- package/README.md +25 -19
- package/__index__.ts +2 -2
- package/bin/context.js +37 -36
- package/package.json +4 -2
- package/src/delta.ts +5 -5
- package/src/dependencies.ts +28 -44
- package/src/file.ts +5 -5
- package/src/manifest-index.ts +3 -3
- package/src/module.ts +19 -16
- package/src/package.ts +27 -22
- package/src/path.ts +3 -3
- package/src/{root-index.ts → runtime.ts} +35 -38
- package/src/types.ts +49 -27
- package/src/util.ts +42 -25
- package/support/transformer.function-metadata.ts +8 -8
- /package/src/{typings.d.ts → global.d.ts} +0 -0
package/LICENSE
CHANGED
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 [
|
|
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 Ⲑ
|
|
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 = Ⲑ
|
|
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
|
-
"
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
"
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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/
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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
|
|
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)
|
|
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
|
|
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
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
+
"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
|
-
"
|
|
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 =
|
|
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(
|
|
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(
|
|
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));
|
package/src/dependencies.ts
CHANGED
|
@@ -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
|
-
|
|
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.
|
|
21
|
+
this.#mainSourcePath = path.resolve(this.ctx.workspace.path, this.ctx.main.folder);
|
|
47
22
|
}
|
|
48
23
|
|
|
49
|
-
#
|
|
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.
|
|
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.#
|
|
61
|
-
|
|
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?.
|
|
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.
|
|
91
|
-
const
|
|
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 ||
|
|
76
|
+
const local = internal || mainLike || !sourcePath.includes('node_modules');
|
|
94
77
|
|
|
95
|
-
const dep = {
|
|
96
|
-
name, version, sourcePath, main,
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
51
|
+
parts.unshift('node_modules', ctx.main.name);
|
|
52
52
|
}
|
|
53
|
-
return path.resolve(ctx.
|
|
53
|
+
return path.resolve(ctx.workspace.path, '.trv/tool', ...parts);
|
|
54
54
|
}
|
|
55
55
|
}
|
package/src/manifest-index.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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,
|
|
48
|
-
if (!
|
|
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 (
|
|
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') &&
|
|
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 (!
|
|
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,
|
|
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,
|
|
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 (!
|
|
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.
|
|
201
|
+
const sourceFolder = sourcePath === ctx.workspace.path ? '' : sourcePath.replace(`${ctx.workspace.path}/`, '');
|
|
200
202
|
|
|
201
|
-
const res = {
|
|
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
|
|
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 #
|
|
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
|
-
*
|
|
24
|
+
* Resolve import given a manifest context
|
|
25
25
|
*/
|
|
26
|
-
static
|
|
27
|
-
|
|
28
|
-
this.#
|
|
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 =
|
|
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.
|
|
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.
|
|
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 $
|
|
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.
|
|
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
|
/**
|
|
@@ -107,23 +82,45 @@ class $RootIndex extends ManifestIndex {
|
|
|
107
82
|
* Resolve module path to folder, with support for main module and monorepo support
|
|
108
83
|
*/
|
|
109
84
|
resolveModulePath(modulePath: string): string {
|
|
110
|
-
const main = this.manifest.
|
|
111
|
-
const workspace = this.manifest.
|
|
85
|
+
const main = this.manifest.main.name;
|
|
86
|
+
const workspace = this.manifest.workspace.path;
|
|
112
87
|
const [base, sub] = modulePath
|
|
113
88
|
.replace(/^(@@?)(#|$)/g, (_, v, r) => `${v === '@' ? main : workspace}${r}`)
|
|
114
89
|
.split('#');
|
|
115
90
|
return path.resolve(this.hasModule(base) ? this.getModule(base)!.sourcePath : base, sub ?? '.');
|
|
116
91
|
}
|
|
117
|
-
}
|
|
118
92
|
|
|
119
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Get manifest module by name
|
|
95
|
+
*/
|
|
96
|
+
getManifestModule(mod: string): ManifestModule {
|
|
97
|
+
return this.manifest.modules[mod];
|
|
98
|
+
}
|
|
120
99
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Get manifest modules
|
|
102
|
+
*/
|
|
103
|
+
getManifestModules(): ManifestModule[] {
|
|
104
|
+
return Object.values(this.manifest.modules);
|
|
126
105
|
}
|
|
127
106
|
}
|
|
128
107
|
|
|
129
|
-
export const
|
|
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
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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 (
|
|
64
|
-
manifest.outputFolder = path.cwd();
|
|
65
|
-
manifest.
|
|
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(
|
|
74
|
-
return
|
|
75
|
-
path.resolve(
|
|
76
|
-
|
|
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
|
-
*
|
|
88
|
+
* Produce the manifest context for the workspace module
|
|
95
89
|
*/
|
|
96
|
-
static
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
|
13
|
-
const
|
|
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
|
|
18
|
+
const runtimeIdx = Symbol.for(`${MANIFEST_MOD}:runtimeIndex`);
|
|
19
19
|
|
|
20
20
|
interface MetadataInfo {
|
|
21
|
-
[
|
|
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[
|
|
76
|
-
const ident = state.createAccess(state[
|
|
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[
|
|
121
|
-
const ident = state.createAccess(state[
|
|
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
|