Unverified Commit 23a96c0c authored by Hong Minhee's avatar Hong Minhee
Browse files

Let `toJsonLd()` return the original JSON-LD

parent 7c08b9fd
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -62,6 +62,10 @@ To be released.
 -  `Context.sendActivity()` and `InboxContext.forwardActivity()` methods now
    reject when they fail to enqueue the task.  [[#192]]

 -  `Object.toJsonLd()` without any `format` option now returns its original
    JSON-LD object even if it not created from `Object.fromJsonLd()` but it is
    returned from another `Object`'s `get*()` method.

 -  Fedify now supports OpenTelemetry for tracing.  [[#170]]

     -  Added `Context.tracerProvider` property.
+6690 −2583

File changed.

Preview size limit exceeded, changes collapsed.

+9 −1
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ async function* generateClass(
    readonly #documentLoader?: DocumentLoader;
    readonly #contextLoader?: DocumentLoader;
    readonly #tracerProvider?: TracerProvider;
    #cachedJsonLd?: unknown;
    readonly id: URL | null;

    protected get _documentLoader(): DocumentLoader | undefined {
@@ -64,10 +65,17 @@ async function* generateClass(
    protected get _tracerProvider(): TracerProvider | undefined {
        return this.#tracerProvider;
    }

    protected get _cachedJsonLd(): unknown | undefined {
      return this.#cachedJsonLd;
    }

    protected set _cachedJsonLd(value: unknown | undefined) {
      this.#cachedJsonLd = value;
    }
    `;
  }
  yield `
    #cachedJsonLd?: unknown;

    /**
     * The type URI of {@link ${type.name}}: \`${typeUri}\`.
+3 −3
Original line number Diff line number Diff line
@@ -33,8 +33,8 @@ export async function* generateEncoder(
    contextLoader?: DocumentLoader,
    context?: string | Record<string, string> | (string | Record<string, string>)[],
  } = {}): Promise<unknown> {
    if (options.format == null && this.#cachedJsonLd != null) {
      return this.#cachedJsonLd;
    if (options.format == null && this._cachedJsonLd != null) {
      return this._cachedJsonLd;
    }
    if (options.format !== "compact" && options.context != null) {
      throw new TypeError(
@@ -451,7 +451,7 @@ export async function* generateDecoder(
  yield `
    if (!("_fromSubclass" in options) || !options._fromSubclass) {
      try {
        instance.#cachedJsonLd = structuredClone(json);
        instance._cachedJsonLd = structuredClone(json);
      } catch {
        getLogger(["fedify", "vocab"]).warn(
          "Failed to cache JSON-LD: {json}",
+77 −12
Original line number Diff line number Diff line
@@ -89,29 +89,55 @@ async function* generateProperty(
          throw error;
        }
        const { document } = fetchResult;
    `;
    for (const range of property.range) {
      if (!(range in types)) continue;
      const rangeType = types[range];
      yield `
        try {
          const obj = await ${rangeType.name}.fromJsonLd(
          const obj = await this.#${property.singularName}_fromJsonLd(
            document,
            { documentLoader, contextLoader, tracerProvider },
            { documentLoader, contextLoader, tracerProvider }
          );
          span.setAttribute("activitypub.object.id", (obj.id ?? url).href);
          span.setAttribute(
            "activitypub.object.type",
            (obj.constructor as typeof ${rangeType.name}).typeId.href
            // @ts-ignore: obj.constructor always has a typeId.
            obj.constructor.typeId.href
          );
          span.end();
          return obj;
        } catch (e) {
          span.setStatus({
            code: SpanStatusCode.ERROR,
            message: String(e),
          });
          throw e;
        } finally {
          span.end();
        }
      });
    }

    async #${property.singularName}_fromJsonLd(
      jsonLd: unknown,
      options: {
        documentLoader?: DocumentLoader,
        contextLoader?: DocumentLoader,
        tracerProvider?: TracerProvider,
      }
    ): Promise<${getTypeNames(property.range, types)}> {
      const documentLoader =
        options.documentLoader ?? this._documentLoader ?? getDocumentLoader();
      const contextLoader =
        options.contextLoader ?? this._contextLoader ?? getDocumentLoader();
      const tracerProvider = options.tracerProvider ??
        this._tracerProvider ?? trace.getTracerProvider();
    `;
    for (const range of property.range) {
      if (!(range in types)) continue;
      const rangeType = types[range];
      yield `
        try {
          return await ${rangeType.name}.fromJsonLd(
            jsonLd,
            { documentLoader, contextLoader, tracerProvider },
          );
        } catch (e) {
          if (!(e instanceof TypeError)) throw e;
        }
      `;
@@ -119,8 +145,8 @@ async function* generateProperty(
    yield `
      throw new TypeError("Expected an object of any type of: " +
        ${JSON.stringify(property.range)}.join(", "));
      });
    }

    `;
    if (property.functional || property.singularAccessor) {
      yield `
@@ -155,6 +181,25 @@ async function* generateProperty(
          this.${await getFieldName(property.uri)}[0] = fetched;
          return fetched;
        }
      `;
      if (property.compactName != null) {
        yield `
        if (
          this._cachedJsonLd != null &&
          typeof this._cachedJsonLd === "object" &&
          "@context" in this._cachedJsonLd &&
          ${JSON.stringify(property.compactName)} in this._cachedJsonLd
        ) {
          const prop = this._cachedJsonLd[
            ${JSON.stringify(property.compactName)}];
          const obj = Array.isArray(prop) ? prop[0] : prop;
          if (obj != null && typeof obj === "object" && "@context" in obj) {
            return await this.#${property.singularName}_fromJsonLd(obj, options);
          }
        }
        `;
      }
      yield `
        return v;
      }
      `;
@@ -194,6 +239,26 @@ async function* generateProperty(
            yield fetched;
            continue;
          }
      `;
      if (property.compactName != null) {
        yield `
          if (
            this._cachedJsonLd != null &&
            typeof this._cachedJsonLd === "object" &&
            "@context" in this._cachedJsonLd &&
            ${JSON.stringify(property.compactName)} in this._cachedJsonLd
          ) {
            const prop = this._cachedJsonLd[
              ${JSON.stringify(property.compactName)}];
            const obj = Array.isArray(prop) ? prop[i] : prop;
            if (obj != null && typeof obj === "object" && "@context" in obj) {
              yield await this.#${property.singularName}_fromJsonLd(obj, options);
              continue;
            }
          }
        `;
      }
      yield `
          yield v;
        }
      }
Loading