From ebf8eeec59d2932b3356f4a2acb05d856701bef4 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Wed, 3 Jul 2024 17:53:55 +1000 Subject: [PATCH] BREAKING(front-matter): remove `createExtractor()` (#5266) * BREAKING(front-matter): remove `createExtractor()` * work --- front_matter/_create_extractor.ts | 83 +++++++++ ...ctor_test.ts => _create_extractor_test.ts} | 2 +- front_matter/any.ts | 9 +- front_matter/create_extractor.ts | 174 ------------------ front_matter/deno.json | 4 +- front_matter/json.ts | 29 +-- front_matter/mod.ts | 2 +- front_matter/toml.ts | 9 +- front_matter/types.ts | 16 ++ front_matter/yaml.ts | 9 +- 10 files changed, 119 insertions(+), 218 deletions(-) create mode 100644 front_matter/_create_extractor.ts rename front_matter/{create_extractor_test.ts => _create_extractor_test.ts} (97%) delete mode 100644 front_matter/create_extractor.ts create mode 100644 front_matter/types.ts diff --git a/front_matter/_create_extractor.ts b/front_matter/_create_extractor.ts new file mode 100644 index 000000000..4b6dcaf15 --- /dev/null +++ b/front_matter/_create_extractor.ts @@ -0,0 +1,83 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +import { EXTRACT_REGEXP_MAP, RECOGNIZE_REGEXP_MAP } from "./_formats.ts"; +import type { Format } from "./_types.ts"; +import type { Extract, Extractor } from "./types.ts"; + +/** Parser function type used alongside {@linkcode createExtractor}. */ +export type Parser = >(str: string) => T; + +function _extract( + str: string, + rx: RegExp, + parse: Parser, +): Extract { + const match = rx.exec(str); + if (!match || match.index !== 0) { + throw new TypeError("Unexpected end of input"); + } + const frontMatter = match.at(-1)?.replace(/^\s+|\s+$/g, "") || ""; + const attrs = parse(frontMatter) as T; + const body = str.replace(match[0], ""); + return { frontMatter, body, attrs }; +} + +/** + * Recognizes the format of the front matter in a string. + * Supports {@link https://yaml.org | YAML}, {@link https://toml.io | TOML} and + * {@link https://www.json.org/ | JSON}. + * + * @param str String to recognize. + * @param formats A list of formats to recognize. Defaults to all supported formats. + */ +function recognize(str: string, formats?: Format[]): Format { + if (!formats) { + formats = Object.keys(RECOGNIZE_REGEXP_MAP) as Format[]; + } + + const [firstLine] = str.split(/(\r?\n)/) as [string]; + + for (const format of formats) { + if (format === "unknown") { + continue; + } + + if (RECOGNIZE_REGEXP_MAP[format].test(firstLine)) { + return format; + } + } + + return "unknown"; +} + +/** + * Factory that creates a function that extracts front matter from a string with + * the given parsers. Supports {@link https://yaml.org | YAML}, + * {@link https://toml.io | TOML} and {@link https://www.json.org/ | JSON}. + * + * For simple use cases where you know which format to parse in advance, use the + * pre-built extractors: + * + * - {@linkcode https://jsr.io/@std/front-matter/doc/yaml/~/extract | extractYaml} + * - {@linkcode https://jsr.io/@std/front-matter/doc/toml/~/extract | extractToml} + * - {@linkcode https://jsr.io/@std/front-matter/doc/json/~/extract | extractJson} + * + * @param formats A descriptor containing Format-parser pairs to use for each format. + * @returns A function that extracts front matter from a string with the given parsers. + */ +export function createExtractor( + formats: Partial>, +): Extractor { + const formatKeys = Object.keys(formats) as Format[]; + + return function extract(str: string): Extract { + const format = recognize(str, formatKeys); + const parser = formats[format]; + + if (format === "unknown" || !parser) { + throw new TypeError(`Unsupported front matter format`); + } + + return _extract(str, EXTRACT_REGEXP_MAP[format], parser); + }; +} diff --git a/front_matter/create_extractor_test.ts b/front_matter/_create_extractor_test.ts similarity index 97% rename from front_matter/create_extractor_test.ts rename to front_matter/_create_extractor_test.ts index 1a3b0df0c..ce19f81ee 100644 --- a/front_matter/create_extractor_test.ts +++ b/front_matter/_create_extractor_test.ts @@ -11,7 +11,7 @@ import { runExtractYamlTests1, runExtractYamlTests2, } from "./_test_utils.ts"; -import { createExtractor, type Parser } from "./create_extractor.ts"; +import { createExtractor, type Parser } from "./_create_extractor.ts"; const extractYaml = createExtractor({ "yaml": parseYaml as Parser }); const extractToml = createExtractor({ "toml": parseToml as Parser }); diff --git a/front_matter/any.ts b/front_matter/any.ts index e169f5d74..957eae3dd 100644 --- a/front_matter/any.ts +++ b/front_matter/any.ts @@ -1,12 +1,11 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { - createExtractor, - type Extractor, - type Parser, -} from "./create_extractor.ts"; +import { createExtractor, type Parser } from "./_create_extractor.ts"; import { parse as parseYaml } from "@std/yaml/parse"; import { parse as parseToml } from "@std/toml/parse"; +import type { Extractor } from "./types.ts"; + +export type { Extractor }; /** * Extracts and parses {@link https://yaml.org | YAML}, {@link https://toml.io | diff --git a/front_matter/create_extractor.ts b/front_matter/create_extractor.ts deleted file mode 100644 index e16e527ed..000000000 --- a/front_matter/create_extractor.ts +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. - -import { EXTRACT_REGEXP_MAP, RECOGNIZE_REGEXP_MAP } from "./_formats.ts"; -import type { Format } from "./_types.ts"; - -/** Return type for {@linkcode Extractor}. */ -export type Extract = { - frontMatter: string; - body: string; - attrs: T; -}; - -/** Function return type for {@linkcode createExtractor}. */ -export type Extractor = >( - str: string, -) => Extract; - -/** Parser function type used alongside {@linkcode createExtractor}. */ -export type Parser = >(str: string) => T; - -function _extract( - str: string, - rx: RegExp, - parse: Parser, -): Extract { - const match = rx.exec(str); - if (!match || match.index !== 0) { - throw new TypeError("Unexpected end of input"); - } - const frontMatter = match.at(-1)?.replace(/^\s+|\s+$/g, "") || ""; - const attrs = parse(frontMatter) as T; - const body = str.replace(match[0], ""); - return { frontMatter, body, attrs }; -} - -/** - * Recognizes the format of the front matter in a string. - * Supports {@link https://yaml.org | YAML}, {@link https://toml.io | TOML} and - * {@link https://www.json.org/ | JSON}. - * - * @param str String to recognize. - * @param formats A list of formats to recognize. Defaults to all supported formats. - */ -function recognize(str: string, formats?: Format[]): Format { - if (!formats) { - formats = Object.keys(RECOGNIZE_REGEXP_MAP) as Format[]; - } - - const [firstLine] = str.split(/(\r?\n)/) as [string]; - - for (const format of formats) { - if (format === "unknown") { - continue; - } - - if (RECOGNIZE_REGEXP_MAP[format].test(firstLine)) { - return format; - } - } - - return "unknown"; -} - -/** - * Factory that creates a function that extracts front matter from a string with - * the given parsers. Supports {@link https://yaml.org | YAML}, - * {@link https://toml.io | TOML} and {@link https://www.json.org/ | JSON}. - * - * For simple use cases where you know which format to parse in advance, use the - * pre-built extractors: - * - * - {@linkcode https://jsr.io/@std/front-matter/doc/yaml/~/extract | extractYaml} - * - {@linkcode https://jsr.io/@std/front-matter/doc/toml/~/extract | extractToml} - * - {@linkcode https://jsr.io/@std/front-matter/doc/json/~/extract | extractJson} - * - * @param formats A descriptor containing Format-parser pairs to use for each format. - * @returns A function that extracts front matter from a string with the given parsers. - * - * @example Extract YAML front matter - * ```ts - * import { createExtractor, Parser } from "@std/front-matter"; - * import { assertEquals } from "@std/assert"; - * import { parse as parseYaml } from "@std/yaml/parse"; - * - * const extractYaml = createExtractor({ yaml: parseYaml as Parser }); - * const { attrs, body, frontMatter } = extractYaml<{ title: string }>( - * `--- - * title: Three dashes marks the spot - * --- - * ferret`); - * assertEquals(attrs.title, "Three dashes marks the spot"); - * assertEquals(body, "ferret"); - * assertEquals(frontMatter, "title: Three dashes marks the spot"); - * ``` - * - * @example Extract TOML front matter - * ```ts - * import { createExtractor, Parser } from "@std/front-matter"; - * import { assertEquals } from "@std/assert"; - * import { parse as parseToml } from "@std/toml/parse"; - * - * const extractToml = createExtractor({ toml: parseToml as Parser }); - * const { attrs, body, frontMatter } = extractToml<{ title: string }>( - * `---toml - * title = 'Three dashes followed by format marks the spot' - * --- - * `); - * assertEquals(attrs.title, "Three dashes followed by format marks the spot"); - * assertEquals(body, ""); - * assertEquals(frontMatter, "title = 'Three dashes followed by format marks the spot'"); - * ``` - * - * @example Extract JSON front matter - * ```ts - * import { createExtractor, Parser } from "@std/front-matter"; - * import { assertEquals } from "@std/assert"; - * - * const extractJson = createExtractor({ json: JSON.parse as Parser }); - * const { attrs, body, frontMatter } = extractJson<{ title: string }>( - * `---json - * {"title": "Three dashes followed by format marks the spot"} - * --- - * goat`); - * assertEquals(attrs.title, "Three dashes followed by format marks the spot"); - * assertEquals(body, "goat"); - * assertEquals(frontMatter, `{"title": "Three dashes followed by format marks the spot"}`); - * ``` - * - * @example Extract YAML or JSON front matter - * ```ts - * import { createExtractor, Parser } from "@std/front-matter"; - * import { assertEquals } from "@std/assert"; - * import { parse as parseYaml } from "@std/yaml/parse"; - * - * const extractYamlOrJson = createExtractor({ - * yaml: parseYaml as Parser, - * json: JSON.parse as Parser, - * }); - * - * let { attrs, body, frontMatter } = extractYamlOrJson<{ title: string }>( - * `--- - * title: Three dashes marks the spot - * --- - * ferret`); - * assertEquals(attrs.title, "Three dashes marks the spot"); - * assertEquals(body, "ferret"); - * assertEquals(frontMatter, "title: Three dashes marks the spot"); - * - * ({ attrs, body, frontMatter } = extractYamlOrJson<{ title: string }>( - * `---json - * {"title": "Three dashes followed by format marks the spot"} - * --- - * goat`)); - * assertEquals(attrs.title, "Three dashes followed by format marks the spot"); - * assertEquals(body, "goat"); - * assertEquals(frontMatter, `{"title": "Three dashes followed by format marks the spot"}`); - * ``` - */ -export function createExtractor( - formats: Partial>, -): Extractor { - const formatKeys = Object.keys(formats) as Format[]; - - return function extract(str: string): Extract { - const format = recognize(str, formatKeys); - const parser = formats[format]; - - if (format === "unknown" || !parser) { - throw new TypeError(`Unsupported front matter format`); - } - - return _extract(str, EXTRACT_REGEXP_MAP[format], parser); - }; -} diff --git a/front_matter/deno.json b/front_matter/deno.json index 585f5eaf2..b32bbd414 100644 --- a/front_matter/deno.json +++ b/front_matter/deno.json @@ -4,10 +4,10 @@ "exports": { ".": "./mod.ts", "./any": "./any.ts", - "./create-extractor": "./create_extractor.ts", "./json": "./json.ts", "./test": "./test.ts", "./toml": "./toml.ts", - "./yaml": "./yaml.ts" + "./yaml": "./yaml.ts", + "./types": "./types.ts" } } diff --git a/front_matter/json.ts b/front_matter/json.ts index 56f20cdaa..71b38cf78 100644 --- a/front_matter/json.ts +++ b/front_matter/json.ts @@ -1,34 +1,13 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { - createExtractor, - type Extractor, - type Parser, -} from "./create_extractor.ts"; +import { createExtractor, type Parser } from "./_create_extractor.ts"; +import type { Extractor } from "./types.ts"; + +export type { Extractor }; /** * Extracts and parses {@link https://www.json.org/ | JSON } from the metadata * of front matter content. - * - * @example Extract JSON front matter - * ```ts - * import { extract } from "@std/front-matter/json"; - * import { assertEquals } from "@std/assert"; - * - * const output = `---json - * { - * "title": "Three dashes marks the spot" - * } - * --- - * Hello, world!`; - * const result = extract(output); - * - * assertEquals(result, { - * frontMatter: '{\n "title": "Three dashes marks the spot"\n}', - * body: "Hello, world!", - * attrs: { title: "Three dashes marks the spot" }, - * }); - * ``` */ export const extract: Extractor = createExtractor({ json: JSON.parse as Parser, diff --git a/front_matter/mod.ts b/front_matter/mod.ts index 227392f73..890e65af1 100644 --- a/front_matter/mod.ts +++ b/front_matter/mod.ts @@ -124,7 +124,7 @@ import { extract as extractJson } from "./json.ts"; import { extract as extractToml } from "./toml.ts"; import { extract as extractYaml } from "./yaml.ts"; -export * from "./create_extractor.ts"; export * from "./test.ts"; +export * from "./types.ts"; export { extractJson, extractToml, extractYaml }; diff --git a/front_matter/toml.ts b/front_matter/toml.ts index 98718e595..d0026fc2f 100644 --- a/front_matter/toml.ts +++ b/front_matter/toml.ts @@ -1,11 +1,10 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { - createExtractor, - type Extractor, - type Parser, -} from "./create_extractor.ts"; +import { createExtractor, type Parser } from "./_create_extractor.ts"; import { parse } from "@std/toml/parse"; +import type { Extractor } from "./types.ts"; + +export type { Extractor }; /** * Extracts and parses {@link https://toml.io | TOML} from the metadata of diff --git a/front_matter/types.ts b/front_matter/types.ts new file mode 100644 index 000000000..3fd8ea5e3 --- /dev/null +++ b/front_matter/types.ts @@ -0,0 +1,16 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +/** Return type for functions of the {@linkcode Extractor} type. */ +export type Extract = { + frontMatter: string; + body: string; + attrs: T; +}; + +/** + * Type for function that accepts an input string and returns + * {@linkcode Extract}. + */ +export type Extractor = >( + str: string, +) => Extract; diff --git a/front_matter/yaml.ts b/front_matter/yaml.ts index cb4a0a9d1..b1ad4442e 100644 --- a/front_matter/yaml.ts +++ b/front_matter/yaml.ts @@ -1,11 +1,10 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. -import { - createExtractor, - type Extractor, - type Parser, -} from "./create_extractor.ts"; +import { createExtractor, type Parser } from "./_create_extractor.ts"; import { parse } from "@std/yaml/parse"; +import type { Extractor } from "./types.ts"; + +export type { Extractor }; /** * Extracts and parses {@link https://yaml.org | YAML} from the metadata of