@travetto/manifest 4.1.0 → 5.0.0-rc.1
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 -5
- package/__index__.ts +2 -2
- package/bin/context.d.ts +1 -1
- package/package.json +2 -2
- package/src/file.ts +4 -9
- package/src/package.ts +1 -1
- package/src/path.ts +38 -28
- package/src/runtime.ts +6 -46
- package/src/util.ts +2 -2
- package/support/transformer.function-metadata.ts +3 -2
- package/support/transformer.rewrite-path-import.ts +39 -0
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#
|
|
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.
|
|
39
39
|
|
|
40
40
|
**Code: Test Class**
|
|
41
41
|
```typescript
|
|
@@ -51,12 +51,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
51
51
|
exports.TestClass = void 0;
|
|
52
52
|
const tslib_1 = require("tslib");
|
|
53
53
|
const Ⲑ_runtime_1 = tslib_1.__importStar(require("@travetto/manifest/src/runtime.js"));
|
|
54
|
+
const Ⲑ_decorator_1 = tslib_1.__importStar(require("@travetto/registry/src/decorator.js"));
|
|
54
55
|
var ᚕf = "@travetto/manifest/doc/test-class.js";
|
|
55
|
-
class TestClass {
|
|
56
|
+
let TestClass = class TestClass {
|
|
56
57
|
static Ⲑinit = Ⲑ_runtime_1.RuntimeIndex.registerFunction(TestClass, ᚕf, { hash: 197152026, lines: [1, 3] }, { doStuff: { hash: 51337554, lines: [2, 2] } }, false, false);
|
|
57
58
|
async doStuff() { }
|
|
58
|
-
}
|
|
59
|
+
};
|
|
59
60
|
exports.TestClass = TestClass;
|
|
61
|
+
exports.TestClass = TestClass = tslib_1.__decorate([
|
|
62
|
+
Ⲑ_decorator_1.Register()
|
|
63
|
+
], TestClass);
|
|
60
64
|
```
|
|
61
65
|
|
|
62
66
|
**Terminal: Index Lookup at Runtime**
|
|
@@ -85,7 +89,9 @@ Once the manifest is created, the application runtime can now read this manifest
|
|
|
85
89
|
* Providing contextual information when provided a filename, import name, etc (e.g. logging, testing output)
|
|
86
90
|
|
|
87
91
|
## Path Normalization
|
|
88
|
-
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#
|
|
92
|
+
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
|
+
|
|
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.
|
|
89
95
|
|
|
90
96
|
## Anatomy of a Manifest
|
|
91
97
|
|
|
@@ -151,7 +157,8 @@ By default, all paths within the framework are assumed to be in a POSIX style, a
|
|
|
151
157
|
[ "test/fixtures/simple.ts", "fixture", 1868155200000, "test" ]
|
|
152
158
|
],
|
|
153
159
|
"$transformer": [
|
|
154
|
-
[ "support/transformer.function-metadata.ts", "ts", 1868155200000, "compile" ]
|
|
160
|
+
[ "support/transformer.function-metadata.ts", "ts", 1868155200000, "compile" ],
|
|
161
|
+
[ "support/transformer.rewrite-path-import.ts", "ts", 1868155200000, "compile" ]
|
|
155
162
|
],
|
|
156
163
|
"src": [
|
|
157
164
|
[ "src/delta.ts", "ts", 1868155200000 ],
|
package/__index__.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/// <reference path="./src/global.d.ts" />
|
|
2
2
|
|
|
3
|
-
export * from './src/path';
|
|
4
3
|
export * from './src/module';
|
|
5
4
|
export * from './src/delta';
|
|
6
5
|
export * from './src/manifest-index';
|
|
@@ -11,4 +10,5 @@ export * from './src/file';
|
|
|
11
10
|
export * from './src/types/context';
|
|
12
11
|
export * from './src/types/package';
|
|
13
12
|
export * from './src/types/manifest';
|
|
14
|
-
export * from './src/types/common';
|
|
13
|
+
export * from './src/types/common';
|
|
14
|
+
export { path } from './src/path';
|
package/bin/context.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/manifest",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-rc.1",
|
|
4
4
|
"description": "Support for project indexing, manifesting, along with file watching",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"path",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
],
|
|
25
25
|
"main": "__index__.ts",
|
|
26
26
|
"engines": {
|
|
27
|
-
"node": ">=
|
|
27
|
+
"node": ">=22.0.0"
|
|
28
28
|
},
|
|
29
29
|
"repository": {
|
|
30
30
|
"url": "https://github.com/travetto/travetto.git",
|
package/src/file.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import os from 'node:os';
|
|
2
1
|
import fs from 'node:fs/promises';
|
|
3
2
|
import { readFileSync } from 'node:fs';
|
|
4
3
|
|
|
@@ -8,15 +7,11 @@ export class ManifestFileUtil {
|
|
|
8
7
|
/**
|
|
9
8
|
* Write file and copy over when ready
|
|
10
9
|
*/
|
|
11
|
-
static async bufferedFileWrite(file: string, content: string
|
|
12
|
-
const
|
|
13
|
-
const tempName = `${path.basename(file, ext)}.${process.ppid}.${process.pid}.${Date.now()}.${Math.random()}${ext}`;
|
|
10
|
+
static async bufferedFileWrite(file: string, content: string): Promise<void> {
|
|
11
|
+
const temp = path.resolve(path.dirname(file), `.${process.hrtime()[0]}.${path.basename(file)}`);
|
|
14
12
|
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
15
|
-
|
|
16
|
-
await fs.
|
|
17
|
-
await fs.copyFile(temp, file);
|
|
18
|
-
fs.unlink(temp); // Don't wait for completion
|
|
19
|
-
return file;
|
|
13
|
+
await fs.writeFile(temp, content, 'utf8');
|
|
14
|
+
await fs.rename(temp, file);
|
|
20
15
|
}
|
|
21
16
|
|
|
22
17
|
/**
|
package/src/package.ts
CHANGED
package/src/path.ts
CHANGED
|
@@ -1,35 +1,45 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import posix from 'node:path/posix';
|
|
2
|
+
import win32 from 'node:path/win32';
|
|
3
|
+
import native from 'node:path';
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Converts a given file name by replace all slashes, with forward slashes
|
|
7
|
-
*/
|
|
8
5
|
const toPosix = (file: string): string => file.replaceAll('\\', '/');
|
|
9
|
-
|
|
10
|
-
* Converts a given file name by replace all slashes, with platform dependent path separators
|
|
11
|
-
*/
|
|
12
|
-
const toNative = (file: string): string => file.replace(/[\\\/]+/g, sep);
|
|
13
|
-
|
|
6
|
+
const toNative = (file: string): string => file.replace(/[\/]/g, native.sep);
|
|
14
7
|
const cwd = (): string => toPosix(process.cwd());
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
9
|
+
export const path: posix.PlatformPath & {
|
|
10
|
+
native: posix.PlatformPath;
|
|
11
|
+
toPosix: typeof toPosix;
|
|
12
|
+
toNative: typeof toNative;
|
|
13
|
+
} = {
|
|
14
|
+
sep: posix.sep,
|
|
15
|
+
delimiter: posix.delimiter,
|
|
16
|
+
posix,
|
|
17
|
+
win32,
|
|
18
|
+
native,
|
|
19
|
+
basename: (file, suffix) => posix.basename(toPosix(file), suffix),
|
|
20
|
+
extname: file => posix.extname(toPosix(file)),
|
|
21
|
+
dirname: file => posix.dirname(toPosix(file)),
|
|
24
22
|
toNative,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
toPosix,
|
|
24
|
+
...process.platform === 'win32' ? {
|
|
25
|
+
resolve: (...args) => toPosix(native.resolve(cwd(), ...args.map(toPosix))),
|
|
26
|
+
join: (root, ...args) => toPosix(native.join(toPosix(root), ...args.map(toPosix))),
|
|
27
|
+
relative: (from, to) => toPosix(native.relative(toPosix(from), toPosix(to))),
|
|
28
|
+
isAbsolute: (file) => native.isAbsolute(toPosix(file)),
|
|
29
|
+
normalize: (file) => toPosix(native.normalize(toPosix(file))),
|
|
30
|
+
parse: (file) => native.parse(toPosix(file)),
|
|
31
|
+
format: (obj) => toPosix(native.format(obj)),
|
|
32
|
+
toNamespacedPath: (file) => toPosix(native.toNamespacedPath(toPosix(file))),
|
|
33
|
+
} : {
|
|
34
|
+
relative: (from, to) => posix.relative(toPosix(from), toPosix(to)),
|
|
35
|
+
resolve: (...args) => posix.resolve(cwd(), ...args.map(toPosix)),
|
|
36
|
+
join: (...args) => posix.join(...args.map(toPosix)),
|
|
37
|
+
isAbsolute: file => posix.isAbsolute(toPosix(file)),
|
|
38
|
+
normalize: file => posix.normalize(toPosix(file)),
|
|
39
|
+
parse: file => posix.parse(toPosix(file)),
|
|
40
|
+
format: obj => posix.format(obj),
|
|
41
|
+
toNamespacedPath: file => toPosix(file),
|
|
42
|
+
}
|
|
30
43
|
};
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
path.resolve = (...args: string[]): string => toPosix(nativeResolve(cwd(), ...args.map(toPosix)));
|
|
34
|
-
path.join = (root: string, ...args: string[]): string => toPosix(nativeJoin(toPosix(root), ...args.map(toPosix)));
|
|
35
|
-
}
|
|
45
|
+
export default path;
|
package/src/runtime.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { path } from './path';
|
|
2
2
|
import { ManifestIndex } from './manifest-index';
|
|
3
|
-
|
|
4
3
|
import type { FunctionMetadata, FunctionMetadataTag } from './types/common';
|
|
5
4
|
import type { IndexedModule, ManifestModule } from './types/manifest';
|
|
6
|
-
import type { ManifestContext } from './types/context';
|
|
7
5
|
|
|
8
6
|
const METADATA = Symbol.for('@travetto/manifest:metadata');
|
|
9
7
|
type Metadated = { [METADATA]: FunctionMetadata };
|
|
@@ -40,9 +38,9 @@ class $RuntimeIndex extends ManifestIndex {
|
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
/**
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
* Get source file from import location
|
|
42
|
+
* @param outputFile
|
|
43
|
+
*/
|
|
46
44
|
getSourceFile(importFile: string): string {
|
|
47
45
|
return this.getFromImport(importFile)?.sourceFile ?? importFile;
|
|
48
46
|
}
|
|
@@ -56,6 +54,7 @@ class $RuntimeIndex extends ManifestIndex {
|
|
|
56
54
|
* @param `methods` Methods and their hashes
|
|
57
55
|
* @param `abstract` Is the class abstract
|
|
58
56
|
* @param `synthetic` Is this code generated at build time
|
|
57
|
+
* @private
|
|
59
58
|
*/
|
|
60
59
|
registerFunction(
|
|
61
60
|
cls: Function, fileOrImport: string, tag: FunctionMetadataTag,
|
|
@@ -81,7 +80,7 @@ class $RuntimeIndex extends ManifestIndex {
|
|
|
81
80
|
/**
|
|
82
81
|
* Retrieve function metadata by function, or function id
|
|
83
82
|
*/
|
|
84
|
-
getFunctionMetadata(clsId
|
|
83
|
+
getFunctionMetadata(clsId?: string | Function): FunctionMetadata | undefined {
|
|
85
84
|
const id = clsId === undefined ? '' : typeof clsId === 'string' ? clsId : clsId.Ⲑid;
|
|
86
85
|
return this.#metadata.get(id);
|
|
87
86
|
}
|
|
@@ -113,43 +112,4 @@ class $RuntimeIndex extends ManifestIndex {
|
|
|
113
112
|
}
|
|
114
113
|
}
|
|
115
114
|
|
|
116
|
-
export const RuntimeIndex = new $RuntimeIndex(process.env.TRV_MANIFEST!);
|
|
117
|
-
|
|
118
|
-
const build = <T extends object, K extends keyof ManifestContext>(inp: T, props: K[]): T & Pick<ManifestContext, K> => {
|
|
119
|
-
for (const prop of props) {
|
|
120
|
-
Object.defineProperty(inp, prop, { configurable: false, get: () => RuntimeIndex.manifest[prop] });
|
|
121
|
-
}
|
|
122
|
-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
123
|
-
return inp as T & ManifestContext;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
export const RuntimeContext = build({
|
|
127
|
-
/**
|
|
128
|
-
* Produce a workspace relative path
|
|
129
|
-
* @param rel The relative path
|
|
130
|
-
*/
|
|
131
|
-
workspaceRelative(...rel: string[]): string {
|
|
132
|
-
return path.resolve(RuntimeIndex.manifest.workspace.path, ...rel);
|
|
133
|
-
},
|
|
134
|
-
/**
|
|
135
|
-
* Strip off the workspace path from a file
|
|
136
|
-
* @param full A full path
|
|
137
|
-
*/
|
|
138
|
-
stripWorkspacePath(full: string): string {
|
|
139
|
-
return full === RuntimeIndex.manifest.workspace.path ? '' : full.replace(`${RuntimeIndex.manifest.workspace.path}/`, '');
|
|
140
|
-
},
|
|
141
|
-
/**
|
|
142
|
-
* Produce a workspace path for tooling, with '@' being replaced by node_module/name folder
|
|
143
|
-
* @param rel The relative path
|
|
144
|
-
*/
|
|
145
|
-
toolPath(...rel: string[]): string {
|
|
146
|
-
rel = rel.flatMap(x => x === '@' ? ['node_modules', RuntimeIndex.manifest.main.name] : [x]);
|
|
147
|
-
return path.resolve(RuntimeIndex.manifest.workspace.path, RuntimeIndex.manifest.build.toolFolder, ...rel);
|
|
148
|
-
},
|
|
149
|
-
/**
|
|
150
|
-
* Are we running from a mono-root?
|
|
151
|
-
*/
|
|
152
|
-
get monoRoot(): boolean {
|
|
153
|
-
return !!RuntimeIndex.manifest.workspace.mono && !RuntimeIndex.manifest.main.folder;
|
|
154
|
-
}
|
|
155
|
-
}, ['main', 'workspace']);
|
|
115
|
+
export const RuntimeIndex = new $RuntimeIndex(process.env.TRV_MANIFEST!);
|
package/src/util.ts
CHANGED
|
@@ -69,8 +69,8 @@ export class ManifestUtil {
|
|
|
69
69
|
const manifest: ManifestRoot = ManifestFileUtil.readAsJsonSync(file);
|
|
70
70
|
// Support packaged environments, by allowing empty manifest.build.outputFolder
|
|
71
71
|
if (manifest.build.outputFolder === '$$PRODUCTION$$') {
|
|
72
|
-
manifest.build.outputFolder = path.
|
|
73
|
-
manifest.workspace.path = path.
|
|
72
|
+
manifest.build.outputFolder = path.resolve();
|
|
73
|
+
manifest.workspace.path = path.resolve();
|
|
74
74
|
}
|
|
75
75
|
return manifest;
|
|
76
76
|
}
|
|
@@ -8,9 +8,10 @@ import {
|
|
|
8
8
|
import type { FunctionMetadataTag } from '../src/types/common';
|
|
9
9
|
|
|
10
10
|
const MANIFEST_MOD = '@travetto/manifest';
|
|
11
|
+
const MANIFEST_MOD_SRC = `${MANIFEST_MOD}/src`;
|
|
11
12
|
const MANIFEST_IDX = `${MANIFEST_MOD}/__index__`;
|
|
12
13
|
|
|
13
|
-
const RUNTIME_IDX_IMPORT = `${
|
|
14
|
+
const RUNTIME_IDX_IMPORT = `${MANIFEST_MOD_SRC}/runtime`;
|
|
14
15
|
const RUNTIME_IDX_CLS = 'RuntimeIndex';
|
|
15
16
|
|
|
16
17
|
const methods = Symbol.for(`${MANIFEST_MOD}:methods`);
|
|
@@ -41,7 +42,7 @@ export class RegisterTransformer {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
static #valid({ importName: imp }: TransformerState): boolean {
|
|
44
|
-
return !imp.startsWith(
|
|
45
|
+
return !imp.startsWith(MANIFEST_MOD_SRC) && imp !== MANIFEST_IDX;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
/**
|
|
@@ -0,0 +1,39 @@
|
|
|
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
|
+
}
|