@metaobjectsdev/render 1.0.8 → 1.0.9-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 +4 -0
- package/dist/filesystem-provider.d.ts +10 -0
- package/dist/filesystem-provider.d.ts.map +1 -0
- package/dist/filesystem-provider.js +42 -0
- package/dist/filesystem-provider.js.map +1 -0
- package/dist/providers.d.ts +3 -0
- package/dist/providers.d.ts.map +1 -0
- package/dist/providers.js +7 -0
- package/dist/providers.js.map +1 -0
- package/package.json +6 -1
- package/src/filesystem-provider.ts +44 -0
- package/src/providers.ts +6 -0
package/README.md
CHANGED
|
@@ -14,6 +14,10 @@ npm install @metaobjectsdev/render
|
|
|
14
14
|
|
|
15
15
|
- **`render()`** — render a MetaObjects `template.output` / `template.prompt` against a typed payload. Deterministic and cache-stable (no whitespace drift that would silently break exact-prefix prompt-cache hits), so output is snapshot-testable.
|
|
16
16
|
- **Provider-resolved partials + format-driven escaping** (text / html / xml / csv / json / markdown).
|
|
17
|
+
- **Providers** — `InMemoryProvider` (root entry, browser-safe) and `FilesystemProvider`
|
|
18
|
+
(Node-only, on the `@metaobjectsdev/render/providers` subpath so the root entry never
|
|
19
|
+
pulls in `node:fs`). `new FilesystemProvider("./prompts").resolve("lobby/welcome")` reads
|
|
20
|
+
`./prompts/lobby/welcome.mustache`, exactly as the C#, Java and Python ports do.
|
|
17
21
|
- **`verify()`** — a build-time drift check that every `{{field}}` referenced by a template resolves to a field on its payload value-object; a renamed field fails the build instead of silently degrading a prompt.
|
|
18
22
|
|
|
19
23
|
This engine backs the prompt-construction pillar — the generated `render<Name>()` helpers emitted by `@metaobjectsdev/codegen-ts` wrap it. See the **metaobjects-prompts** skill and the repo `docs/` for authoring `template.*` and payload VOs.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Provider } from "./provider.js";
|
|
2
|
+
/** The default template file extension, shared with every other port. */
|
|
3
|
+
export declare const DEFAULT_TEMPLATE_EXTENSION = ".mustache";
|
|
4
|
+
export declare class FilesystemProvider implements Provider {
|
|
5
|
+
private readonly extension;
|
|
6
|
+
private readonly root;
|
|
7
|
+
constructor(root: string, extension?: string);
|
|
8
|
+
resolve(ref: string): string | undefined;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=filesystem-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem-provider.d.ts","sourceRoot":"","sources":["../src/filesystem-provider.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,yEAAyE;AACzE,eAAO,MAAM,0BAA0B,cAAc,CAAC;AAKtD,qBAAa,kBAAmB,YAAW,QAAQ;IAGvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAFpD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,IAAI,EAAE,MAAM,EAAmB,SAAS,GAAE,MAAmC;IAIzF,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAezC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Filesystem-backed provider: resolves a `group/source` reference to
|
|
2
|
+
// <root>/<group>/<source>.mustache. NODE-ONLY — it is reachable solely through
|
|
3
|
+
// the `@metaobjectsdev/render/providers` subpath so the package's root entry
|
|
4
|
+
// stays importable in a browser bundle.
|
|
5
|
+
//
|
|
6
|
+
// Mirrors the C# MetaObjects.Render.FilesystemProvider, the Java
|
|
7
|
+
// com.metaobjects.render.FilesystemProvider and the Python
|
|
8
|
+
// metaobjects.render.FilesystemProvider: read the file when present, return
|
|
9
|
+
// undefined when absent / unreadable / not a regular file, and refuse a ref that
|
|
10
|
+
// escapes the root (undefined, never a throw).
|
|
11
|
+
import { readFileSync, statSync } from "node:fs";
|
|
12
|
+
import { resolve, sep } from "node:path";
|
|
13
|
+
/** The default template file extension, shared with every other port. */
|
|
14
|
+
export const DEFAULT_TEMPLATE_EXTENSION = ".mustache";
|
|
15
|
+
const REF_SEPARATOR = "/";
|
|
16
|
+
const PARENT_SEGMENT = "..";
|
|
17
|
+
export class FilesystemProvider {
|
|
18
|
+
extension;
|
|
19
|
+
root;
|
|
20
|
+
constructor(root, extension = DEFAULT_TEMPLATE_EXTENSION) {
|
|
21
|
+
this.extension = extension;
|
|
22
|
+
this.root = resolve(root);
|
|
23
|
+
}
|
|
24
|
+
resolve(ref) {
|
|
25
|
+
const segments = ref.split(REF_SEPARATOR).filter((s) => s.length > 0);
|
|
26
|
+
if (segments.length === 0 || segments.includes(PARENT_SEGMENT))
|
|
27
|
+
return undefined;
|
|
28
|
+
const candidate = resolve(this.root, ...segments) + this.extension;
|
|
29
|
+
// Path-traversal guard (belt-and-suspenders after the `..` check).
|
|
30
|
+
if (!candidate.startsWith(this.root + sep))
|
|
31
|
+
return undefined;
|
|
32
|
+
try {
|
|
33
|
+
if (!statSync(candidate).isFile())
|
|
34
|
+
return undefined;
|
|
35
|
+
return readFileSync(candidate, "utf8");
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=filesystem-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filesystem-provider.js","sourceRoot":"","sources":["../src/filesystem-provider.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,+EAA+E;AAC/E,6EAA6E;AAC7E,wCAAwC;AACxC,EAAE;AACF,iEAAiE;AACjE,2DAA2D;AAC3D,4EAA4E;AAC5E,iFAAiF;AACjF,+CAA+C;AAE/C,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGzC,yEAAyE;AACzE,MAAM,CAAC,MAAM,0BAA0B,GAAG,WAAW,CAAC;AAEtD,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,MAAM,OAAO,kBAAkB;IAGc;IAF1B,IAAI,CAAS;IAE9B,YAAY,IAAY,EAAmB,YAAoB,0BAA0B;QAA9C,cAAS,GAAT,SAAS,CAAqC;QACvF,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,CAAC,GAAW;QACjB,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACtE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC;YAAE,OAAO,SAAS,CAAC;QAEjF,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QACnE,mEAAmE;QACnE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QAE7D,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE;gBAAE,OAAO,SAAS,CAAC;YACpD,OAAO,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAE,KAAK,QAAQ,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// `@metaobjectsdev/render/providers` — the NODE-ONLY provider entry.
|
|
2
|
+
//
|
|
3
|
+
// The root entry (`@metaobjectsdev/render`) is browser-safe and must stay that
|
|
4
|
+
// way; anything that touches the filesystem lives behind this subpath.
|
|
5
|
+
export { FilesystemProvider, DEFAULT_TEMPLATE_EXTENSION } from "./filesystem-provider.js";
|
|
6
|
+
export { InMemoryProvider } from "./provider.js";
|
|
7
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,EAAE;AACF,+EAA+E;AAC/E,uEAAuE;AACvE,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAiB,gBAAgB,EAAE,MAAM,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/render",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9-rc.1",
|
|
4
4
|
"description": "Logic-less, deterministic text render engine (Mustache) for MetaObjects templates — provider-resolved partials, format-driven escaping, zero core dependency.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
"bun": "./src/index.ts",
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
12
|
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./providers": {
|
|
15
|
+
"bun": "./src/providers.ts",
|
|
16
|
+
"types": "./dist/providers.d.ts",
|
|
17
|
+
"default": "./dist/providers.js"
|
|
13
18
|
}
|
|
14
19
|
},
|
|
15
20
|
"files": [
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Filesystem-backed provider: resolves a `group/source` reference to
|
|
2
|
+
// <root>/<group>/<source>.mustache. NODE-ONLY — it is reachable solely through
|
|
3
|
+
// the `@metaobjectsdev/render/providers` subpath so the package's root entry
|
|
4
|
+
// stays importable in a browser bundle.
|
|
5
|
+
//
|
|
6
|
+
// Mirrors the C# MetaObjects.Render.FilesystemProvider, the Java
|
|
7
|
+
// com.metaobjects.render.FilesystemProvider and the Python
|
|
8
|
+
// metaobjects.render.FilesystemProvider: read the file when present, return
|
|
9
|
+
// undefined when absent / unreadable / not a regular file, and refuse a ref that
|
|
10
|
+
// escapes the root (undefined, never a throw).
|
|
11
|
+
|
|
12
|
+
import { readFileSync, statSync } from "node:fs";
|
|
13
|
+
import { resolve, sep } from "node:path";
|
|
14
|
+
import type { Provider } from "./provider.js";
|
|
15
|
+
|
|
16
|
+
/** The default template file extension, shared with every other port. */
|
|
17
|
+
export const DEFAULT_TEMPLATE_EXTENSION = ".mustache";
|
|
18
|
+
|
|
19
|
+
const REF_SEPARATOR = "/";
|
|
20
|
+
const PARENT_SEGMENT = "..";
|
|
21
|
+
|
|
22
|
+
export class FilesystemProvider implements Provider {
|
|
23
|
+
private readonly root: string;
|
|
24
|
+
|
|
25
|
+
constructor(root: string, private readonly extension: string = DEFAULT_TEMPLATE_EXTENSION) {
|
|
26
|
+
this.root = resolve(root);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
resolve(ref: string): string | undefined {
|
|
30
|
+
const segments = ref.split(REF_SEPARATOR).filter((s) => s.length > 0);
|
|
31
|
+
if (segments.length === 0 || segments.includes(PARENT_SEGMENT)) return undefined;
|
|
32
|
+
|
|
33
|
+
const candidate = resolve(this.root, ...segments) + this.extension;
|
|
34
|
+
// Path-traversal guard (belt-and-suspenders after the `..` check).
|
|
35
|
+
if (!candidate.startsWith(this.root + sep)) return undefined;
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
if (!statSync(candidate).isFile()) return undefined;
|
|
39
|
+
return readFileSync(candidate, "utf8");
|
|
40
|
+
} catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/providers.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// `@metaobjectsdev/render/providers` — the NODE-ONLY provider entry.
|
|
2
|
+
//
|
|
3
|
+
// The root entry (`@metaobjectsdev/render`) is browser-safe and must stay that
|
|
4
|
+
// way; anything that touches the filesystem lives behind this subpath.
|
|
5
|
+
export { FilesystemProvider, DEFAULT_TEMPLATE_EXTENSION } from "./filesystem-provider.js";
|
|
6
|
+
export { type Provider, InMemoryProvider } from "./provider.js";
|