diff --git a/deno.json b/deno.json index 223b95e..edae569 100644 --- a/deno.json +++ b/deno.json @@ -15,7 +15,7 @@ "build:npm": "deno run -A ./scripts/build_npm.ts" }, "publish": { - "include": ["LICENSE", "README.md", "crypto", "identity"], + "include": ["LICENSE", "README.md", "crypto", "identity", "richText"], "exclude": ["**/*.test.ts"] }, "test": { diff --git a/richText/mod.ts b/richText/mod.ts new file mode 100644 index 0000000..6c9f234 --- /dev/null +++ b/richText/mod.ts @@ -0,0 +1,33 @@ +/** + * `richText` defines the structure of rich text used through out Blah. + * + * Note that this module only defines a single block of rich text. That is, we only deal with "inline" elements. + * + * @module + */ + +import type z from "zod"; + +import { + type BlahRichTextSpan, + type BlahRichTextSpanAttributes, + blahRichTextSpanAttributesSchema as internalBlahRichTextSpanAttributesSchema, + blahRichTextSpanSchema as internalBlahRichTextSpanSchema, +} from "./span.ts"; +const blahRichTextSpanAttributesSchema: z.ZodType = + internalBlahRichTextSpanAttributesSchema; +const blahRichTextSpanSchema: z.ZodType = + internalBlahRichTextSpanSchema; +export { + type BlahRichTextSpan, + type BlahRichTextSpanAttributes, + blahRichTextSpanAttributesSchema, + blahRichTextSpanSchema, +}; + +import { + type BlahRichText, + blahRichTextSchema as internalBlahRichTextSchema, +} from "./richText.ts"; +const blahRichTextSchema: z.ZodType = internalBlahRichTextSchema; +export { type BlahRichText, blahRichTextSchema }; diff --git a/richText/richText.test.ts b/richText/richText.test.ts new file mode 100644 index 0000000..057be2d --- /dev/null +++ b/richText/richText.test.ts @@ -0,0 +1,8 @@ +import { assertTypeMatchesZodSchema } from "../test/utils.ts"; +import { type BlahRichText, blahRichTextSchema } from "./richText.ts"; + +Deno.test("type BlahRichText is accurate", () => { + assertTypeMatchesZodSchema( + blahRichTextSchema, + ); +}); diff --git a/richText/richText.ts b/richText/richText.ts new file mode 100644 index 0000000..516ffd3 --- /dev/null +++ b/richText/richText.ts @@ -0,0 +1,5 @@ +import { z } from "zod"; +import { type BlahRichTextSpan, blahRichTextSpanSchema } from "./span.ts"; + +export const blahRichTextSchema = z.array(blahRichTextSpanSchema); +export type BlahRichText = Array; diff --git a/richText/span.test.ts b/richText/span.test.ts new file mode 100644 index 0000000..63cb390 --- /dev/null +++ b/richText/span.test.ts @@ -0,0 +1,8 @@ +import { assertTypeMatchesZodSchema } from "../test/utils.ts"; +import { type BlahRichTextSpan, blahRichTextSpanSchema } from "./span.ts"; + +Deno.test("type BlahRichTextSpan is accurate", () => { + assertTypeMatchesZodSchema( + blahRichTextSpanSchema, + ); +}); diff --git a/richText/span.ts b/richText/span.ts new file mode 100644 index 0000000..8090984 --- /dev/null +++ b/richText/span.ts @@ -0,0 +1,27 @@ +import { z } from "zod"; + +export const blahRichTextSpanAttributesSchema = z.object({ + b: z.boolean().default(false), + i: z.boolean().default(false), + u: z.boolean().default(false), + s: z.boolean().default(false), + m: z.boolean().default(false), + tag: z.boolean().default(false), + link: z.string().url().optional(), +}); + +export type BlahRichTextSpanAttributes = { + b?: boolean; + i?: boolean; + u?: boolean; + s?: boolean; + m?: boolean; + tag?: boolean; + link?: string | undefined; +}; + +export const blahRichTextSpanSchema = z.union([ + z.string(), + z.tuple([z.string(), blahRichTextSpanAttributesSchema]), +]); +export type BlahRichTextSpan = string | [string, BlahRichTextSpanAttributes]; diff --git a/richText/toPlainText.test.ts b/richText/toPlainText.test.ts new file mode 100644 index 0000000..73045b3 --- /dev/null +++ b/richText/toPlainText.test.ts @@ -0,0 +1,8 @@ +import { expect } from "@std/expect"; +import type { BlahRichText } from "./mod.ts"; +import { toPlainText } from "./toPlainText.ts"; + +Deno.test("toPlainText", () => { + const richText: BlahRichText = ["hello ", ["world", { b: true }]]; + expect(toPlainText(richText)).toBe("hello world"); +}); diff --git a/richText/toPlainText.ts b/richText/toPlainText.ts new file mode 100644 index 0000000..e197d02 --- /dev/null +++ b/richText/toPlainText.ts @@ -0,0 +1,6 @@ +import type { BlahRichText } from "./richText.ts"; + +export function toPlainText(richText: BlahRichText): string { + return richText.map((span) => (typeof span === "string" ? span : span[0])) + .join(""); +} diff --git a/scripts/build_npm.ts b/scripts/build_npm.ts index 69c7c2f..81a8541 100644 --- a/scripts/build_npm.ts +++ b/scripts/build_npm.ts @@ -7,6 +7,7 @@ await build({ entryPoints: [ { name: "./crypto", path: "crypto/mod.ts" }, { name: "./identity", path: "identity/mod.ts" }, + { name: "./richText", path: "richText/mod.ts" }, ], outDir: "./npm", importMap: "deno.json",