Page MenuHomeSealhub

No OneTemporary

diff --git a/src/components/markdown.test.ts b/src/components/markdown.test.ts
index 8253522..145e3f4 100644
--- a/src/components/markdown.test.ts
+++ b/src/components/markdown.test.ts
@@ -1,32 +1,36 @@
import { Registry } from "../registry.js";
import { Markdown } from "./markdown.js";
-import { JDDocument, makeSimpleJDDContext, render } from "../index.js";
+import {
+ documentContainerFromParsed,
+ makeSimpleJDDContext,
+ render,
+} from "../index.js";
import assert from "assert";
import { streamToString } from "tempstream";
import { FileManager } from "@sealcode/file-manager";
describe("markdown component", () => {
it("renders as a part of a JDD", async () => {
- const document = [
+ const document = documentContainerFromParsed([
{ component_name: "markdown", args: { markdown: `# Hello World` } },
{
component_name: "markdown",
args: { markdown: `Multiple components ftw` },
},
- ] as JDDocument;
+ ]);
const registry = new Registry();
registry.add("markdown", Markdown);
const result = await streamToString(
render(
registry,
document,
makeSimpleJDDContext(new FileManager("/tmp", "/uploaded_files"))
)
);
assert.strictEqual(
result,
`<h1>Hello World</h1>\n\n<p>Multiple components ftw</p>\n`
);
});
});
diff --git a/src/document.test.ts b/src/document.test.ts
new file mode 100644
index 0000000..62c3917
--- /dev/null
+++ b/src/document.test.ts
@@ -0,0 +1,81 @@
+import { FileManager } from "@sealcode/file-manager";
+import {
+ Component,
+ ComponentArgument,
+ JDDContext,
+ documentContainerFromParsed,
+ documentToStorage,
+ makeSimpleJDDContext,
+} from "./index.js";
+import { Registry } from "./registry.js";
+import assert from "assert";
+
+describe("document", () => {
+ it("converts from parsed to storage", async () => {
+ const registry = new Registry();
+
+ const args = {
+ test: new (class extends ComponentArgument<number, string, string> {
+ countWords() {
+ return 0;
+ }
+ getEmptyValue() {
+ return 0;
+ }
+ getSubArgument(): never {
+ throw new Error("no arguments");
+ }
+ getTypeName() {
+ return "test";
+ }
+
+ async storageToParsed(
+ _context: JDDContext,
+ value: string
+ ): Promise<number> {
+ return parseInt(value);
+ }
+
+ async parsedToStorage(
+ _context: JDDContext,
+ value: number
+ ): Promise<string> {
+ return value.toString();
+ }
+
+ async receivedToParsed(
+ _context: JDDContext,
+ value: string
+ ): Promise<number> {
+ return parseInt(value);
+ }
+ })(),
+ };
+
+ registry.add(
+ "test",
+ class extends Component<typeof args> {
+ getArguments() {
+ return args;
+ }
+ toHTML() {
+ return "";
+ }
+ }
+ );
+
+ const document = documentContainerFromParsed([
+ { component_name: "test", args: { test: 1 } },
+ { component_name: "test", args: { test: 2 } },
+ ]);
+ const to_store = await documentToStorage(
+ registry,
+ makeSimpleJDDContext(new FileManager("/tmp", "/uploaded_files")),
+ document
+ );
+ assert.deepStrictEqual(to_store.value, [
+ { component_name: "test", args: { test: "1" } },
+ { component_name: "test", args: { test: "2" } },
+ ]);
+ });
+});
diff --git a/src/document.ts b/src/document.ts
new file mode 100644
index 0000000..8570577
--- /dev/null
+++ b/src/document.ts
@@ -0,0 +1,60 @@
+import { JDDContext } from "./jdd-context.js";
+import { Registry } from "./registry.js";
+
+export const JDDStatus = Symbol();
+
+export type RawJDDocument = Array<{
+ component_name: string;
+ args: Record<string, unknown>;
+}>;
+
+export type JDDocumentContainer<Status extends "parsed" | "storage"> = {
+ value: RawJDDocument;
+ [JDDStatus]: Status;
+};
+
+export async function documentToStorage(
+ registry: Registry,
+ jdd_context: JDDContext,
+ document_container: JDDocumentContainer<"parsed">
+): Promise<JDDocumentContainer<"storage">> {
+ const result = await Promise.all(
+ document_container.value.map(async ({ component_name, args }) => {
+ const component = registry.get(component_name);
+ if (!component) {
+ throw new Error(`Unknown component: ${component_name}`);
+ }
+ return {
+ component_name,
+ args: await component.convertParsedToStorage(jdd_context, args),
+ };
+ })
+ );
+ return { value: result, [JDDStatus]: "storage" };
+}
+
+export async function documentToParsed(
+ registry: Registry,
+ jdd_context: JDDContext,
+ document_container: JDDocumentContainer<"storage">
+): Promise<JDDocumentContainer<"parsed">> {
+ const result = await Promise.all(
+ document_container.value.map(async ({ component_name, args }) => {
+ const component = registry.get(component_name);
+ if (!component) {
+ throw new Error(`Unknown component: ${component_name}`);
+ }
+ return {
+ component_name,
+ args: await component.convertStorageToParsed(jdd_context, args),
+ };
+ })
+ );
+ return { value: result, [JDDStatus]: "parsed" };
+}
+
+export function documentContainerFromParsed(
+ document: RawJDDocument
+): JDDocumentContainer<"parsed"> {
+ return { value: [...document], [JDDStatus]: "parsed" };
+}
diff --git a/src/index.ts b/src/index.ts
index bad000b..711ce3e 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,132 +1,132 @@
import { tempstream } from "tempstream";
import { JDDContext } from "./jdd-context.js";
import { Registry } from "./registry.js";
import { EarlyAsset } from "./component.js";
import { hasField } from "@sealcode/ts-predicates";
+import { JDDocumentContainer } from "./document.js";
export * from "./component.js";
export * from "./component-arguments/component-argument.js";
export * as ComponentArguments from "./component-arguments/component-arguments.js";
export * from "./component-arguments/component-arguments.js"; // exporting this also as root elements to make it easier to auto-import those
export * from "./jdd-context.js";
export * from "./registry.js";
export { insert_nbsp } from "./utils/insert_nbsp.js";
+export * from "./document.js";
-export type JDDocument = Array<{
- component_name: string;
- args: Record<string, unknown>;
-}>;
-
-export function countWords(registry: Registry, document: JDDocument): number {
- return document.reduce((acc, { component_name, args }) => {
+export function countWords(
+ registry: Registry,
+ document_container: JDDocumentContainer<"parsed">
+): number {
+ return document_container.value.reduce((acc, { component_name, args }) => {
const component = registry.get(component_name);
if (!component) {
console.warn(
"Component not found in the registry: " + component_name
);
return acc + 0;
}
return acc + component.countWords(args);
}, 0);
}
export async function renderEarlyAssets(
registry: Registry,
- document: JDDocument,
+ document_container: JDDocumentContainer<"parsed">,
context: JDDContext
) {
const early_assets = (
await Promise.all(
- document.map(async ({ component_name, args }) => {
+ document_container.value.map(async ({ component_name, args }) => {
const component = registry.get(component_name);
if (!component) {
console.warn(
"Component not found in the registry: " + component_name
);
return [];
}
for (const arg_name in component?.getArguments()) {
if (!Object.prototype.hasOwnProperty.call(args, arg_name)) {
args[arg_name] = component
?.getArguments()
[arg_name]?.getEmptyValue();
}
}
return await component.getEarlyAssets(args, context);
})
)
).flat();
const deduplicated_assets: Record<string, EarlyAsset> = {};
for (const asset of early_assets) {
deduplicated_assets[asset.identity] = asset;
}
return Object.values(deduplicated_assets)
.map((asset) => {
if (asset.type == "script") {
if (hasField("url", asset)) {
return /* HTML */ `<script
async
src="${asset.url}"
onLoad="document.dispatchEvent(new Event('loaded-${asset.identity}'))"
${(asset.integrity &&
`integrity="${asset.integrity}" crossorigin="anonymous"`) ||
""}
></script>`;
} else {
return /* HTML */ `<script><${asset.content}/script>`;
}
} else if (asset.type == "style") {
if (hasField("url", asset)) {
const integrity =
(asset.integrity &&
`integrity="${asset.integrity}" crossorigin="anonymous"`) ||
"";
// see https://web.dev/articles/defer-non-critical-css
return /* HTML */ `<link
rel="preload"
href="${asset.url}"
as="style"
onload="this.onload=null;this.rel='stylesheet'"
${integrity}
/>
<noscript
><link
rel="stylesheet"
href="${asset.url}"
${integrity}
/></noscript>`;
} else {
return /* HTML */ `<style>
${asset.content}
</style>`;
}
}
})
.join(" ");
}
export function render(
registry: Registry,
- document: JDDocument,
+ document: JDDocumentContainer<"parsed">,
context: JDDContext
) {
- return tempstream`${document.map(({ component_name, args }) => {
+ return tempstream`${document.value.map(({ component_name, args }) => {
const component = registry.get(component_name);
if (!component) {
console.warn(
"Component not found in the registry: " + component_name
);
return "";
}
for (const arg_name in component?.getArguments()) {
if (!Object.prototype.hasOwnProperty.call(args, arg_name)) {
args[arg_name] = component
?.getArguments()
[arg_name]?.getEmptyValue();
}
}
return component.toHTML(args, context);
})}`;
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 23, 06:21 (19 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
556224
Default Alt Text
(9 KB)

Event Timeline