diff --git a/_tasks/dnt.ts b/_tasks/dnt.ts index 64f1e38ae..ea26a48b5 100755 --- a/_tasks/dnt.ts +++ b/_tasks/dnt.ts @@ -98,9 +98,9 @@ await Promise.all([ name: "wat-the-crypto", version: "0.0.3", }, - "https://deno.land/x/scale@v0.12.2/mod.ts#=": { + "https://deno.land/x/scale@v0.13.0/mod.ts#=": { name: "scale-codec", - version: "0.12.2", + version: "0.13.0", }, "https://deno.land/x/smoldot2@light-js-deno-v1.0.6/index-deno.js": { name: "smoldot", diff --git a/codegen/CodecCodegen.ts b/codegen/CodecCodegen.ts index 612a466d0..d7309b072 100644 --- a/codegen/CodecCodegen.ts +++ b/codegen/CodecCodegen.ts @@ -40,9 +40,7 @@ export class CodecCodegen { if (existing === null) { this.codecIds.set(value, this.nextCodecId++) } else if (existing === undefined) { - const meta = value._metadata.find((x): x is typeof x & { type: "atomic" | "factory" } => - x.type === "atomic" || x.type === "factory" - ) + const meta = value._metadata[0] if (!meta || meta.type === "atomic") return if (meta.factory === $.deferred) { this.codecIds.set(value, this.nextCodecId++) @@ -86,9 +84,7 @@ export class CodecCodegen { } if (value === null) return "null" if (value instanceof $.Codec) { - const meta = value._metadata.find((x): x is typeof x & { type: "atomic" | "factory" } => - x.type === "atomic" || x.type === "factory" - ) + const meta = value._metadata[0] if (!meta) throw new Error("Cannot serialize metadata-less codec") if (meta.type === "atomic") return `C.${meta.name}` const id = this.codecIds.get(value) diff --git a/codegen/TypeCodegen.ts b/codegen/TypeCodegen.ts index 1c4b32541..3a0c384d2 100644 --- a/codegen/TypeCodegen.ts +++ b/codegen/TypeCodegen.ts @@ -27,6 +27,8 @@ export class TypeCodegen { ) isTuple = new $.CodecVisitor().add($.tuple, () => true).fallback(() => false) + isField = new $.CodecVisitor() + .add($.field, () => true).fallback(() => false) nativeVisitor = new $.CodecVisitor() .add($.int, (_codec, _signed, size) => size > 32 ? "bigint" : "number") @@ -93,10 +95,28 @@ export class TypeCodegen { (_codec, variants) => Object.values(variants).map((v) => this.codecCodegen.print(v)).join(" | "), ) + .add( + $.documented, + (_codec, docs, inner) => { + if (this.isField.visit(inner)) { + return `{\n${formatDocComment(docs)}\n${this.native(inner).slice(1)}` + } + return `${formatDocComment(docs)}\n` + this.native(inner) + }, + ) .add($.never, () => "never") .add($null, () => "null") declVisitor = new $.CodecVisitor<(name: string, isTypes: boolean) => string>() + .generic((visitor) => + visitor.add( + $.documented, + (_codec, docs, inner) => (name, isTypes) => + (isTypes + ? formatDocComment(docs) + "\n" + : "") + visitor.visit(inner)(name, isTypes).trim(), + ) + ) .add($.literalUnion, (_codec, _variants) => (name, isTypes) => { const variants = Object.values(_variants) as string[] return isTypes @@ -243,7 +263,8 @@ export ${isTypes ? `namespace ${name}` : `const ${name} =`} { const trailing = isTypes ? `: C.$.Codec<${name}>` : `= ${this.codecCodegen.print(codec)}` return ` export const $${name.replace(/^./, (x) => x.toLowerCase())}${trailing} - ${this.declVisitor.visit(codec)(name, isTypes)} + + ${this.declVisitor.visit(codec)(name, isTypes).trim()} ` }).join("\n") files.set( @@ -270,3 +291,9 @@ export ${isTypes ? `namespace ${name}` : `const ${name} =`} { ) } } + +function formatDocComment(docs: string) { + if (!docs) return "" + if (!docs.includes("\n")) return `/** ${docs} */` + return `/**\n${docs.replace(/^/gm, " * ")}\n*/` +} diff --git a/deps/scale.ts b/deps/scale.ts index 326cae1df..ebfaaf41a 100644 --- a/deps/scale.ts +++ b/deps/scale.ts @@ -1 +1 @@ -export * from "https://deno.land/x/scale@v0.12.2/mod.ts#=" +export * from "https://deno.land/x/scale@v0.13.0/mod.ts#=" diff --git a/scale_info/transformTys.ts b/scale_info/transformTys.ts index 3813b3a13..b5e382327 100644 --- a/scale_info/transformTys.ts +++ b/scale_info/transformTys.ts @@ -91,7 +91,9 @@ export function transformTys(tys: Ty[]): ScaleInfo { } } else { return $.object( - ...ty.fields.map((x) => maybeOptionalField(normalizeIdent(x.name!), visit(x.ty))), + ...ty.fields.map((x) => + withDocs(x.docs, maybeOptionalField(normalizeIdent(x.name!), visit(x.ty))) + ), ) } } else if (ty.type === "Tuple") { @@ -128,7 +130,10 @@ export function transformTys(tys: Ty[]): ScaleInfo { } else { // Object variant const memberFields = fields.map((field) => { - return maybeOptionalField(normalizeIdent(field.name!), visit(field.ty)) + return withDocs( + field.docs, + maybeOptionalField(normalizeIdent(field.name!), visit(field.ty)), + ) }) member = $.variant(type, ...memberFields) } @@ -165,7 +170,7 @@ export function transformTys(tys: Ty[]): ScaleInfo { function withDocs(_docs: string[], codec: Codec): Codec { const docs = normalizeDocs(_docs) - if (docs) return $.withMetadata($.docs(docs), codec) + if (docs) return $.documented(docs, codec) return codec } diff --git a/server/factories.ts b/server/factories.ts index 0bfa1e28b..d0fff8509 100644 --- a/server/factories.ts +++ b/server/factories.ts @@ -1,3 +1,4 @@ +import { escapeHtml } from "../deps/escape.ts" import { Status } from "../deps/std/http.ts" import { CacheBase } from "../util/cache/base.ts" @@ -57,7 +58,7 @@ export function acceptsHtml(request: Request): boolean { export async function renderCode(code: string) { return ` -
${code}
+
${escapeHtml(code)}
` } diff --git a/util/normalize.ts b/util/normalize.ts index d072e0b30..074642889 100644 --- a/util/normalize.ts +++ b/util/normalize.ts @@ -6,7 +6,17 @@ export function normalizeIdent(ident: string) { } export function normalizeDocs(docs: string[] | undefined): string { - return docs?.join("\n") ?? "" + let str = docs?.join("\n") ?? "" + str = str + .replace(/[^\S\n]+$/gm, "") // strip trailing whitespace + .replace(/^\n+|\n+$/g, "") // strip leading and trailing newlines + const match = /^([^\S\n]+).*(?:\n\1.*)*$/.exec(str) // find a common indent + if (match) { + const { 1: prefix } = match + str = str.replace(new RegExp(`^${prefix}`, "gm"), "") // strip the common indent + // this `new RegExp` is safe because `prefix` must be whitespace + } + return str } export function normalizePackageName(name: string) {