remark-mdat 2.0.0 → 2.0.1

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/dist/index.d.ts CHANGED
@@ -115,7 +115,7 @@ declare function getSoleRule<T extends NormalizedRules | Rules>(rules: T): T[key
115
115
  declare function getSoleRuleKey<T extends NormalizedRules | Rules>(rules: T): keyof T;
116
116
  //#endregion
117
117
  //#region src/lib/mdast-utils/mdast-util-mdat.d.ts
118
- declare function mdat(tree: Root, file: VFile, rules: Rules): Promise<void>;
118
+ declare function mdat(tree: Root, file: VFile, rules: NormalizedRules | Rules): Promise<void>;
119
119
  //#endregion
120
120
  //#region src/lib/mdast-utils/mdast-util-mdat-clean.d.ts
121
121
  /**
@@ -128,7 +128,7 @@ declare function mdatClean(tree: Root, file: VFile): void;
128
128
  /**
129
129
  * Mdast utility to expand mdat comments in the tree.
130
130
  */
131
- declare function mdatExpand(tree: Root, file: VFile, rules: Rules): Promise<void>;
131
+ declare function mdatExpand(tree: Root, file: VFile, rules: NormalizedRules | Rules): Promise<void>;
132
132
  //#endregion
133
133
  //#region src/lib/mdast-utils/mdast-util-mdat-split.d.ts
134
134
  /**
package/dist/index.js CHANGED
@@ -128,6 +128,9 @@ function parseCommentNode(node, parent) {
128
128
  else throw new VFileMessage("Unknown error", node);
129
129
  }
130
130
  }
131
+ const HTML_COMMENT_OPEN_REGEX = /^\s*<!-{2,}\s*/;
132
+ const HTML_COMMENT_CLOSE_REGEX = /\s*-{2,}>\s*$/;
133
+ const WHITESPACE_REGEX = /\s/;
131
134
  /**
132
135
  * Parse any comment string into structured data.
133
136
  * Comments using code-style notation (`//`, `#`, `/*`) are ignored and return `undefined`.
@@ -137,9 +140,9 @@ function parseComment(text) {
137
140
  if (!isComment(text)) return;
138
141
  const closingPrefix = "/";
139
142
  const commentHtml = text.trim();
140
- const commentBody = commentHtml.replace(/^\s*<!-{2,}\s*/, "").replace(/\s*-{2,}>\s*$/, "");
143
+ const commentBody = commentHtml.replace(HTML_COMMENT_OPEN_REGEX, "").replace(HTML_COMMENT_CLOSE_REGEX, "");
141
144
  const parenIndex = commentBody.indexOf("(");
142
- const rawKeyword = parenIndex === -1 ? commentBody.split(/\s/)[0] : commentBody.slice(0, parenIndex).trim();
145
+ const rawKeyword = parenIndex === -1 ? commentBody.split(WHITESPACE_REGEX)[0] : commentBody.slice(0, parenIndex).trim();
143
146
  if (rawKeyword.startsWith("//") || rawKeyword.startsWith("#") || rawKeyword.startsWith("/*")) return;
144
147
  const type = rawKeyword.startsWith(closingPrefix) ? "close" : "open";
145
148
  let keyword = rawKeyword;
@@ -206,7 +209,14 @@ function mdatClean(tree, file) {
206
209
  }
207
210
  //#endregion
208
211
  //#region src/lib/mdat/rules.ts
212
+ /** Brand symbol to detect pre-normalized rules and skip re-validation. */
213
+ const NORMALIZED = Symbol("normalized");
214
+ /** Check whether rules have already been normalized. */
215
+ function isNormalized(rules) {
216
+ return NORMALIZED in rules;
217
+ }
209
218
  function normalizeRules(rules) {
219
+ validateRules(rules);
210
220
  const normalizedRules = {};
211
221
  for (const [keyword, rule] of Object.entries(rules)) if (typeof rule === "string") normalizedRules[keyword] = {
212
222
  content: async () => rule,
@@ -237,7 +247,7 @@ function normalizeRules(rules) {
237
247
  order: rule.order ?? 0
238
248
  };
239
249
  }
240
- validateNormalizedRules(normalizedRules);
250
+ Object.defineProperty(normalizedRules, NORMALIZED, { value: true });
241
251
  return normalizedRules;
242
252
  }
243
253
  function validateRules(rules) {
@@ -247,18 +257,7 @@ function validateRules(rules) {
247
257
  if (error instanceof Error) throw new TypeError(`Error validating rules: ${error.message}`);
248
258
  }
249
259
  }
250
- function validateNormalizedRules(rules) {
251
- try {
252
- normalizedRulesSchema.parse(rules);
253
- } catch (error) {
254
- if (error instanceof Error) throw new TypeError(`Error validating rules: ${error.message}`);
255
- }
256
- }
257
260
  const functionSchema = z.custom((value) => typeof value === "function");
