Unverified Commit 4855f61c authored by Hong Minhee's avatar Hong Minhee
Browse files

Bypass JSON-LD processor to make toJsonLd() faster

parent b48b42d2
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@
  "yaml.format.enable": false,
  "yaml.hover": true,
  "yaml.schemas": {
    "codegen/schema.yaml": "/vocab/*.yaml",
    "https://json-schema.org/draft/2020-12/schema": "/codegen/schema.yaml"
    "src/codegen/schema.yaml": "/src/vocab/*.yaml",
    "https://json-schema.org/draft/2020-12/schema": "/src/codegen/schema.yaml"
  },
  "yaml.validate": true,
  "[javascript]": {
@@ -67,6 +67,7 @@
    "callouts",
    "cfworker",
    "codegen",
    "compactable",
    "cryptosuite",
    "decorrelated",
    "deflist",
+4 −1
Original line number Diff line number Diff line
@@ -10,12 +10,15 @@ To be released.

 -  Improved the performance of `Object.toJsonLd()` method.

     -  `Object.toJsonLd()` method no longer guarantees that the returned
        JSON-LD object is compacted unless the `format: "compact"` option is
        provided.
     -  Added `format` option to `Object.toJsonLd()` method.
     -  Deprecated `expand` option of `Object.toJsonLd()` method.
        Use `format: "expand"` option instead.
     -  The `context` option of `Object.toJsonLd()` method is now only
        applicable to `format: "compact"`.  Otherwise, it throws
        a `TypeErrror`.
        a `TypeError`.


Version 0.13.0
+4278 −187

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ export async function* generateClasses(
  runtimePath: string,
): AsyncIterable<string> {
  runtimePath = runtimePath.replace(/\/+$/, "");
  yield "// deno-lint-ignore-file ban-unused-ignore\n";
  yield "// deno-lint-ignore-file ban-unused-ignore prefer-const\n";
  yield "// @ts-ignore TS7016\n";
  yield 'import jsonld from "jsonld";\n';
  yield 'import { getLogger } from "@logtape/logtape";\n';
+90 −3
Original line number Diff line number Diff line
@@ -2,10 +2,12 @@ import { generateField, getFieldName } from "./field.ts";
import type { TypeSchema } from "./schema.ts";
import {
  areAllScalarTypes,
  getAllProperties,
  getDecoder,
  getDecoders,
  getEncoders,
  getSubtypes,
  isCompactableType,
} from "./type.ts";

export async function* generateEncoder(
@@ -55,6 +57,92 @@ export async function* generateEncoder(
      ...options,
      contextLoader: options.contextLoader ?? fetchDocumentLoader,
    };
  `;
  if (isCompactableType(typeUri, types)) {
    yield `
    if (
      options.format == null
    `;
    for (const property of type.properties) {
      if (!property.range.every((r) => isCompactableType(r, types))) {
        yield `
        && (
          this.${await getFieldName(property.uri)} == null ||
          this.${await getFieldName(property.uri)}.length < 1
        )
        `;
      }
    }
    yield `
    ) {
    `;
    if (type.extends == null) {
      yield "const result: Record<string, unknown> = {};";
    } else {
      yield `
      const result = await super.toJsonLd({
        ...options,
        format: undefined,
        context: undefined,
      }) as Record<string, unknown>;
      `;
      const selfProperties = type.properties.map((p) => p.uri);
      for (const property of getAllProperties(typeUri, types, true)) {
        if (!selfProperties.includes(property.uri)) continue;
        yield `delete result[${JSON.stringify(property.compactName)}];`;
      }
    }
    yield `
      // deno-lint-ignore no-unused-vars
      let compactItems: unknown[];
    `;
    for (const property of type.properties) {
      yield `
      compactItems = [];
      for (const v of this.${await getFieldName(property.uri)}) {
        const item = (
      `;
      if (!areAllScalarTypes(property.range, types)) {
        yield "v instanceof URL ? v.href : ";
      }
      const encoders = getEncoders(
        property.range,
        types,
        "v",
        "options",
        true,
      );
      for (const code of encoders) yield code;
      yield `
        );
        compactItems.push(item);
      }
      `;
      if (property.functional || property.container !== "list") {
        yield `
        if (compactItems.length > 1) {
          result[${JSON.stringify(property.compactName)}] = compactItems;
        } else if (compactItems.length === 1) {
          result[${JSON.stringify(property.compactName)}] = compactItems[0];
        }
        `;
      } else {
        yield `
        if (compactItems.length > 0) {
          result[${JSON.stringify(property.compactName)}] = compactItems;
        }
        `;
      }
    }
    yield `
      result["type"] = ${JSON.stringify(type.compactName ?? type.uri)};
      if (this.id != null) result["id"] = this.id.href;
      result["@context"] = ${JSON.stringify(type.defaultContext)};
      return result;
    }
    `;
  }
  yield `
    // deno-lint-ignore no-unused-vars prefer-const
    let array: unknown[];
  `;
@@ -110,7 +198,7 @@ export async function* generateEncoder(
  }
  yield `
    values["@type"] = [${JSON.stringify(type.uri)}];
    if (this.id) values["@id"] = this.id.href;
    if (this.id != null) values["@id"] = this.id.href;
    if (options.format === "expand") {
      return await jsonld.expand(
        values,
@@ -287,12 +375,11 @@ export async function* generateDecoder(
    if (!("_fromSubclass" in options) || !options._fromSubclass) {
      try {
        instance.#cachedJsonLd = structuredClone(json);
      } catch (e) {
      } catch {
        getLogger(["fedify", "vocab"]).warn(
          "Failed to cache JSON-LD: {json}",
          { json },
        );
        throw e;
      }
    }
    return instance;
Loading