@markuplint/spec-generator 4.8.0 → 4.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/read-json.js CHANGED
@@ -2,6 +2,14 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { glob } from 'glob';
4
4
  import strip from 'strip-json-comments';
5
+ /**
6
+ * Reads and parses a single JSON file (with support for JSON comments) from an absolute file path.
7
+ *
8
+ * @template T - The expected shape of the parsed JSON data
9
+ * @param filePath - The absolute file path to the JSON file
10
+ * @returns The parsed JSON content
11
+ * @throws If the provided path is not absolute
12
+ */
5
13
  export function readJson(filePath) {
6
14
  if (!path.isAbsolute(filePath)) {
7
15
  throw new Error(`The path must be absolute path: ${filePath}`);
@@ -10,6 +18,16 @@ export function readJson(filePath) {
10
18
  json = strip(json);
11
19
  return JSON.parse(json);
12
20
  }
21
+ /**
22
+ * Reads multiple JSON files matching a glob pattern and optionally transforms each result.
23
+ * All matched files are read and parsed in parallel.
24
+ *
25
+ * @template T - The expected shape of each parsed JSON file
26
+ * @param pattern - An absolute glob pattern to match JSON files
27
+ * @param hook - An optional transformation function called with each file path and its parsed body
28
+ * @returns An array of parsed (and optionally transformed) JSON objects
29
+ * @throws If the provided pattern is not an absolute path
30
+ */
13
31
  export async function readJsons(pattern, hook = (_, body) => body) {
14
32
  if (!path.isAbsolute(pattern)) {
15
33
  throw new Error(`The pattern must be absolute path: ${pattern}`);
package/lib/scraping.d.ts CHANGED
@@ -1,3 +1,18 @@
1
1
  import type { ExtendedElementSpec } from '@markuplint/ml-spec';
2
+ /**
3
+ * Generates minimal element specification stubs for obsolete/deprecated elements
4
+ * that do not already exist in the provided specs array.
5
+ *
6
+ * @param obsoleteList - A list of element names considered obsolete or deprecated
7
+ * @param specs - The existing element specifications to check against for duplicates
8
+ * @returns An array of element spec stubs for elements not already present in `specs`
9
+ */
2
10
  export declare function fetchObsoleteElements(obsoleteList: readonly string[], specs: readonly ExtendedElementSpec[]): ExtendedElementSpec[];
11
+ /**
12
+ * Scrapes an MDN element reference page to extract metadata about an HTML or SVG element.
13
+ * Gathers description, compatibility status flags, content categories, and attributes.
14
+ *
15
+ * @param link - The MDN URL for the element (e.g., `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a`)
16
+ * @returns An extended element specification object populated with scraped MDN data
17
+ */
3
18
  export declare function fetchHTMLElement(link: string): Promise<ExtendedElementSpec>;
package/lib/scraping.js CHANGED
@@ -1,6 +1,17 @@
1
1
  import { fetch } from './fetch.js';
2
2
  import { sortObjectByKey } from './utils.js';
3
+ /**
4
+ * CSS selector for the main content area on MDN pages.
5
+ */
3
6
  const MAIN_ARTICLE_SELECTOR = 'main#content';
7
+ /**
8
+ * Generates minimal element specification stubs for obsolete/deprecated elements
9
+ * that do not already exist in the provided specs array.
10
+ *
11
+ * @param obsoleteList - A list of element names considered obsolete or deprecated
12
+ * @param specs - The existing element specifications to check against for duplicates
13
+ * @returns An array of element spec stubs for elements not already present in `specs`
14
+ */
4
15
  export function fetchObsoleteElements(obsoleteList, specs) {
5
16
  return obsoleteList
6
17
  .map(name => {
@@ -27,6 +38,13 @@ export function fetchObsoleteElements(obsoleteList, specs) {
27
38
  })
28
39
  .filter((e) => !!e);
29
40
  }
41
+ /**
42
+ * Scrapes an MDN element reference page to extract metadata about an HTML or SVG element.
43
+ * Gathers description, compatibility status flags, content categories, and attributes.
44
+ *
45
+ * @param link - The MDN URL for the element (e.g., `https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/a`)
46
+ * @returns An extended element specification object populated with scraped MDN data
47
+ */
30
48
  export async function fetchHTMLElement(link) {
31
49
  const $ = await fetch(link);
32
50
  const name = link.replace(/.+\/([\w-]+)$/, '$1').toLowerCase();
@@ -116,6 +134,13 @@ export async function fetchHTMLElement(link) {
116
134
  };
117
135
  return spec;
118
136
  }
137
+ /**
138
+ * Extracts the text value of a specific property from the MDN technical summary table.
139
+ *
140
+ * @param $ - The Cheerio API instance for the page
141
+ * @param prop - The property name to look for in the table header cells (matched case-insensitively)
142
+ * @returns The trimmed text content of the corresponding table cell
143
+ */
119
144
  function getProperty(
120
145
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
121
146
  $, prop) {
@@ -126,6 +151,15 @@ $, prop) {
126
151
  .filter(el => new RegExp(prop, 'i').test($(el).text())));
127
152
  return $th.siblings('td').text().trim().replaceAll(/\s+/g, ' ');
128
153
  }
154
+ /**
155
+ * Extracts element attributes from an MDN page section identified by its `aria-labelledby` ID.
156
+ * Parses each `<dt>` entry in the section's definition list to gather attribute name,
157
+ * description, and status flags (experimental, obsolete, deprecated, non-standard).
158
+ *
159
+ * @param $ - The Cheerio API instance for the page
160
+ * @param id - The `aria-labelledby` ID of the section containing the attributes
161
+ * @returns An object containing a record of parsed attribute definitions keyed by attribute name
162
+ */
129
163
  function getAttributes(
130
164
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
131
165
  $, id) {
@@ -185,6 +219,12 @@ $, id) {
185
219
  }
186
220
  return { attributes };
187
221
  }
222
+ /**
223
+ * Traverses the DOM upward from a starting element to find its nearest preceding heading element.
224
+ *
225
+ * @param $start - The Cheerio element from which to begin the upward search
226
+ * @returns The heading element if found, or `null` if no heading is encountered
227
+ */
188
228
  function getItsHeading(
189
229
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
190
230
  $start) {
@@ -197,6 +237,12 @@ $start) {
197
237
  }
198
238
  return null;
199
239
  }
240
+ /**
241
+ * Moves to the previous sibling of the given element, or to its parent if no previous sibling exists.
242
+ *
243
+ * @param $start - The Cheerio element from which to navigate
244
+ * @returns The previous sibling or parent element
245
+ */
200
246
  function upToPrevOrParent(
201
247
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
202
248
  $start) {
@@ -206,6 +252,12 @@ $start) {
206
252
  }
207
253
  return $needle;
208
254
  }
255
+ /**
256
+ * Checks whether a Cheerio element is an HTML heading element (`<h1>` through `<h6>`).
257
+ *
258
+ * @param $el - The Cheerio element to test
259
+ * @returns `true` if the element is a heading, `false` otherwise
260
+ */
209
261
  function isHeading(
210
262
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
211
263
  $el) {
package/lib/svg.d.ts CHANGED
@@ -1 +1,8 @@
1
+ /**
2
+ * Fetches the MDN SVG element index page and extracts the list of
3
+ * obsolete and deprecated SVG element names.
4
+ * Each name is prefixed with `"svg_"` to distinguish it from HTML elements.
5
+ *
6
+ * @returns An array of deprecated/obsolete SVG element names (e.g., `["svg_altGlyph", ...]`)
7
+ */
1
8
  export declare function getSVGElementList(): Promise<string[]>;
package/lib/svg.js CHANGED
@@ -1,5 +1,12 @@
1
1
  import { fetch } from './fetch.js';
2
2
  import { getThisOutline } from './utils.js';
3
+ /**
4
+ * Fetches the MDN SVG element index page and extracts the list of
5
+ * obsolete and deprecated SVG element names.
6
+ * Each name is prefixed with `"svg_"` to distinguish it from HTML elements.
7
+ *
8
+ * @returns An array of deprecated/obsolete SVG element names (e.g., `["svg_altGlyph", ...]`)
9
+ */
3
10
  export async function getSVGElementList() {
4
11
  const index = 'https://developer.mozilla.org/en-US/docs/Web/SVG/Element';
5
12
  const $ = await fetch(index);
package/lib/utils.d.ts CHANGED
@@ -1,14 +1,73 @@
1
1
  import type * as cheerio from 'cheerio';
2
2
  import type { AnyNode } from 'domhandler';
3
+ /**
4
+ * Represents an object that has a `name` property.
5
+ */
3
6
  type HasName = {
4
7
  readonly name: string;
5
8
  };
9
+ /**
10
+ * Compares two items by their name property (or string value) in a case-insensitive manner.
11
+ * Suitable for use as a comparator function in `Array.prototype.sort`.
12
+ *
13
+ * @param a - The first item to compare, either a string or an object with a `name` property
14
+ * @param b - The second item to compare, either a string or an object with a `name` property
15
+ * @returns A negative number if `a` comes before `b`, positive if after, or zero if equal
16
+ */
6
17
  export declare function nameCompare(a: HasName | string, b: HasName | string): 1 | 0 | -1;
18
+ /**
19
+ * Creates a new object with the same key-value pairs, sorted alphabetically by key.
20
+ *
21
+ * @template T - The type of the object
22
+ * @param o - The object whose keys should be sorted
23
+ * @returns A new object with keys in sorted alphabetical order
24
+ */
7
25
  export declare function sortObjectByKey<T>(o: T): T;
26
+ /**
27
+ * Removes duplicate items from an array based on their `name` property,
28
+ * keeping only the first occurrence.
29
+ *
30
+ * @template T - The type of array items, must have a `name` property
31
+ * @param array - The array to deduplicate
32
+ * @returns A new array with unique items by name
33
+ */
8
34
  export declare function arrayUnique<T extends HasName>(array: readonly T[]): T[];
35
+ /**
36
+ * Collects all sibling elements following a starting element until the next `<h2>` heading
37
+ * (or end of siblings) and wraps them in a container `<div>`.
38
+ * Useful for extracting a section of content defined by a heading.
39
+ *
40
+ * @param $ - The Cheerio API instance for DOM manipulation
41
+ * @param $start - The starting element (typically a heading) from which to collect siblings
42
+ * @returns A Cheerio wrapper around a `<div>` containing cloned elements of the section
43
+ */
9
44
  export declare function getThisOutline($: cheerio.CheerioAPI, $start: cheerio.Cheerio<AnyNode>): cheerio.Cheerio<AnyNode>;
45
+ /**
46
+ * Merges two attribute objects, with values from `fromJSON` taking precedence
47
+ * over values from `fromDocs` when keys overlap.
48
+ *
49
+ * @template T - The type of the attribute objects
50
+ * @param fromDocs - Attribute data sourced from documentation
51
+ * @param fromJSON - Attribute data sourced from JSON specification files
52
+ * @returns A merged object combining both sources
53
+ */
10
54
  export declare function mergeAttributes<T>(fromDocs: T, fromJSON: T): T;
55
+ /**
56
+ * Returns the keys of an object with a custom type cast.
57
+ *
58
+ * @template T - The type of the input object
59
+ * @template K - The desired key type (defaults to `keyof T`)
60
+ * @param object - The object whose keys to extract
61
+ * @returns An array of the object's keys cast to the specified type
62
+ */
11
63
  export declare function keys<T, K = keyof T>(object: T): K[];
64
+ /**
65
+ * Parses an element name string to extract the local name, namespace, and markup language type.
66
+ * Handles SVG-prefixed names (e.g., `"svg_circle"`) and plain HTML names.
67
+ *
68
+ * @param origin - The raw element name, optionally prefixed with `"svg_"` for SVG elements
69
+ * @returns An object containing the `localName`, optional SVG `namespace` URI, and `ml` type (`"SVG"` or `"HTML"`)
70
+ */
12
71
  export declare function getName(origin: string): {
13
72
  localName: string;
14
73
  namespace: "http://www.w3.org/2000/svg" | undefined;
package/lib/utils.js CHANGED
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Compares two items by their name property (or string value) in a case-insensitive manner.
3
+ * Suitable for use as a comparator function in `Array.prototype.sort`.
4
+ *
5
+ * @param a - The first item to compare, either a string or an object with a `name` property
6
+ * @param b - The second item to compare, either a string or an object with a `name` property
7
+ * @returns A negative number if `a` comes before `b`, positive if after, or zero if equal
8
+ */
1
9
  export function nameCompare(a, b) {
2
10
  const nameA = typeof a === 'string' ? a : (a.name?.toUpperCase() ?? String(a));
3
11
  const nameB = typeof b === 'string' ? b : (b.name?.toUpperCase() ?? String(b));
@@ -9,6 +17,13 @@ export function nameCompare(a, b) {
9
17
  }
10
18
  return 0;
11
19
  }
20
+ /**
21
+ * Creates a new object with the same key-value pairs, sorted alphabetically by key.
22
+ *
23
+ * @template T - The type of the object
24
+ * @param o - The object whose keys should be sorted
25
+ * @returns A new object with keys in sorted alphabetical order
26
+ */
12
27
  export function sortObjectByKey(o) {
13
28
  // @ts-ignore
14
29
  const keys = Object.keys(o);
@@ -21,6 +36,14 @@ export function sortObjectByKey(o) {
21
36
  }
22
37
  return newObj;
23
38
  }
39
+ /**
40
+ * Removes duplicate items from an array based on their `name` property,
41
+ * keeping only the first occurrence.
42
+ *
43
+ * @template T - The type of array items, must have a `name` property
44
+ * @param array - The array to deduplicate
45
+ * @returns A new array with unique items by name
46
+ */
24
47
  export function arrayUnique(array) {
25
48
  const nameStack = [];
26
49
  const result = [];
@@ -33,6 +56,15 @@ export function arrayUnique(array) {
33
56
  }
34
57
  return result;
35
58
  }
59
+ /**
60
+ * Collects all sibling elements following a starting element until the next `<h2>` heading
61
+ * (or end of siblings) and wraps them in a container `<div>`.
62
+ * Useful for extracting a section of content defined by a heading.
63
+ *
64
+ * @param $ - The Cheerio API instance for DOM manipulation
65
+ * @param $start - The starting element (typically a heading) from which to collect siblings
66
+ * @returns A Cheerio wrapper around a `<div>` containing cloned elements of the section
67
+ */
36
68
  export function getThisOutline(
37
69
  // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
38
70
  $,
@@ -49,16 +81,40 @@ $start) {
49
81
  $container.append(el);
50
82
  return $container;
51
83
  }
84
+ /**
85
+ * Merges two attribute objects, with values from `fromJSON` taking precedence
86
+ * over values from `fromDocs` when keys overlap.
87
+ *
88
+ * @template T - The type of the attribute objects
89
+ * @param fromDocs - Attribute data sourced from documentation
90
+ * @param fromJSON - Attribute data sourced from JSON specification files
91
+ * @returns A merged object combining both sources
92
+ */
52
93
  export function mergeAttributes(fromDocs, fromJSON) {
53
94
  return {
54
95
  ...fromDocs,
55
96
  ...fromJSON,
56
97
  };
57
98
  }
99
+ /**
100
+ * Returns the keys of an object with a custom type cast.
101
+ *
102
+ * @template T - The type of the input object
103
+ * @template K - The desired key type (defaults to `keyof T`)
104
+ * @param object - The object whose keys to extract
105
+ * @returns An array of the object's keys cast to the specified type
106
+ */
58
107
  export function keys(object) {
59
108
  // @ts-ignore
60
109
  return Object.keys(object);
61
110
  }
111
+ /**
112
+ * Parses an element name string to extract the local name, namespace, and markup language type.
113
+ * Handles SVG-prefixed names (e.g., `"svg_circle"`) and plain HTML names.
114
+ *
115
+ * @param origin - The raw element name, optionally prefixed with `"svg_"` for SVG elements
116
+ * @returns An object containing the `localName`, optional SVG `namespace` URI, and `ml` type (`"SVG"` or `"HTML"`)
117
+ */
62
118
  export function getName(origin) {
63
119
  const [, ns, localName] = origin.match(/^(?:(svg)_)?(\w+)/i) ?? [];
64
120
  const name = localName ?? origin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/spec-generator",
3
- "version": "4.8.0",
3
+ "version": "4.8.2",
4
4
  "description": "Generates @markuplint/html-spec",
5
5
  "repository": "git@github.com:markuplint/markuplint.git",
6
6
  "author": "Yusuke Hirao <yusukehirao@me.com>",
@@ -23,17 +23,17 @@
23
23
  "dependencies": {
24
24
  "@types/cheerio": "1.0.0",
25
25
  "ajv": "8.17.1",
26
- "cheerio": "1.1.2",
26
+ "cheerio": "1.2.0",
27
27
  "cli-progress": "3.12.0",
28
- "fast-xml-parser": "5.2.5",
29
- "glob": "11.0.3",
28
+ "fast-xml-parser": "5.3.5",
29
+ "glob": "13.0.1",
30
30
  "strip-json-comments": "5.0.3"
31
31
  },
32
32
  "devDependencies": {
33
- "@markuplint/ml-spec": "4.10.0",
34
- "@markuplint/test-tools": "4.5.21",
33
+ "@markuplint/ml-spec": "4.10.2",
34
+ "@markuplint/test-tools": "4.5.23",
35
35
  "@types/cli-progress": "3.11.6",
36
36
  "type-fest": "4.41.0"
37
37
  },
38
- "gitHead": "ae97eb2d31ecedf4f0800fbbf18588aad4ebca04"
38
+ "gitHead": "193ee7c1262bbed95424e38efdf1a8e56ff049f4"
39
39
  }