@travetto/manifest 5.0.0-rc.1 → 5.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 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 [RuntimeIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/runtime.ts#L12) 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 associated data by the id.
39
39
 
40
40
  **Code: Test Class**
41
41
  ```typescript
@@ -50,11 +50,11 @@ 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 Ⲑ_runtime_1 = tslib_1.__importStar(require("@travetto/manifest/src/runtime.js"));
54
53
  const Ⲑ_decorator_1 = tslib_1.__importStar(require("@travetto/registry/src/decorator.js"));
55
- var ᚕf = "@travetto/manifest/doc/test-class.js";
54
+ const Ⲑ_function_1 = tslib_1.__importStar(require("@travetto/runtime/src/function.js"));
55
+ var ᚕm = ["@travetto/manifest", "doc/test-class"];
56
56
  let TestClass = class TestClass {
57
- static Ⲑinit = Ⲑ_runtime_1.RuntimeIndex.registerFunction(TestClass, ᚕf, { hash: 197152026, lines: [1, 3] }, { doStuff: { hash: 51337554, lines: [2, 2] } }, false, false);
57
+ static Ⲑinit = Ⲑ_function_1.register(TestClass, ᚕm, { hash: 197152026, lines: [1, 3] }, { doStuff: { hash: 51337554, lines: [2, 2] } }, false, false);
58
58
  async doStuff() { }
59
59
  };
60
60
  exports.TestClass = TestClass;
@@ -63,21 +63,6 @@ exports.TestClass = TestClass = tslib_1.__decorate([
63
63
  ], TestClass);
64
64
  ```
65
65
 
66
- **Terminal: Index Lookup at Runtime**
67
- ```bash
68
- $ trv main ./doc/lookup.ts
69
-
70
- {
71
- id: '@travetto/manifest:doc/test-class○TestClass',
72
- source: './doc/test-class.ts',
73
- hash: 197152026,
74
- lines: [ 1, 3 ],
75
- methods: { doStuff: { hash: 51337554, lines: [ 2, 2 ] } },
76
- abstract: false,
77
- synthetic: false
78
- }
79
- ```
80
-
81
66
  ## Module Indexing
82
67
  Once the manifest is created, the application runtime can now read this manifest, which allows for influencing runtime behavior. The most common patterns include:
83
68
  * Loading all source files
@@ -91,8 +76,6 @@ Once the manifest is created, the application runtime can now read this manifest
91
76
  ## Path Normalization
92
77
  By default, all paths within the framework are assumed to be in a POSIX style, and all input paths are converted to the POSIX style. This works appropriately within a Unix and a Windows environment. This module offers up [path](https://github.com/travetto/travetto/tree/main/module/manifest/src/path.ts#L9) as an equivalent to [Node](https://nodejs.org)'s [http](https://nodejs.org/api/path.html) library. This allows for consistent behavior across all file-interactions.
93
78
 
94
- Imports pointing at $`node:path` and $`path` are rewritten at compile time to point to the implementation provided by the module. This allows for seamless import/usage patterns with the reliability needed for cross platform support.
95
-
96
79
  ## Anatomy of a Manifest
97
80
 
98
81
  **Code: Manifest for @travetto/manifest**
@@ -140,7 +123,6 @@ Imports pointing at $`node:path` and $`path` are rewritten at compile time to po
140
123
  ],
141
124
  "doc": [
142
125
  [ "DOC.tsx", "ts", 1868155200000, "doc" ],
143
- [ "doc/lookup.ts", "ts", 1868155200000, "doc" ],
144
126
  [ "doc/test-class.ts", "ts", 1868155200000, "doc" ]
145
127
  ],
146
128
  "$index": [
@@ -150,26 +132,19 @@ Imports pointing at $`node:path` and $`path` are rewritten at compile time to po
150
132
  [ "package.json", "package-json", 1868155200000 ]
151
133
  ],
152
134
  "test": [
153
- [ "test/path.ts", "ts", 1868155200000, "test" ],
154
- [ "test/runtime.ts", "ts", 1868155200000, "test" ]
135
+ [ "test/path.ts", "ts", 1868155200000, "test" ]
155
136
  ],
156
137
  "test/fixtures": [
157
138
  [ "test/fixtures/simple.ts", "fixture", 1868155200000, "test" ]
158
139
  ],
159
- "$transformer": [
160
- [ "support/transformer.function-metadata.ts", "ts", 1868155200000, "compile" ],
161
- [ "support/transformer.rewrite-path-import.ts", "ts", 1868155200000, "compile" ]
162
- ],
163
140
  "src": [
164
141
  [ "src/delta.ts", "ts", 1868155200000 ],
165
142
  [ "src/dependencies.ts", "ts", 1868155200000 ],
166
143
  [ "src/file.ts", "ts", 1868155200000 ],
167
- [ "src/global.d.ts", "typings", 1868155200000 ],
168
144
  [ "src/manifest-index.ts", "ts", 1868155200000 ],
169
145
  [ "src/module.ts", "ts", 1868155200000 ],
170
146
  [ "src/package.ts", "ts", 1868155200000 ],
171
147
  [ "src/path.ts", "ts", 1868155200000 ],
172
- [ "src/runtime.ts", "ts", 1868155200000 ],
173
148
  [ "src/util.ts", "ts", 1868155200000 ],
174
149
  [ "src/types/common.ts", "ts", 1868155200000 ],
175
150
  [ "src/types/context.ts", "ts", 1868155200000 ],
package/__index__.ts CHANGED
@@ -1,9 +1,8 @@
1
- /// <reference path="./src/global.d.ts" />
1
+ /// <reference path="../runtime/src/global.d.ts" />
2
2
 
3
3
  export * from './src/module';
4
4
  export * from './src/delta';
5
5
  export * from './src/manifest-index';
6
- export * from './src/runtime';
7
6
  export * from './src/package';
8
7
  export * from './src/util';
9
8
  export * from './src/file';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/manifest",
3
- "version": "5.0.0-rc.1",
3
+ "version": "5.0.0-rc.2",
4
4
  "description": "Support for project indexing, manifesting, along with file watching",
5
5
  "keywords": [
6
6
  "path",
@@ -22,13 +22,12 @@ export class ManifestIndex {
22
22
  #manifest: ManifestRoot;
23
23
  #modules: IndexedModule[];
24
24
  #modulesByName: Record<string, IndexedModule> = {};
25
- #modulesByFolder: Record<string, IndexedModule> = {};
26
25
  #outputRoot: string;
27
26
  #outputToEntry = new Map<string, IndexedFile>();
28
27
  #sourceToEntry = new Map<string, IndexedFile>();
29
28
  #importToEntry = new Map<string, IndexedFile>();
30
29
 
31
- constructor(manifest: string) {
30
+ constructor(manifest: string = process.env.TRV_MANIFEST!) {
32
31
  this.init(manifest);
33
32
  }
34
33
 
@@ -50,6 +49,14 @@ export class ManifestIndex {
50
49
  this.#index();
51
50
  }
52
51
 
52
+ /**
53
+ * **WARNING**: This is a destructive operation, and should only be called before loading any code
54
+ * @private
55
+ */
56
+ reinitForModule(module: string): void {
57
+ this.init(`${this.outputRoot}/node_modules/${module}`);
58
+ }
59
+
53
60
  #moduleFiles(m: ManifestModule, files: ManifestModuleFile[]): IndexedFile[] {
54
61
  return files.map(([f, type, ts, role = 'std']) => {
55
62
  const isSource = type === 'ts' || type === 'js';
@@ -98,7 +105,6 @@ export class ManifestIndex {
98
105
  }
99
106
  }
100
107
  this.#modulesByName = Object.fromEntries(this.#modules.map(x => [x.name, x]));
101
- this.#modulesByFolder = Object.fromEntries(this.#modules.map(x => [x.sourceFolder, x]));
102
108
 
103
109
  // Store child information
104
110
  for (const mod of this.#modules) {
@@ -162,13 +168,6 @@ export class ManifestIndex {
162
168
  return this.#modulesByName[name];
163
169
  }
164
170
 
165
- /**
166
- * Get module by folder
167
- */
168
- getModuleByFolder(folder: string): IndexedModule | undefined {
169
- return this.#modulesByFolder[folder];
170
- }
171
-
172
171
  /**
173
172
  * Resolve import
174
173
  */
@@ -203,15 +202,6 @@ export class ManifestIndex {
203
202
  return name ? this.getModule(name) : undefined;
204
203
  }
205
204
 
206
- /**
207
- * Get module from import name
208
- * @param importName
209
- */
210
- getModuleFromImport(importName: string): IndexedModule | undefined {
211
- const name = this.getFromImport(importName)?.module;
212
- return name ? this.getModule(name) : undefined;
213
- }
214
-
215
205
  /**
216
206
  * Build module list from an expression list (e.g. `@travetto/rest,-@travetto/log)
217
207
  */
@@ -266,4 +256,34 @@ export class ManifestIndex {
266
256
  );
267
257
  return lookup(file.replace(`${base}/`, '').split('/'));
268
258
  }
259
+
260
+ /**
261
+ * Get manifest module by name
262
+ */
263
+ getManifestModule(mod: string): ManifestModule {
264
+ return this.manifest.modules[mod];
265
+ }
266
+
267
+ /**
268
+ * Get manifest modules
269
+ */
270
+ getManifestModules(): ManifestModule[] {
271
+ return Object.values(this.manifest.modules);
272
+ }
273
+
274
+ /**
275
+ * Get main module for manifest
276
+ */
277
+ get mainModule(): IndexedModule {
278
+ return this.getModule(this.manifest.main.name)!;
279
+ }
280
+
281
+ /**
282
+ * Get source file from import location
283
+ * @param importFile
284
+ */
285
+ getSourceFile(importFile: string | [string, string]): string {
286
+ importFile = Array.isArray(importFile) ? importFile.join('/') : importFile;
287
+ return this.getFromImport(importFile)?.sourceFile ?? importFile;
288
+ }
269
289
  }
@@ -8,13 +8,4 @@ export type ManifestModuleFolderType =
8
8
  'test/fixtures' | 'support/fixtures' | 'support/resources' |
9
9
  '$other' | '$transformer';
10
10
 
11
- export type ManifestModuleRole = 'std' | 'test' | 'doc' | 'compile' | 'build';
12
-
13
- export type FunctionMetadataTag = { hash: number, lines: [number, number] };
14
- export type FunctionMetadata = FunctionMetadataTag & {
15
- id: string;
16
- source: string;
17
- methods?: Record<string, FunctionMetadataTag>;
18
- synthetic?: boolean;
19
- abstract?: boolean;
20
- };
11
+ export type ManifestModuleRole = 'std' | 'test' | 'doc' | 'compile' | 'build';
package/src/global.d.ts DELETED
@@ -1,3 +0,0 @@
1
- declare interface Function {
2
- Ⲑid: string;
3
- }
package/src/runtime.ts DELETED
@@ -1,115 +0,0 @@
1
- import { path } from './path';
2
- import { ManifestIndex } from './manifest-index';
3
- import type { FunctionMetadata, FunctionMetadataTag } from './types/common';
4
- import type { IndexedModule, ManifestModule } from './types/manifest';
5
-
6
- const METADATA = Symbol.for('@travetto/manifest:metadata');
7
- type Metadated = { [METADATA]: FunctionMetadata };
8
-
9
- /**
10
- * Extended manifest index geared for application execution
11
- */
12
- class $RuntimeIndex extends ManifestIndex {
13
-
14
- #metadata = new Map<string, FunctionMetadata>();
15
-
16
- /**
17
- * **WARNING**: This is a destructive operation, and should only be called before loading any code
18
- * @private
19
- */
20
- reinitForModule(module: string): void {
21
- this.init(`${this.outputRoot}/node_modules/${module}`);
22
- }
23
-
24
- /**
25
- * Get internal id from file name and optionally, class name
26
- */
27
- getId(filename: string, clsName?: string): string {
28
- filename = path.toPosix(filename);
29
- const id = this.getEntry(filename)?.id ?? filename;
30
- return clsName ? `${id}○${clsName}` : id;
31
- }
32
-
33
- /**
34
- * Get main module for manifest
35
- */
36
- get mainModule(): IndexedModule {
37
- return this.getModule(this.manifest.main.name)!;
38
- }
39
-
40
- /**
41
- * Get source file from import location
42
- * @param outputFile
43
- */
44
- getSourceFile(importFile: string): string {
45
- return this.getFromImport(importFile)?.sourceFile ?? importFile;
46
- }
47
-
48
- /**
49
- * Initialize the meta data for a function/class
50
- * @param cls Class
51
- * @param `file` Filename
52
- * @param `hash` Hash of class contents
53
- * @param `line` Line number in source
54
- * @param `methods` Methods and their hashes
55
- * @param `abstract` Is the class abstract
56
- * @param `synthetic` Is this code generated at build time
57
- * @private
58
- */
59
- registerFunction(
60
- cls: Function, fileOrImport: string, tag: FunctionMetadataTag,
61
- methods?: Record<string, FunctionMetadataTag>, abstract?: boolean, synthetic?: boolean
62
- ): boolean {
63
- const source = this.getSourceFile(fileOrImport);
64
- const id = this.getId(source, cls.name);
65
- Object.defineProperty(cls, 'Ⲑid', { value: id });
66
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
67
- (cls as unknown as Metadated)[METADATA] = { id, source, ...tag, methods, abstract, synthetic };
68
- this.#metadata.set(id, { id, source, ...tag, methods, abstract, synthetic });
69
- return true;
70
- }
71
-
72
- /**
73
- * Retrieve function metadata by function, or function id
74
- */
75
- getFunctionMetadataFromClass(cls: Function | undefined): FunctionMetadata | undefined {
76
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
77
- return (cls as unknown as Metadated)?.[METADATA];
78
- }
79
-
80
- /**
81
- * Retrieve function metadata by function, or function id
82
- */
83
- getFunctionMetadata(clsId?: string | Function): FunctionMetadata | undefined {
84
- const id = clsId === undefined ? '' : typeof clsId === 'string' ? clsId : clsId.Ⲑid;
85
- return this.#metadata.get(id);
86
- }
87
-
88
- /**
89
- * Resolve module path to folder, with support for main module and monorepo support
90
- */
91
- resolveModulePath(modulePath: string): string {
92
- const main = this.manifest.main.name;
93
- const workspace = this.manifest.workspace.path;
94
- const [base, sub] = modulePath
95
- .replace(/^(@@?)(#|$)/g, (_, v, r) => `${v === '@' ? main : workspace}${r}`)
96
- .split('#');
97
- return path.resolve(this.hasModule(base) ? this.getModule(base)!.sourcePath : base, sub ?? '.');
98
- }
99
-
100
- /**
101
- * Get manifest module by name
102
- */
103
- getManifestModule(mod: string): ManifestModule {
104
- return this.manifest.modules[mod];
105
- }
106
-
107
- /**
108
- * Get manifest modules
109
- */
110
- getManifestModules(): ManifestModule[] {
111
- return Object.values(this.manifest.modules);
112
- }
113
- }
114
-
115
- export const RuntimeIndex = new $RuntimeIndex(process.env.TRV_MANIFEST!);
@@ -1,142 +0,0 @@
1
- import ts from 'typescript';
2
-
3
- import {
4
- TransformerState, OnMethod, OnClass, AfterClass,
5
- AfterFunction, CoreUtil, SystemUtil, Import
6
- } from '@travetto/transformer';
7
-
8
- import type { FunctionMetadataTag } from '../src/types/common';
9
-
10
- const MANIFEST_MOD = '@travetto/manifest';
11
- const MANIFEST_MOD_SRC = `${MANIFEST_MOD}/src`;
12
- const MANIFEST_IDX = `${MANIFEST_MOD}/__index__`;
13
-
14
- const RUNTIME_IDX_IMPORT = `${MANIFEST_MOD_SRC}/runtime`;
15
- const RUNTIME_IDX_CLS = 'RuntimeIndex';
16
-
17
- const methods = Symbol.for(`${MANIFEST_MOD}:methods`);
18
- const cls = Symbol.for(`${MANIFEST_MOD}:class`);
19
- const fn = Symbol.for(`${MANIFEST_MOD}:function`);
20
- const runtimeIdx = Symbol.for(`${MANIFEST_MOD}:runtimeIndex`);
21
-
22
- interface MetadataInfo {
23
- [runtimeIdx]?: Import;
24
- [methods]?: Record<string, FunctionMetadataTag>;
25
- [cls]?: FunctionMetadataTag;
26
- [fn]?: number;
27
- }
28
-
29
- /**
30
- * Providing metadata for classes
31
- */
32
- export class RegisterTransformer {
33
-
34
- static #tag(state: TransformerState, node: ts.Node): FunctionMetadataTag {
35
- const hash = SystemUtil.naiveHash(node.getText());
36
- try {
37
- const range = CoreUtil.getRangeOf(state.source, node) ?? [0, 0];
38
- return { hash, lines: range };
39
- } catch (err) {
40
- return { hash, lines: [0, 0] };
41
- }
42
- }
43
-
44
- static #valid({ importName: imp }: TransformerState): boolean {
45
- return !imp.startsWith(MANIFEST_MOD_SRC) && imp !== MANIFEST_IDX;
46
- }
47
-
48
- /**
49
- * Hash each class
50
- */
51
- @OnClass()
52
- static collectClassMetadata(state: TransformerState & MetadataInfo, node: ts.ClassDeclaration): ts.ClassDeclaration {
53
- if (!this.#valid(state)) {
54
- return node; // Exclude self
55
- }
56
- state[cls] = this.#tag(state, node);
57
- return node;
58
- }
59
-
60
- /**
61
- * Hash each method
62
- */
63
- @OnMethod()
64
- static collectMethodMetadata(state: TransformerState & MetadataInfo, node: ts.MethodDeclaration): ts.MethodDeclaration {
65
- if (state[cls] && ts.isIdentifier(node.name) && !CoreUtil.isAbstract(node) && ts.isClassDeclaration(node.parent)) {
66
- state[methods] ??= {};
67
- state[methods]![node.name.escapedText.toString()] = this.#tag(state, node);
68
- }
69
- return node;
70
- }
71
-
72
- /**
73
- * After visiting each class, register all the collected metadata
74
- */
75
- @AfterClass()
76
- static registerClassMetadata(state: TransformerState & MetadataInfo, node: ts.ClassDeclaration): ts.ClassDeclaration {
77
- if (!state[cls]) {
78
- return node;
79
- }
80
-
81
- state[runtimeIdx] ??= state.importFile(RUNTIME_IDX_IMPORT);
82
- const ident = state.createAccess(state[runtimeIdx].ident, RUNTIME_IDX_CLS);
83
-
84
- const name = node.name?.escapedText.toString() ?? '';
85
-
86
- const meta = state.factory.createCallExpression(
87
- state.createAccess(ident, 'registerFunction'),
88
- [],
89
- [
90
- state.createIdentifier(name),
91
- state.getFilenameIdentifier(),
92
- state.fromLiteral(state[cls]),
93
- state.extendObjectLiteral(state[methods] || {}),
94
- state.fromLiteral(CoreUtil.isAbstract(node)),
95
- state.fromLiteral(name.endsWith(TransformerState.SYNTHETIC_EXT))
96
- ]
97
- );
98
-
99
- state[methods] = {};
100
- delete state[cls];
101
-
102
- return state.factory.updateClassDeclaration(
103
- node,
104
- node.modifiers,
105
- node.name,
106
- node.typeParameters,
107
- node.heritageClauses,
108
- [
109
- state.createStaticField('Ⲑinit', meta),
110
- ...node.members
111
- ]
112
- );
113
- }
114
-
115
- /**
116
- * Give proper functions a file name
117
- */
118
- @AfterFunction()
119
- static registerFunctionMetadata(state: TransformerState & MetadataInfo, node: ts.FunctionDeclaration | ts.FunctionExpression): typeof node {
120
- if (!this.#valid(state)) {
121
- return node;
122
- }
123
-
124
- if (ts.isFunctionDeclaration(node) && node.name && node.parent && ts.isSourceFile(node.parent)) {
125
- // If we have a class like function
126
- state[runtimeIdx] ??= state.importFile(RUNTIME_IDX_IMPORT);
127
- const ident = state.createAccess(state[runtimeIdx].ident, RUNTIME_IDX_CLS);
128
- const tag = this.#tag(state, node);
129
- const meta = state.factory.createCallExpression(
130
- state.createAccess(ident, 'registerFunction'),
131
- [],
132
- [
133
- state.createIdentifier(node.name),
134
- state.getFilenameIdentifier(),
135
- state.fromLiteral(tag),
136
- ]
137
- );
138
- state.addStatements([state.factory.createExpressionStatement(meta)]);
139
- }
140
- return node;
141
- }
142
- }
@@ -1,39 +0,0 @@
1
- import ts from 'typescript';
2
-
3
- import { TransformerState, OnFile } from '@travetto/transformer';
4
-
5
- const PATH_REGEX = /^['"](node:)?path['"]$/;
6
- const PATH_TARGET = '@travetto/manifest/src/path';
7
- const SKIP_SRC = /^@travetto\/manifest\/(src|support)/;
8
-
9
- /**
10
- * Rewriting path imports to use manifest's path
11
- */
12
- export class PathImportTransformer {
13
-
14
- /**
15
- * Hash each class
16
- */
17
- @OnFile()
18
- static rewritePathImport(state: TransformerState, node: ts.SourceFile): ts.SourceFile {
19
- if (SKIP_SRC.test(state.importName)) {
20
- return node;
21
- }
22
-
23
- const stmt = node.statements.find((x): x is ts.ImportDeclaration =>
24
- ts.isImportDeclaration(x) && PATH_REGEX.test(x.moduleSpecifier?.getText() ?? ''));
25
- if (stmt) {
26
- const updated = state.factory.updateImportDeclaration(
27
- stmt,
28
- stmt.modifiers,
29
- stmt.importClause,
30
- state.factory.createStringLiteral(PATH_TARGET),
31
- stmt.attributes
32
- );
33
- return state.factory.updateSourceFile(node, node.statements.map(x =>
34
- x === stmt ? updated : x
35
- ));
36
- }
37
- return node;
38
- }
39
- }