@travetto/manifest 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -21
- package/package.json +1 -1
- package/src/delta.ts +7 -4
- package/src/manifest-index.ts +8 -5
- package/src/module.ts +30 -11
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<!-- This file was generated by @travetto/doc and should not be modified directly -->
|
|
2
|
-
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/manifest/DOC.
|
|
2
|
+
<!-- Please modify https://github.com/travetto/travetto/tree/main/module/manifest/DOC.tsx and execute "npx trv doc" to rebuild -->
|
|
3
3
|
# Manifest
|
|
4
|
+
|
|
4
5
|
## Support for project indexing, manifesting, along with file watching
|
|
5
6
|
|
|
6
7
|
**Install: @travetto/manifest**
|
|
@@ -13,8 +14,6 @@ yarn add @travetto/manifest
|
|
|
13
14
|
```
|
|
14
15
|
|
|
15
16
|
This module aims to be the boundary between the file system and the code. The module provides:
|
|
16
|
-
|
|
17
|
-
|
|
18
17
|
* Project Manifesting
|
|
19
18
|
* Manifest Delta
|
|
20
19
|
* Class and Function Metadata
|
|
@@ -26,7 +25,7 @@ This module aims to be the boundary between the file system and the code. The m
|
|
|
26
25
|
The project manifest fulfills two main goals: Compile-time Support, and Runtime Knowledge of the project.
|
|
27
26
|
|
|
28
27
|
### Compile-time Support
|
|
29
|
-
During the compilation process, the compiler needs to know every file that is eligible for compilation, when the file was last created/modified, and any specific patterns for interacting with a given file (e.g. transformers vs. testing code vs. support files that happen to share a common extension with code).
|
|
28
|
+
During the compilation process, the compiler needs to know every file that is eligible for compilation, when the file was last created/modified, and any specific patterns for interacting with a given file (e.g. transformers vs. testing code vs. support files that happen to share a common extension with code).
|
|
30
29
|
|
|
31
30
|
### Runtime Knowledge
|
|
32
31
|
Additionally, once the code has been compiled (or even bundled after that), the executing process needs to know what files are available for loading, and any patterns necessary for knowing which files to load versus which ones to ignore. This allows for dynamic loading of modules/files without knowledge/access to the file system, and in a more performant manner.
|
|
@@ -35,10 +34,9 @@ Additionally, once the code has been compiled (or even bundled after that), the
|
|
|
35
34
|
During the compilation process, it is helpful to know how the output content differs from the manifest, which is produced from the source input. The [ManifestDeltaUtil](https://github.com/travetto/travetto/tree/main/module/manifest/src/delta.ts#L21) provides the functionality for a given manifest, and will produce a stream of changes grouped by module. This is the primary input into the [Compiler](https://github.com/travetto/travetto/tree/main/module/compiler#readme "The compiler infrastructure for the Travetto framework")'s incremental behavior to know when a file has changed and needs to be recompiled.
|
|
36
35
|
|
|
37
36
|
## Class and Function Metadata
|
|
37
|
+
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.
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
`Ⲑid` is used heavily throughout the framework for determining which classes are owned by the framework, and being able to lookup the needed data from the [RootIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/root-index.ts) using the `getFunctionMetadata` method.
|
|
39
|
+
`Ⲑid` is used heavily throughout the framework for determining which classes are owned by the framework, and being able to lookup the needed data from the [RootIndex](https://github.com/travetto/travetto/tree/main/module/manifest/src/root-index.ts#L12) using the `getFunctionMetadata` method.
|
|
42
40
|
|
|
43
41
|
**Code: Test Class**
|
|
44
42
|
```typescript
|
|
@@ -78,7 +76,6 @@ $ trv main ./doc/lookup.ts
|
|
|
78
76
|
|
|
79
77
|
## Module Indexing
|
|
80
78
|
Once the manifest is created, the application runtime can now read this manifest, which allows for influencing runtime behavior. The most common patterns include:
|
|
81
|
-
|
|
82
79
|
* Loading all source files
|
|
83
80
|
* Iterating over every test file
|
|
84
81
|
* Finding all source folders for watching
|
|
@@ -168,7 +165,7 @@ This method allows for watching one or more folders, and registering a callback
|
|
|
168
165
|
[ "README.md", "md", 1868155200000 ]
|
|
169
166
|
],
|
|
170
167
|
"doc": [
|
|
171
|
-
[ "DOC.
|
|
168
|
+
[ "DOC.tsx", "ts", 1868155200000, "doc" ],
|
|
172
169
|
[ "doc/lookup.ts", "ts", 1868155200000, "doc" ],
|
|
173
170
|
[ "doc/test-class.ts", "ts", 1868155200000, "doc" ]
|
|
174
171
|
],
|
|
@@ -214,25 +211,21 @@ This method allows for watching one or more folders, and registering a callback
|
|
|
214
211
|
```
|
|
215
212
|
|
|
216
213
|
### General Context
|
|
217
|
-
The general context describes the project-space and any important information for how to build/execute the code.
|
|
214
|
+
The general context describes the project-space and any important information for how to build/execute the code.
|
|
218
215
|
|
|
219
216
|
The context contains:
|
|
220
|
-
|
|
221
217
|
* A generated timestamp
|
|
222
|
-
* Module Type: [
|
|
223
|
-
* The main module to execute.
|
|
218
|
+
* Module Type: `commonjs`([CommonJS](https://nodejs.org/api/modules.html)) or `module`([Ecmascript Module](https://nodejs.org/api/esm.html))
|
|
219
|
+
* The main module to execute. (*This primarily pertains to mono-repo support when there are multiple modules in the project*)
|
|
224
220
|
* The root path of the project/workspace
|
|
225
|
-
* Whether or not the project is a mono-repo.
|
|
226
|
-
* The location where all compiled code will be stored. Defaults to: `.trv_output`.
|
|
221
|
+
* Whether or not the project is a mono-repo. (*This is determined by using the 'workspaces' field in your [Package JSON](https://docs.npmjs.com/cli/v9/configuring-npm/package-json)*)
|
|
222
|
+
* The location where all compiled code will be stored. Defaults to: `.trv_output`. (*Can be overridden in your [Package JSON](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) in 'travetto.outputFolder'*)
|
|
227
223
|
* The location where the intermediate compiler will be created. Defaults to: `.trv_compiler`
|
|
228
224
|
* The location where tooling will be able to write to. Defaults to: `.trv_output`
|
|
229
225
|
* Which package manager is in use [Npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) or [Yarn](https://yarnpg.com)
|
|
230
226
|
|
|
231
227
|
### Modules
|
|
232
|
-
The modules represent all of the [Travetto](https://travetto.dev)-aware dependencies (including dev dependencies) used for compiling, testing and executing. A prod-only version is produced when packaging the final output.
|
|
233
|
-
|
|
234
|
-
Each module contains:
|
|
235
|
-
|
|
228
|
+
The modules represent all of the [Travetto](https://travetto.dev)-aware dependencies (including dev dependencies) used for compiling, testing and executing. A prod-only version is produced when packaging the final output. Each module contains:
|
|
236
229
|
* The dependency npm name
|
|
237
230
|
* The dependency version
|
|
238
231
|
* A flag to determine if its a local module
|
|
@@ -245,7 +238,6 @@ Each module contains:
|
|
|
245
238
|
|
|
246
239
|
### Module Files
|
|
247
240
|
The module files are a simple categorization of files into a predetermined set of folders:
|
|
248
|
-
|
|
249
241
|
* $root - All uncategorized files at the module root
|
|
250
242
|
* $index - __index__.ts, index.ts files at the root of the project
|
|
251
243
|
* $package - The [Package JSON](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) for the project
|
|
@@ -259,7 +251,6 @@ The module files are a simple categorization of files into a predetermined set o
|
|
|
259
251
|
* doc - Documentation files. All .ts files under the doc/ folder
|
|
260
252
|
* $transformer - All .ts files under the pattern support/transform*. These are used during compilation and never at runtime
|
|
261
253
|
* bin - Entry point .js files. All .js files under the bin/ folder
|
|
262
|
-
|
|
263
254
|
Within each file there is a pattern of either a 3 or 4 element array:
|
|
264
255
|
|
|
265
256
|
**Code: Sample file**
|
package/package.json
CHANGED
package/src/delta.ts
CHANGED
|
@@ -36,15 +36,18 @@ export class ManifestDeltaUtil {
|
|
|
36
36
|
const root = `${ctx.workspacePath}/${ctx.outputFolder}/${left.outputFolder}`;
|
|
37
37
|
const right = new Set(
|
|
38
38
|
(await ManifestModuleUtil.scanFolder(root, left.main))
|
|
39
|
-
.filter(x =>
|
|
40
|
-
|
|
39
|
+
.filter(x => {
|
|
40
|
+
const type = ManifestModuleUtil.getFileType(x);
|
|
41
|
+
return type === 'ts' || type === 'typings' || type === 'js' || type === 'package-json';
|
|
42
|
+
})
|
|
43
|
+
.map(x => ManifestModuleUtil.sourceToBlankExt(x.replace(`${root}/`, '')))
|
|
41
44
|
);
|
|
42
45
|
|
|
43
46
|
for (const el of Object.keys(left.files)) {
|
|
44
|
-
const output = `${outputFolder}/${left.outputFolder}/${el
|
|
47
|
+
const output = ManifestModuleUtil.sourceToOutputExt(`${outputFolder}/${left.outputFolder}/${el}`);
|
|
45
48
|
const [, , leftTs] = left.files[el];
|
|
46
49
|
const stat = await fs.stat(output).catch(() => { });
|
|
47
|
-
right.delete(
|
|
50
|
+
right.delete(ManifestModuleUtil.sourceToBlankExt(el));
|
|
48
51
|
|
|
49
52
|
if (!stat) {
|
|
50
53
|
add(el, 'added');
|
package/src/manifest-index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ManifestModuleUtil } from './module';
|
|
1
2
|
import { path } from './path';
|
|
2
3
|
|
|
3
4
|
import {
|
|
@@ -78,13 +79,14 @@ export class ManifestIndex {
|
|
|
78
79
|
|
|
79
80
|
#moduleFiles(m: ManifestModule, files: ManifestModuleFile[]): IndexedFile[] {
|
|
80
81
|
return files.map(([f, type, ts, profile = 'std']) => {
|
|
82
|
+
const isSource = type === 'ts' || type === 'js';
|
|
81
83
|
const sourceFile = path.resolve(this.#manifest.workspacePath, m.sourceFolder, f);
|
|
82
|
-
const js =
|
|
84
|
+
const js = isSource ? ManifestModuleUtil.sourceToOutputExt(f) : f;
|
|
83
85
|
const outputFile = this.#resolveOutput(m.outputFolder, js);
|
|
84
86
|
const modImport = `${m.name}/${js}`;
|
|
85
87
|
let id = modImport.replace(`${m.name}/`, _ => _.replace(/[/]$/, ':'));
|
|
86
|
-
if (
|
|
87
|
-
id =
|
|
88
|
+
if (isSource) {
|
|
89
|
+
id = ManifestModuleUtil.sourceToBlankExt(id);
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
return { id, type, sourceFile, outputFile, import: modImport, profile, relativeFile: f, module: m.name };
|
|
@@ -117,7 +119,6 @@ export class ManifestIndex {
|
|
|
117
119
|
this.#sourceToEntry.set(entry.sourceFile, entry);
|
|
118
120
|
this.#importToEntry.set(entry.import, entry);
|
|
119
121
|
this.#importToEntry.set(entry.import.replace(/[.]js$/, ''), entry);
|
|
120
|
-
this.#importToEntry.set(entry.import.replace(/[.]js$/, '.ts'), entry);
|
|
121
122
|
}
|
|
122
123
|
}
|
|
123
124
|
}
|
|
@@ -221,7 +222,7 @@ export class ManifestIndex {
|
|
|
221
222
|
* Resolve import
|
|
222
223
|
*/
|
|
223
224
|
resolveFileImport(name: string): string {
|
|
224
|
-
return this
|
|
225
|
+
return this.getFromImport(name)?.outputFile ?? name;
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
/**
|
|
@@ -237,6 +238,8 @@ export class ManifestIndex {
|
|
|
237
238
|
* @param source
|
|
238
239
|
*/
|
|
239
240
|
getFromImport(imp: string): IndexedFile | undefined {
|
|
241
|
+
// Strip ext
|
|
242
|
+
imp = ManifestModuleUtil.sourceToBlankExt(imp);
|
|
240
243
|
return this.#importToEntry.get(imp);
|
|
241
244
|
}
|
|
242
245
|
|
package/src/module.ts
CHANGED
|
@@ -15,17 +15,15 @@ const EXT_MAPPING: Record<string, ManifestModuleFileType> = {
|
|
|
15
15
|
'.cjs': 'js',
|
|
16
16
|
'.json': 'json',
|
|
17
17
|
'.ts': 'ts',
|
|
18
|
+
'.tsx': 'ts',
|
|
18
19
|
'.md': 'md'
|
|
19
20
|
};
|
|
20
21
|
|
|
21
|
-
const INDEX_FILES = new Set(
|
|
22
|
-
'index
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
'__index.ts',
|
|
27
|
-
'__index.js'
|
|
28
|
-
]);
|
|
22
|
+
const INDEX_FILES = new Set(
|
|
23
|
+
['__index__', '__index', 'index', 'jsx-runtime'].flatMap(f =>
|
|
24
|
+
['ts', 'tsx', 'js'].map(ext => `${f}.${ext}`)
|
|
25
|
+
)
|
|
26
|
+
);
|
|
29
27
|
|
|
30
28
|
export class ManifestModuleUtil {
|
|
31
29
|
|
|
@@ -35,6 +33,13 @@ export class ManifestModuleUtil {
|
|
|
35
33
|
return Math.max(stat.mtimeMs, stat.ctimeMs);
|
|
36
34
|
}
|
|
37
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Replace a source file's extension with a given value
|
|
38
|
+
*/
|
|
39
|
+
static #sourceToExtension(inputFile: string, ext: string): string {
|
|
40
|
+
return inputFile.replace(/[.][tj]sx?$/, ext);
|
|
41
|
+
}
|
|
42
|
+
|
|
38
43
|
/**
|
|
39
44
|
* Simple file scanning
|
|
40
45
|
*/
|
|
@@ -93,7 +98,7 @@ export class ManifestModuleUtil {
|
|
|
93
98
|
* Get file type for a file name
|
|
94
99
|
*/
|
|
95
100
|
static getFileType(moduleFile: string): ManifestModuleFileType {
|
|
96
|
-
if (moduleFile
|
|
101
|
+
if (moduleFile.endsWith('package.json')) {
|
|
97
102
|
return 'package-json';
|
|
98
103
|
} else if (
|
|
99
104
|
moduleFile.startsWith('support/fixtures/') ||
|
|
@@ -117,7 +122,7 @@ export class ManifestModuleUtil {
|
|
|
117
122
|
return 'compile';
|
|
118
123
|
} else if (moduleFile.startsWith('support/test/') || moduleFile.startsWith('test/')) {
|
|
119
124
|
return 'test';
|
|
120
|
-
} else if (moduleFile.startsWith('doc/') ||
|
|
125
|
+
} else if (moduleFile.startsWith('doc/') || /^DOC[.]tsx?$/.test(moduleFile)) {
|
|
121
126
|
return 'doc';
|
|
122
127
|
} else {
|
|
123
128
|
return;
|
|
@@ -149,7 +154,7 @@ export class ManifestModuleUtil {
|
|
|
149
154
|
case 'support': return key;
|
|
150
155
|
default: return '$other';
|
|
151
156
|
}
|
|
152
|
-
} else if (
|
|
157
|
+
} else if (/^DOC[.]tsx?$/.test(moduleFile)) {
|
|
153
158
|
return 'doc';
|
|
154
159
|
} else if (INDEX_FILES.has(moduleFile)) {
|
|
155
160
|
return '$index';
|
|
@@ -210,4 +215,18 @@ export class ManifestModuleUtil {
|
|
|
210
215
|
const modules = await Promise.all(sorted.map(x => this.describeModule(ctx, x)));
|
|
211
216
|
return Object.fromEntries(modules.map(m => [m.name, m]));
|
|
212
217
|
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get the output file name for a given input
|
|
221
|
+
*/
|
|
222
|
+
static sourceToOutputExt(inputFile: string): string {
|
|
223
|
+
return this.#sourceToExtension(inputFile, '.js');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Get the file without an extension
|
|
228
|
+
*/
|
|
229
|
+
static sourceToBlankExt(inputFile: string): string {
|
|
230
|
+
return this.#sourceToExtension(inputFile, '');
|
|
231
|
+
}
|
|
213
232
|
}
|