258
- const normalizedRuleSchema = z.lazy(() => z.object({
259
- content: z.union([functionSchema, z.array(normalizedRuleSchema)]),
260
- order: z.number()
261
- }));
262
261
  const ruleSchema = z.lazy(() => z.union([
263
262
  functionSchema,
264
263
  z.array(ruleSchema),
@@ -272,9 +271,9 @@ const ruleSchema = z.lazy(() => z.union([
272
271
  order: z.number().optional()
273
272
  })
274
273
  ]));
275
- const keywordSchema = z.string().check(z.refine((key) => !/^[/*#]/.test(key), { message: "Rule keywords must not start with \"/\", \"*\", or \"#\" — these prefixes are reserved for comment syntax" }));
274
+ const COMMENT_PREFIX_REGEX = /^[/*#]/;
275
+ const keywordSchema = z.string().check(z.refine((key) => !COMMENT_PREFIX_REGEX.test(key), { message: "Rule keywords must not start with \"/\", \"*\", or \"#\" — these prefixes are reserved for comment syntax" }));
276
276
  const rulesSchema = z.record(keywordSchema, ruleSchema).describe("MDAT Rules");
277
- const normalizedRulesSchema = z.record(keywordSchema, normalizedRuleSchema).describe("MDAT Rules");
278
277
  /**
279
278
  * Expand rule content. For compound rules (content arrays), individual
280
279
  * sub-rule failures are reported via `onWarning` and skipped. The entire
@@ -344,8 +343,7 @@ function getSoleRecord(record) {
344
343
  * Mdast utility to expand mdat comments in the tree.
345
344
  */
346
345
  async function mdatExpand(tree, file, rules) {
347
- validateRules(rules);
348
- const normalizedRules = normalizeRules(rules);
346
+ const normalizedRules = isNormalized(rules) ? rules : normalizeRules(rules);
349
347
  const frontmatter = (() => {
350
348
  if (typeof file.value !== "string") return;
351
349
  const { data } = matter(file.value);
@@ -368,6 +366,7 @@ async function mdatExpand(tree, file, rules) {
368
366
  commentMarkers.push(commentMarker);
369
367
  });
370
368
  commentMarkers.sort((a, b) => normalizedRules[a.keyword].order - normalizedRules[b.keyword].order);
369
+ const parser = remark().use(remarkGfm);
371
370
  for (const comment of commentMarkers) {
372
371
  const { html, keyword, node, options, parent } = comment;
373
372
  const rule = normalizedRules[keyword];
@@ -384,7 +383,7 @@ async function mdatExpand(tree, file, rules) {
384
383
  }
385
384
  continue;
386
385
  }
387
- const newNodes = remark().use(remarkGfm).parse(newMarkdownString).children;
386
+ const newNodes = parser.parse(newMarkdownString).children;
388
387
  const closingNode = {
389
388
  type: "html",
390
389
  value: `<!-- /${keyword} -->`
@@ -403,6 +402,8 @@ async function mdatExpand(tree, file, rules) {
403
402
  function mdatSplit(tree, file) {
404
403
  visit(tree, "html", (node, index, parent) => {
405
404
  if (parent === void 0 || index === void 0) return CONTINUE;
405
+ const v = node.value;
406
+ if (v.startsWith("<!--") && v.endsWith("-->") && !v.includes("<!--", 4)) return CONTINUE;
406
407
  const htmlNodes = splitHtmlIntoMdastNodes(node);
407
408
  if (htmlNodes.length > 1) {
408
409
  saveLog(file, "warn", "split", "Multiple comments in a single HTML node.", node);
@@ -471,12 +472,12 @@ const optionsSchema = z.object({ rules: rulesSchema.optional() }).describe("MDAT
471
472
  * A remark plugin that expands HTML comments in Markdown files.
472
473
  */
473
474
  const remarkMdat = function(options) {
474
- const resolvedRules = {
475
+ const normalizedRules = normalizeRules({
475
476
  ...defaultRules,
476
477
  ...options?.rules
477
- };
478
+ });
478
479
  return async function(tree, file) {
479
- await mdat(tree, file, resolvedRules);
480
+ await mdat(tree, file, normalizedRules);
480
481
  };
481
482
  };
482
483
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remark-mdat",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "A remark plugin implementing the Markdown Autophagic Template (MDAT) system.",
5
5
  "keywords": [
6
6
  "mdat",
@@ -46,7 +46,7 @@
46
46
  "gray-matter-es": "^0.2.1",
47
47
  "hast-util-from-html": "^2.0.3",
48
48
  "json5": "^2.2.3",
49
- "lognow": "^0.5.2",
49
+ "lognow": "^0.6.0",
50
50
  "picocolors": "^1.1.1",
51
51
  "remark": "^15.0.1",
52
52
  "remark-gfm": "^4.0.1",
@@ -59,7 +59,7 @@
59
59
  },
60
60
  "devDependencies": {
61
61
  "@arethetypeswrong/core": "^0.18.2",
62
- "@kitschpatrol/shared-config": "^6.2.0",
62
+ "@kitschpatrol/shared-config": "^7.0.0",
63
63
  "@types/node": "~20.19.37",
64
64
  "bumpp": "^11.0.1",
65
65
  "publint": "^0.3.18",
@@ -77,6 +77,8 @@
77
77
  }
78
78
  },
79
79
  "scripts": {
80
+ "bench": "vitest bench --no-file-parallelism --compare test/benchmarks/baseline.json",
81
+ "bench:baseline": "vitest bench --no-file-parallelism --outputJson test/benchmarks/baseline.json",
80
82
  "build": "tsdown",
81
83
  "clean": "git rm -f pnpm-lock.yaml ; git clean -fdX",
82
84
  "dev": "pnpm run test",