@brandlab-digital/conformance 2.1.0 → 3.0.0

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.
Files changed (67) hide show
  1. package/dist/analytics-e2e.d.ts +52 -0
  2. package/dist/analytics-e2e.d.ts.map +1 -0
  3. package/dist/analytics-e2e.js +189 -0
  4. package/dist/analytics-e2e.js.map +1 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +40 -3
  8. package/dist/cli.js.map +1 -1
  9. package/dist/contact-e2e.d.ts +43 -0
  10. package/dist/contact-e2e.d.ts.map +1 -0
  11. package/dist/contact-e2e.js +193 -0
  12. package/dist/contact-e2e.js.map +1 -0
  13. package/dist/current-release.js +7 -7
  14. package/dist/current-release.js.map +1 -1
  15. package/dist/e2e-support.d.ts +42 -0
  16. package/dist/e2e-support.d.ts.map +1 -0
  17. package/dist/e2e-support.js +126 -0
  18. package/dist/e2e-support.js.map +1 -0
  19. package/dist/engineering.d.ts +14 -0
  20. package/dist/engineering.d.ts.map +1 -1
  21. package/dist/engineering.js +446 -50
  22. package/dist/engineering.js.map +1 -1
  23. package/dist/estate.d.ts +105 -0
  24. package/dist/estate.d.ts.map +1 -0
  25. package/dist/estate.js +391 -0
  26. package/dist/estate.js.map +1 -0
  27. package/dist/families-e2e.d.ts +45 -0
  28. package/dist/families-e2e.d.ts.map +1 -0
  29. package/dist/families-e2e.js +248 -0
  30. package/dist/families-e2e.js.map +1 -0
  31. package/dist/glob.d.ts +21 -0
  32. package/dist/glob.d.ts.map +1 -0
  33. package/dist/glob.js +138 -0
  34. package/dist/glob.js.map +1 -0
  35. package/dist/knip.d.ts +47 -0
  36. package/dist/knip.d.ts.map +1 -0
  37. package/dist/knip.js +84 -0
  38. package/dist/knip.js.map +1 -0
  39. package/dist/project.d.ts +4 -1
  40. package/dist/project.d.ts.map +1 -1
  41. package/dist/project.js +163 -147
  42. package/dist/project.js.map +1 -1
  43. package/dist/public-copy.d.ts +36 -0
  44. package/dist/public-copy.d.ts.map +1 -0
  45. package/dist/public-copy.js +517 -0
  46. package/dist/public-copy.js.map +1 -0
  47. package/dist/rule-registry.d.ts +292 -0
  48. package/dist/rule-registry.d.ts.map +1 -0
  49. package/dist/rule-registry.js +68 -0
  50. package/dist/rule-registry.js.map +1 -0
  51. package/dist/search-certification.d.ts +4 -0
  52. package/dist/search-certification.d.ts.map +1 -1
  53. package/dist/search-certification.js +17 -3
  54. package/dist/search-certification.js.map +1 -1
  55. package/dist/source-files.d.ts +54 -0
  56. package/dist/source-files.d.ts.map +1 -0
  57. package/dist/source-files.js +323 -0
  58. package/dist/source-files.js.map +1 -0
  59. package/dist/static-rules.d.ts +45 -0
  60. package/dist/static-rules.d.ts.map +1 -0
  61. package/dist/static-rules.js +762 -0
  62. package/dist/static-rules.js.map +1 -0
  63. package/dist/verification-policy.d.ts +13 -4
  64. package/dist/verification-policy.d.ts.map +1 -1
  65. package/dist/verification-policy.js +31 -12
  66. package/dist/verification-policy.js.map +1 -1
  67. package/package.json +37 -1
@@ -0,0 +1,517 @@
1
+ import { posix } from "node:path";
2
+ import ts from "typescript";
3
+ import { BRANDLAB_IMPLEMENTATION_COPY_PATTERNS, isBrandlabTradePhrase } from "./search-certification.js";
4
+ import { lineAt } from "./source-files.js";
5
+ /** Root-level framework modules that configure the server and never render copy. */
6
+ const SERVER_ROOT_MODULE = /^(?:instrumentation[\w.-]*|proxy|middleware|next\.config)\.[cm]?[jt]sx?$/;
7
+ /** Test, fixture and story sources are not part of the public build. */
8
+ const NON_PUBLIC_DIRECTORY = /(?:^|\/)(?:__tests__|__mocks__|__fixtures__|__snapshots__)\//;
9
+ const NON_PUBLIC_ROOT = /^(?:src\/)?(?:test|tests|testing|e2e|fixtures|mocks|stories|storybook)\//;
10
+ const NON_PUBLIC_FILE = /\.(?:d\.[cm]?ts|stories\.[cm]?[jt]sx?)$/;
11
+ function isNonPublicPath(path) {
12
+ return NON_PUBLIC_DIRECTORY.test(path) || NON_PUBLIC_ROOT.test(path);
13
+ }
14
+ /** Whether a project source module can render public output. */
15
+ export function isPublicModulePath(path) {
16
+ if (!path.includes("/") && SERVER_ROOT_MODULE.test(path))
17
+ return false;
18
+ return !isNonPublicPath(path) && !NON_PUBLIC_FILE.test(path);
19
+ }
20
+ const CONTENT_SEGMENTS = new Set(["content", "posts", "blog", "articles", "data", "app"]);
21
+ const DOCUMENTATION_NAMES = /^(?:readme|agents|claude|changelog|contributing|license|design|strategy)(?:\.[\w-]+)?\.mdx?$/i;
22
+ /** Whether a project file is public content: MDX anywhere, Markdown and JSON under content or data. */
23
+ export function isPublicDocumentPath(path) {
24
+ if (isNonPublicPath(path))
25
+ return false;
26
+ const name = posix.basename(path);
27
+ if (/\.mdx$/i.test(path))
28
+ return !DOCUMENTATION_NAMES.test(name);
29
+ const inContent = posix.dirname(path).split("/").some((segment) => CONTENT_SEGMENTS.has(segment));
30
+ if (/\.md$/i.test(path))
31
+ return inContent && !DOCUMENTATION_NAMES.test(name);
32
+ return /\.json$/i.test(path) && inContent && !/(?:^|\.)schema\.json$/i.test(name);
33
+ }
34
+ // --- matching ----------------------------------------------------------------
35
+ const GLOBAL_PATTERNS = BRANDLAB_IMPLEMENTATION_COPY_PATTERNS.map((pattern) => ({
36
+ pattern,
37
+ global: new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`),
38
+ }));
39
+ /**
40
+ * The first wording pattern that occurs as a word of prose. Occurrences inside a
41
+ * code token (a Tailwind variant such as placeholder:text-stone-400, a path, a file
42
+ * name, a CSS property or a kebab-case class) or a literal trade phrase (benchtop
43
+ * template) are not implementation wording. Text that is not a copy slot must hold
44
+ * at least two words, so single identifiers never match.
45
+ */
46
+ export function findImplementationWording(text, options = {}) {
47
+ if (!options.singleWord && !/\S\s+\S/.test(text))
48
+ return null;
49
+ for (const { pattern, global } of GLOBAL_PATTERNS) {
50
+ for (const match of text.matchAll(global)) {
51
+ if (isBrandlabTradePhrase(text, match.index, match[0].length))
52
+ continue;
53
+ if (/\s/.test(match[0]) || !isCodeToken(text, match.index, match[0].length)) {
54
+ return { pattern, index: match.index };
55
+ }
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ function isCodeToken(text, index, length) {
61
+ let start = index;
62
+ while (start > 0 && !/\s/.test(text[start - 1]))
63
+ start -= 1;
64
+ let end = index + length;
65
+ while (end < text.length && !/\s/.test(text[end]))
66
+ end += 1;
67
+ const token = text
68
+ .slice(start, end)
69
+ .replace(/^[("'‘“]+/, "")
70
+ .replace(/[)"'’”.,;:!?]+$/, "");
71
+ if (/[/\\[\]{}()<>=@#$^|`]/.test(token) || /[:.]/.test(token))
72
+ return true;
73
+ return /^-?[a-z0-9]+(?:-[a-z0-9]+)+$/.test(token) && (/\d/.test(token) || token.split("-").length >= 3);
74
+ }
75
+ // --- rendering context -------------------------------------------------------
76
+ /** Class, style and variant names never hold copy: className, inputClass, cardStyles, variants. */
77
+ const CLASS_OR_STYLE_WORDS = new Set([
78
+ "class", "classes", "classname", "classnames", "cls", "style", "styles", "sx", "css", "tw", "variant",
79
+ "variants", "compoundvariants",
80
+ ]);
81
+ const CLASS_OR_STYLE_SUFFIX = /[a-z0-9](?:Class|Classes|ClassName|ClassNames|Style|Styles|Variants|Css)$/;
82
+ /** Internal record fields and builders (rationale, evidence, decisions) never render. */
83
+ const INTERNAL_RECORD_NAME = /^(?:rationales?|evidence|decisions?)$|[a-z0-9](?:Rationales?|Evidence|Decisions?)$/;
84
+ /** Names whose values are identifiers, addresses or code rather than copy. */
85
+ const NON_RENDERING_NAMES = new Set([
86
+ "id", "key", "ref", "href", "src", "srcset", "sizes", "url", "path", "pathname", "slug", "route",
87
+ "canonical", "icon", "variant", "size", "as", "type", "kind", "mode", "tone", "theme", "layout",
88
+ "rel", "target", "method", "enctype", "pattern", "regex", "selector", "matcher",
89
+ "media", "strategy", "loading", "decoding", "fetchpriority", "crossorigin", "referrerpolicy",
90
+ "integrity", "nonce", "viewbox", "d", "points", "transform", "fill", "stroke", "xmlns",
91
+ "testid", "datatestid", "fontfamily", "font", "locale", "timezone", "format", "env", "event",
92
+ "eventname", "@context", "@id", "@type",
93
+ ]);
94
+ /** Intrinsic element attributes that render text (visibly or to assistive technology). */
95
+ const RENDERED_INTRINSIC_ATTRIBUTES = new Set(["alt", "title", "placeholder", "label", "content", "value", "summary", "abbr"]);
96
+ const RENDERED_ARIA_ATTRIBUTES = new Set(["aria-label", "aria-description", "aria-roledescription", "aria-valuetext", "aria-placeholder"]);
97
+ /** Attributes that pass through a component without rendering. */
98
+ const NON_RENDERING_COMPONENT_ATTRIBUTES = new Set([
99
+ "name", "form", "htmlfor", "for", "lang", "dir", "tabindex", "slot", "role", "autocomplete", "inputmode",
100
+ "accept", "allow", "sandbox", "width", "height", "itemprop", "itemtype", "itemid", "property", "charset",
101
+ "httpequiv", "http-equiv", "priority", "quality", "prefetch", "scroll", "replace",
102
+ ]);
103
+ /** Copy slots are checked even when they hold a single word. */
104
+ const COPY_NAME = /^(?:alt|title|label|caption|heading|headline|subheading|subtitle|eyebrow|summary|excerpt|intro|description|text|body|content|question|answer|placeholder|cta|tagline|quote|message|aria-label)$|[a-z0-9](?:Alt|Title|Label|Caption|Heading|Headline|Subtitle|Eyebrow|Summary|Excerpt|Description|Text|Body|Content|Question|Answer|Placeholder|Cta|Tagline|Message)$/;
105
+ /** Elements whose children are code, not copy. */
106
+ const CODE_ELEMENTS = new Set(["script", "style", "Script"]);
107
+ /** Calls whose string arguments are class lists. */
108
+ const CLASS_UTILITIES = new Set(["cn", "clsx", "cx", "classNames", "classnames", "twMerge", "twJoin", "cva", "tv"]);
109
+ /** Calls whose string arguments never render. */
110
+ const NON_RENDERING_CALLS = /^(?:(?:console|logger|log)\.\w+|require(?:\.resolve)?|fetch|RegExp|Symbol(?:\.for)?|JSON\.parse|matchMedia|redirect|permanentRedirect|notFound|invariant|assert\w*|gtag|(?:NextResponse|Response)\.(?:redirect|rewrite))$|\.(?:querySelector(?:All)?|getElementById|getElementsByClassName|closest|matches|matchMedia|addEventListener|removeEventListener|setAttribute|getAttribute|removeAttribute|hasAttribute|toggleAttribute|startsWith|endsWith|includes|indexOf|split|replace|replaceAll|match|matchAll|search|test|join|localeCompare)$|classList\./;
111
+ const NON_RENDERING_CONSTRUCTORS = /(?:Error|^URL|^URLSearchParams|^RegExp|^Date|^Headers|^Intl\.\w+)$/;
112
+ const CODE_TAGS = /^(?:css|sql|gql|graphql|keyframes|createGlobalStyle|styled(?:\.\w+)?)$/;
113
+ const COMPARISONS = new Set([
114
+ ts.SyntaxKind.EqualsEqualsEqualsToken, ts.SyntaxKind.ExclamationEqualsEqualsToken,
115
+ ts.SyntaxKind.EqualsEqualsToken, ts.SyntaxKind.ExclamationEqualsToken, ts.SyntaxKind.InKeyword,
116
+ ts.SyntaxKind.InstanceOfKeyword,
117
+ ]);
118
+ function nameRenders(name) {
119
+ const lower = name.toLowerCase();
120
+ return !CLASS_OR_STYLE_WORDS.has(lower) && !CLASS_OR_STYLE_SUFFIX.test(name) && !INTERNAL_RECORD_NAME.test(name) &&
121
+ !NON_RENDERING_NAMES.has(lower) && !lower.startsWith("data-");
122
+ }
123
+ function attributeRenders(tag, attribute) {
124
+ if (attribute.startsWith("aria-"))
125
+ return RENDERED_ARIA_ATTRIBUTES.has(attribute);
126
+ if (/^on[A-Z]/.test(attribute) || !nameRenders(attribute))
127
+ return false;
128
+ if (/^[a-z]/.test(tag) && !tag.includes("."))
129
+ return RENDERED_INTRINSIC_ATTRIBUTES.has(attribute);
130
+ return !NON_RENDERING_COMPONENT_ATTRIBUTES.has(attribute.toLowerCase());
131
+ }
132
+ function entityName(node) {
133
+ if (ts.isIdentifier(node) || ts.isPrivateIdentifier(node))
134
+ return node.text;
135
+ if (ts.isStringLiteralLike(node) || ts.isNumericLiteral(node))
136
+ return node.text;
137
+ if (ts.isPropertyAccessExpression(node)) {
138
+ const object = entityName(node.expression);
139
+ return object === null ? node.name.text : `${object}.${node.name.text}`;
140
+ }
141
+ if (ts.isCallExpression(node))
142
+ return entityName(node.expression);
143
+ if (ts.isJsxNamespacedName(node))
144
+ return `${node.namespace.text}:${node.name.text}`;
145
+ if (node.kind === ts.SyntaxKind.ThisKeyword)
146
+ return "this";
147
+ return null;
148
+ }
149
+ function lastName(name) {
150
+ return name.slice(name.lastIndexOf(".") + 1);
151
+ }
152
+ /** Where a string literal renders, or null when its position never renders. */
153
+ function literalSlot(node) {
154
+ let slot;
155
+ let child = node;
156
+ for (let parent = node.parent; parent && !ts.isSourceFile(parent); child = parent, parent = parent.parent) {
157
+ if (ts.isTypeNode(parent) || ts.isEnumMember(parent) || ts.isComputedPropertyName(parent))
158
+ return null;
159
+ if (ts.isImportDeclaration(parent) || ts.isExportDeclaration(parent) ||
160
+ ts.isExternalModuleReference(parent) || ts.isImportEqualsDeclaration(parent) ||
161
+ ts.isThrowStatement(parent))
162
+ return null;
163
+ if (ts.isExpressionStatement(parent) && child === node)
164
+ return null;
165
+ if (ts.isCaseClause(parent) && parent.expression === child)
166
+ return null;
167
+ if (ts.isElementAccessExpression(parent) && parent.argumentExpression === child)
168
+ return null;
169
+ if (ts.isPropertyAssignment(parent) || ts.isPropertyDeclaration(parent)) {
170
+ if (parent.name === child)
171
+ return null;
172
+ const key = entityName(parent.name);
173
+ if (key !== null) {
174
+ if (!nameRenders(key))
175
+ return null;
176
+ slot ??= { where: `the ${key} field`, singleWord: COPY_NAME.test(key) };
177
+ }
178
+ }
179
+ else if (ts.isJsxAttribute(parent)) {
180
+ const attribute = entityName(parent.name) ?? "";
181
+ const element = parent.parent.parent;
182
+ if (!attributeRenders(entityName(element.tagName) ?? "", attribute))
183
+ return null;
184
+ slot ??= { where: `the ${attribute} attribute`, singleWord: attribute === "alt" || COPY_NAME.test(attribute) };
185
+ }
186
+ else if (ts.isJsxElement(parent)) {
187
+ if (CODE_ELEMENTS.has(entityName(parent.openingElement.tagName) ?? ""))
188
+ return null;
189
+ slot ??= { where: "JSX text", singleWord: true };
190
+ }
191
+ else if (ts.isJsxFragment(parent)) {
192
+ slot ??= { where: "JSX text", singleWord: true };
193
+ }
194
+ else if (ts.isCallExpression(parent) || ts.isNewExpression(parent)) {
195
+ if (parent.expression === child)
196
+ continue;
197
+ if (parent.expression.kind === ts.SyntaxKind.ImportKeyword)
198
+ return null;
199
+ const callee = entityName(parent.expression) ?? "";
200
+ const skipped = ts.isNewExpression(parent)
201
+ ? NON_RENDERING_CONSTRUCTORS.test(callee)
202
+ : CLASS_UTILITIES.has(lastName(callee)) || NON_RENDERING_CALLS.test(callee) ||
203
+ INTERNAL_RECORD_NAME.test(lastName(callee));
204
+ if (skipped)
205
+ return null;
206
+ slot ??= { where: "a rendered string", singleWord: false };
207
+ }
208
+ else if (ts.isTaggedTemplateExpression(parent)) {
209
+ if (CODE_TAGS.test(entityName(parent.tag) ?? ""))
210
+ return null;
211
+ }
212
+ else if (ts.isBinaryExpression(parent)) {
213
+ if (COMPARISONS.has(parent.operatorToken.kind))
214
+ return null;
215
+ if (parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && parent.right === child) {
216
+ const target = entityName(parent.left);
217
+ if (target !== null && !nameRenders(lastName(target)))
218
+ return null;
219
+ }
220
+ }
221
+ else if (ts.isVariableDeclaration(parent) || ts.isParameter(parent) || ts.isBindingElement(parent) ||
222
+ ts.isFunctionDeclaration(parent) || ts.isMethodDeclaration(parent)) {
223
+ const name = parent.name && ts.isIdentifier(parent.name) ? parent.name.text : null;
224
+ if (name !== null && !nameRenders(name))
225
+ return null;
226
+ if (name !== null && !ts.isFunctionDeclaration(parent) && !ts.isMethodDeclaration(parent)) {
227
+ slot ??= { where: `the ${name} value`, singleWord: COPY_NAME.test(name) };
228
+ }
229
+ }
230
+ }
231
+ return slot ?? { where: "a rendered string", singleWord: false };
232
+ }
233
+ function insideCodeElement(node) {
234
+ for (let parent = node.parent; parent && !ts.isSourceFile(parent); parent = parent.parent) {
235
+ if (ts.isJsxElement(parent) && CODE_ELEMENTS.has(entityName(parent.openingElement.tagName) ?? ""))
236
+ return true;
237
+ }
238
+ return false;
239
+ }
240
+ /** Tags inside a string (rich text) do not render; blank them without moving offsets. */
241
+ function blankTags(text) {
242
+ return text.replace(/<[^<>]*>/g, (tag) => " ".repeat(tag.length));
243
+ }
244
+ /** Implementation wording in the rendered copy of a TypeScript, JavaScript or JSON source. */
245
+ export function findWordingInSource(source) {
246
+ const text = source.text;
247
+ const findings = [];
248
+ const report = (value, offsets, slot) => {
249
+ const match = findImplementationWording(value, { singleWord: slot.singleWord });
250
+ if (match)
251
+ findings.push({ line: lineAt(text, offsets(match.index)), where: slot.where, pattern: match.pattern });
252
+ };
253
+ const visit = (node) => {
254
+ if (ts.isJsxText(node)) {
255
+ if (!node.containsOnlyTriviaWhiteSpaces && !insideCodeElement(node)) {
256
+ const start = node.end - node.text.length;
257
+ report(node.text, (index) => start + index, { where: "JSX text", singleWord: true });
258
+ }
259
+ return;
260
+ }
261
+ if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
262
+ const slot = literalSlot(node);
263
+ const start = node.getStart(source) + 1;
264
+ if (slot)
265
+ report(blankTags(node.text), (index) => start + index, slot);
266
+ return;
267
+ }
268
+ if (ts.isTemplateExpression(node)) {
269
+ const slot = literalSlot(node);
270
+ if (slot) {
271
+ const parts = [node.head, ...node.templateSpans.map((span) => span.literal)];
272
+ const starts = [];
273
+ let value = "";
274
+ for (const [position, part] of parts.entries()) {
275
+ if (position > 0)
276
+ value += " ";
277
+ starts.push(value.length);
278
+ value += part.text;
279
+ }
280
+ report(blankTags(value), (index) => {
281
+ let position = starts.length - 1;
282
+ while (position > 0 && starts[position] > index)
283
+ position -= 1;
284
+ return parts[position].getStart(source) + 1 + (index - starts[position]);
285
+ }, slot);
286
+ }
287
+ }
288
+ ts.forEachChild(node, visit);
289
+ };
290
+ visit(source);
291
+ return findings;
292
+ }
293
+ /** Parse a JSON document with parent links so data values share the module rules. */
294
+ export function parseJsonSource(path, text) {
295
+ return ts.createSourceFile(path, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.JSON);
296
+ }
297
+ // --- MDX and Markdown --------------------------------------------------------
298
+ /** Frontmatter keys whose values are identifiers, dates or addresses. */
299
+ const NON_RENDERING_FRONTMATTER = /^(?:slug|date|datePublished|dateModified|published|publishedAt|updated|updatedAt|lastModified|draft|id|image|images|cover|coverImage|thumbnail|ogImage|src|href|url|canonical|layout|template|redirect|redirectFrom|aliases|order|weight|featured|noindex|robots|readingTime)$/i;
300
+ /** Implementation wording in the rendered text of an MDX or Markdown document. */
301
+ export function findWordingInMarkdown(text) {
302
+ const findings = [];
303
+ const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n|$)/.exec(text);
304
+ let bodyStart = 0;
305
+ if (frontmatter) {
306
+ bodyStart = frontmatter[0].length;
307
+ let lastKey = null;
308
+ let offset = text.indexOf("\n") + 1;
309
+ for (const line of frontmatter[1].split("\n")) {
310
+ const entry = /^\s*(?:-\s+)?(?:(["']?)([\w@$.-]+)\1\s*:(?=\s|$))?\s*(.*?)\s*$/.exec(line.replace(/\r$/, ""));
311
+ if (entry[2])
312
+ lastKey = entry[2];
313
+ const key = entry[2] ?? lastKey;
314
+ const value = frontmatterValue(entry[3]);
315
+ if (key !== null && value !== "" && !NON_RENDERING_FRONTMATTER.test(key) && nameRenders(key)) {
316
+ const match = findImplementationWording(value, { singleWord: COPY_NAME.test(key) });
317
+ if (match)
318
+ findings.push({ line: lineAt(text, offset), where: `the ${key} frontmatter`, pattern: match.pattern });
319
+ }
320
+ offset += line.length + 1;
321
+ }
322
+ }
323
+ const { prose, esm } = renderedMarkdownText(text, bodyStart);
324
+ if (esm.trim() !== "") {
325
+ // ESM such as `export const metadata = { ... }` renders as page metadata.
326
+ findings.push(...findWordingInSource(ts.createSourceFile("content.tsx", esm, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX)));
327
+ }
328
+ let offset = 0;
329
+ for (const line of prose.split("\n")) {
330
+ const match = findImplementationWording(line, { singleWord: true });
331
+ if (match && offset + match.index >= bodyStart) {
332
+ findings.push({ line: lineAt(text, offset + match.index), where: "the content", pattern: match.pattern });
333
+ }
334
+ offset += line.length + 1;
335
+ }
336
+ return findings.sort((left, right) => left.line - right.line);
337
+ }
338
+ /** A frontmatter scalar or inline list as its rendered words ("" for block indicators and comments). */
339
+ function frontmatterValue(raw) {
340
+ if (/^[|>][-+]?\d*$/.test(raw) || raw.startsWith("#"))
341
+ return "";
342
+ const list = /^\[(.*)\]$/.exec(raw);
343
+ if (list)
344
+ return list[1].replace(/["']/g, " ");
345
+ return raw.replace(/^(["'])(.*)\1$/, "$2");
346
+ }
347
+ /**
348
+ * The document with everything that does not render as words blanked in place
349
+ * (offsets and lines unchanged): frontmatter, code, ESM, comments, expressions,
350
+ * tag syntax (rendered attribute values stay), link targets and Markdown markers.
351
+ * The ESM blocks come back separately, blanked the same way, to be read as source.
352
+ */
353
+ function renderedMarkdownText(text, bodyStart) {
354
+ const out = text.split("");
355
+ const esmOut = text.replace(/[^\n]/g, " ").split("");
356
+ const blank = (from, to) => {
357
+ for (let index = Math.max(from, 0); index < Math.min(to, out.length); index += 1) {
358
+ if (out[index] !== "\n")
359
+ out[index] = " ";
360
+ }
361
+ };
362
+ blank(0, bodyStart);
363
+ // Fenced code and ESM blocks, line by line.
364
+ let fence = null;
365
+ let esm = false;
366
+ let offset = bodyStart;
367
+ for (const line of text.slice(bodyStart).split("\n")) {
368
+ const end = offset + line.length;
369
+ const marker = /^ {0,3}(`{3,}|~{3,})/.exec(line)?.[1];
370
+ if (fence !== null) {
371
+ blank(offset, end);
372
+ if (marker && marker[0] === fence[0] && marker.length >= fence.length && line.trim() === marker)
373
+ fence = null;
374
+ }
375
+ else if (marker) {
376
+ blank(offset, end);
377
+ fence = marker;
378
+ }
379
+ else if (esm || /^(?:import|export)\b/.test(line)) {
380
+ for (let index = offset; index < end; index += 1)
381
+ esmOut[index] = text[index];
382
+ blank(offset, end);
383
+ esm = line.trim() !== "";
384
+ }
385
+ offset = end + 1;
386
+ }
387
+ // Comments, expressions, inline code and tags.
388
+ const skipBraces = (from) => {
389
+ let depth = 0;
390
+ for (let index = from; index < text.length; index += 1) {
391
+ const char = out[index];
392
+ if (char === "{")
393
+ depth += 1;
394
+ else if (char === "}" && --depth === 0)
395
+ return index + 1;
396
+ }
397
+ return -1;
398
+ };
399
+ let index = bodyStart;
400
+ while (index < out.length) {
401
+ const char = out[index];
402
+ if (char === "\\" && index + 1 < out.length && out[index + 1] !== "\n") {
403
+ blank(index, index + 1);
404
+ index += 2;
405
+ }
406
+ else if (char === "`") {
407
+ let run = 1;
408
+ while (out[index + run] === "`")
409
+ run += 1;
410
+ const close = text.indexOf("`".repeat(run), index + run);
411
+ if (close === -1)
412
+ index += run;
413
+ else {
414
+ blank(index, close + run);
415
+ index = close + run;
416
+ }
417
+ }
418
+ else if (char === "{") {
419
+ const end = skipBraces(index);
420
+ if (end === -1)
421
+ index += 1;
422
+ else {
423
+ blank(index, end);
424
+ index = end;
425
+ }
426
+ }
427
+ else if (char === "<" && text.startsWith("<!--", index)) {
428
+ const close = text.indexOf("-->", index + 4);
429
+ const end = close === -1 ? text.length : close + 3;
430
+ blank(index, end);
431
+ index = end;
432
+ }
433
+ else if (char === "<" && /[A-Za-z/]/.test(out[index + 1] ?? "")) {
434
+ const end = blankTag(text, out, index, blank, skipBraces);
435
+ index = end === -1 ? index + 1 : end;
436
+ }
437
+ else {
438
+ index += 1;
439
+ }
440
+ }
441
+ // Markdown syntax: reference definitions, link targets and markers.
442
+ let rendered = out.join("");
443
+ rendered = rendered.replace(/^ {0,3}\[[^\]\n]+\]:[^\n]*$/gm, (line) => " ".repeat(line.length));
444
+ rendered = rendered.replace(/(!?\[)([^\]\n]*)(\]\([^)\n]*\)|\]\[[^\]\n]*\])/g, (_match, open, label, target) => `${" ".repeat(open.length)}${label}${" ".repeat(target.length)}`);
445
+ rendered = rendered.replace(/[*~#>|]/g, " ").replace(/(?<!\w)_+|_+(?!\w)/g, (match) => " ".repeat(match.length));
446
+ return { prose: rendered, esm: esmOut.join("") };
447
+ }
448
+ /** Blank one JSX or HTML tag in place, keeping rendered attribute values; -1 if it is not a tag. */
449
+ function blankTag(text, out, start, blank, skipBraces) {
450
+ const name = /^<\/?([A-Za-z][\w.:-]*)/.exec(text.slice(start, start + 200));
451
+ if (!name)
452
+ return -1;
453
+ const tag = name[1];
454
+ let index = start + name[0].length;
455
+ const keep = [];
456
+ while (index < text.length) {
457
+ while (/\s/.test(text[index] ?? "")) {
458
+ if (text.startsWith("\n\n", index))
459
+ return -1;
460
+ index += 1;
461
+ }
462
+ if (text.startsWith("/>", index)) {
463
+ index += 2;
464
+ break;
465
+ }
466
+ if (text[index] === ">") {
467
+ index += 1;
468
+ break;
469
+ }
470
+ if (text[index] === "{") {
471
+ const end = skipBraces(index);
472
+ if (end === -1)
473
+ return -1;
474
+ index = end;
475
+ continue;
476
+ }
477
+ const attribute = /^[^\s=>/{}]+/.exec(text.slice(index, index + 100))?.[0];
478
+ if (!attribute)
479
+ return -1;
480
+ index += attribute.length;
481
+ while (text[index] === " " || text[index] === "\t")
482
+ index += 1;
483
+ if (text[index] !== "=")
484
+ continue;
485
+ index += 1;
486
+ while (text[index] === " " || text[index] === "\t")
487
+ index += 1;
488
+ const quote = text[index];
489
+ if (quote === '"' || quote === "'") {
490
+ const close = text.indexOf(quote, index + 1);
491
+ if (close === -1)
492
+ return -1;
493
+ if (attributeRenders(tag, attribute))
494
+ keep.push([index + 1, close]);
495
+ index = close + 1;
496
+ }
497
+ else if (quote === "{") {
498
+ const end = skipBraces(index);
499
+ if (end === -1)
500
+ return -1;
501
+ index = end;
502
+ }
503
+ else {
504
+ const value = /^[^\s>]+/.exec(text.slice(index))?.[0] ?? "";
505
+ index += value.length;
506
+ }
507
+ }
508
+ const saved = keep.map(([from, to]) => out.slice(from, to));
509
+ blank(start, index);
510
+ keep.forEach(([from], position) => {
511
+ saved[position].forEach((char, offset) => {
512
+ out[from + offset] = char;
513
+ });
514
+ });
515
+ return index;
516
+ }
517
+ //# sourceMappingURL=public-copy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-copy.js","sourceRoot":"","sources":["../src/public-copy.ts"],"names":[],"mappings":"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","sourcesContent":["import { posix } from \"node:path\";\nimport ts from \"typescript\";\nimport { BRANDLAB_IMPLEMENTATION_COPY_PATTERNS, isBrandlabTradePhrase } from \"./search-certification.js\";\nimport { lineAt } from \"./source-files.js\";\n\n/**\n * Implementation wording found in text that renders publicly: JSX text, rendered\n * attributes, copy-bearing string literals, MDX and Markdown prose, frontmatter\n * and JSON data values.\n */\nexport interface PublicCopyFinding {\n line: number;\n /** Where the text renders, such as \"JSX text\" or \"the alt attribute\". */\n where: string;\n pattern: RegExp;\n}\n\n/** Root-level framework modules that configure the server and never render copy. */\nconst SERVER_ROOT_MODULE = /^(?:instrumentation[\\w.-]*|proxy|middleware|next\\.config)\\.[cm]?[jt]sx?$/;\n/** Test, fixture and story sources are not part of the public build. */\nconst NON_PUBLIC_DIRECTORY = /(?:^|\\/)(?:__tests__|__mocks__|__fixtures__|__snapshots__)\\//;\nconst NON_PUBLIC_ROOT = /^(?:src\\/)?(?:test|tests|testing|e2e|fixtures|mocks|stories|storybook)\\//;\nconst NON_PUBLIC_FILE = /\\.(?:d\\.[cm]?ts|stories\\.[cm]?[jt]sx?)$/;\n\nfunction isNonPublicPath(path: string): boolean {\n return NON_PUBLIC_DIRECTORY.test(path) || NON_PUBLIC_ROOT.test(path);\n}\n\n/** Whether a project source module can render public output. */\nexport function isPublicModulePath(path: string): boolean {\n if (!path.includes(\"/\") && SERVER_ROOT_MODULE.test(path)) return false;\n return !isNonPublicPath(path) && !NON_PUBLIC_FILE.test(path);\n}\n\nconst CONTENT_SEGMENTS = new Set([\"content\", \"posts\", \"blog\", \"articles\", \"data\", \"app\"]);\nconst DOCUMENTATION_NAMES = /^(?:readme|agents|claude|changelog|contributing|license|design|strategy)(?:\\.[\\w-]+)?\\.mdx?$/i;\n\n/** Whether a project file is public content: MDX anywhere, Markdown and JSON under content or data. */\nexport function isPublicDocumentPath(path: string): boolean {\n if (isNonPublicPath(path)) return false;\n const name = posix.basename(path);\n if (/\\.mdx$/i.test(path)) return !DOCUMENTATION_NAMES.test(name);\n const inContent = posix.dirname(path).split(\"/\").some((segment) => CONTENT_SEGMENTS.has(segment));\n if (/\\.md$/i.test(path)) return inContent && !DOCUMENTATION_NAMES.test(name);\n return /\\.json$/i.test(path) && inContent && !/(?:^|\\.)schema\\.json$/i.test(name);\n}\n\n// --- matching ----------------------------------------------------------------\n\nconst GLOBAL_PATTERNS = BRANDLAB_IMPLEMENTATION_COPY_PATTERNS.map((pattern) => ({\n pattern,\n global: new RegExp(pattern.source, pattern.flags.includes(\"g\") ? pattern.flags : `${pattern.flags}g`),\n}));\n\n/**\n * The first wording pattern that occurs as a word of prose. Occurrences inside a\n * code token (a Tailwind variant such as placeholder:text-stone-400, a path, a file\n * name, a CSS property or a kebab-case class) or a literal trade phrase (benchtop\n * template) are not implementation wording. Text that is not a copy slot must hold\n * at least two words, so single identifiers never match.\n */\nexport function findImplementationWording(\n text: string,\n options: { singleWord?: boolean } = {},\n): { pattern: RegExp; index: number } | null {\n if (!options.singleWord && !/\\S\\s+\\S/.test(text)) return null;\n for (const { pattern, global } of GLOBAL_PATTERNS) {\n for (const match of text.matchAll(global)) {\n if (isBrandlabTradePhrase(text, match.index, match[0].length)) continue;\n if (/\\s/.test(match[0]) || !isCodeToken(text, match.index, match[0].length)) {\n return { pattern, index: match.index };\n }\n }\n }\n return null;\n}\n\nfunction isCodeToken(text: string, index: number, length: number): boolean {\n let start = index;\n while (start > 0 && !/\\s/.test(text[start - 1]!)) start -= 1;\n let end = index + length;\n while (end < text.length && !/\\s/.test(text[end]!)) end += 1;\n const token = text\n .slice(start, end)\n .replace(/^[(\"'‘“]+/, \"\")\n .replace(/[)\"'’”.,;:!?]+$/, \"\");\n if (/[/\\\\[\\]{}()<>=@#$^|`]/.test(token) || /[:.]/.test(token)) return true;\n return /^-?[a-z0-9]+(?:-[a-z0-9]+)+$/.test(token) && (/\\d/.test(token) || token.split(\"-\").length >= 3);\n}\n\n// --- rendering context -------------------------------------------------------\n\n/** Class, style and variant names never hold copy: className, inputClass, cardStyles, variants. */\nconst CLASS_OR_STYLE_WORDS = new Set([\n \"class\", \"classes\", \"classname\", \"classnames\", \"cls\", \"style\", \"styles\", \"sx\", \"css\", \"tw\", \"variant\",\n \"variants\", \"compoundvariants\",\n]);\nconst CLASS_OR_STYLE_SUFFIX = /[a-z0-9](?:Class|Classes|ClassName|ClassNames|Style|Styles|Variants|Css)$/;\n/** Internal record fields and builders (rationale, evidence, decisions) never render. */\nconst INTERNAL_RECORD_NAME = /^(?:rationales?|evidence|decisions?)$|[a-z0-9](?:Rationales?|Evidence|Decisions?)$/;\n\n/** Names whose values are identifiers, addresses or code rather than copy. */\nconst NON_RENDERING_NAMES = new Set([\n \"id\", \"key\", \"ref\", \"href\", \"src\", \"srcset\", \"sizes\", \"url\", \"path\", \"pathname\", \"slug\", \"route\",\n \"canonical\", \"icon\", \"variant\", \"size\", \"as\", \"type\", \"kind\", \"mode\", \"tone\", \"theme\", \"layout\",\n \"rel\", \"target\", \"method\", \"enctype\", \"pattern\", \"regex\", \"selector\", \"matcher\",\n \"media\", \"strategy\", \"loading\", \"decoding\", \"fetchpriority\", \"crossorigin\", \"referrerpolicy\",\n \"integrity\", \"nonce\", \"viewbox\", \"d\", \"points\", \"transform\", \"fill\", \"stroke\", \"xmlns\",\n \"testid\", \"datatestid\", \"fontfamily\", \"font\", \"locale\", \"timezone\", \"format\", \"env\", \"event\",\n \"eventname\", \"@context\", \"@id\", \"@type\",\n]);\n\n/** Intrinsic element attributes that render text (visibly or to assistive technology). */\nconst RENDERED_INTRINSIC_ATTRIBUTES = new Set([\"alt\", \"title\", \"placeholder\", \"label\", \"content\", \"value\", \"summary\", \"abbr\"]);\nconst RENDERED_ARIA_ATTRIBUTES = new Set([\"aria-label\", \"aria-description\", \"aria-roledescription\", \"aria-valuetext\", \"aria-placeholder\"]);\n/** Attributes that pass through a component without rendering. */\nconst NON_RENDERING_COMPONENT_ATTRIBUTES = new Set([\n \"name\", \"form\", \"htmlfor\", \"for\", \"lang\", \"dir\", \"tabindex\", \"slot\", \"role\", \"autocomplete\", \"inputmode\",\n \"accept\", \"allow\", \"sandbox\", \"width\", \"height\", \"itemprop\", \"itemtype\", \"itemid\", \"property\", \"charset\",\n \"httpequiv\", \"http-equiv\", \"priority\", \"quality\", \"prefetch\", \"scroll\", \"replace\",\n]);\n\n/** Copy slots are checked even when they hold a single word. */\nconst COPY_NAME =\n /^(?:alt|title|label|caption|heading|headline|subheading|subtitle|eyebrow|summary|excerpt|intro|description|text|body|content|question|answer|placeholder|cta|tagline|quote|message|aria-label)$|[a-z0-9](?:Alt|Title|Label|Caption|Heading|Headline|Subtitle|Eyebrow|Summary|Excerpt|Description|Text|Body|Content|Question|Answer|Placeholder|Cta|Tagline|Message)$/;\n\n/** Elements whose children are code, not copy. */\nconst CODE_ELEMENTS = new Set([\"script\", \"style\", \"Script\"]);\n/** Calls whose string arguments are class lists. */\nconst CLASS_UTILITIES = new Set([\"cn\", \"clsx\", \"cx\", \"classNames\", \"classnames\", \"twMerge\", \"twJoin\", \"cva\", \"tv\"]);\n/** Calls whose string arguments never render. */\nconst NON_RENDERING_CALLS =\n /^(?:(?:console|logger|log)\\.\\w+|require(?:\\.resolve)?|fetch|RegExp|Symbol(?:\\.for)?|JSON\\.parse|matchMedia|redirect|permanentRedirect|notFound|invariant|assert\\w*|gtag|(?:NextResponse|Response)\\.(?:redirect|rewrite))$|\\.(?:querySelector(?:All)?|getElementById|getElementsByClassName|closest|matches|matchMedia|addEventListener|removeEventListener|setAttribute|getAttribute|removeAttribute|hasAttribute|toggleAttribute|startsWith|endsWith|includes|indexOf|split|replace|replaceAll|match|matchAll|search|test|join|localeCompare)$|classList\\./;\nconst NON_RENDERING_CONSTRUCTORS = /(?:Error|^URL|^URLSearchParams|^RegExp|^Date|^Headers|^Intl\\.\\w+)$/;\nconst CODE_TAGS = /^(?:css|sql|gql|graphql|keyframes|createGlobalStyle|styled(?:\\.\\w+)?)$/;\nconst COMPARISONS = new Set([\n ts.SyntaxKind.EqualsEqualsEqualsToken, ts.SyntaxKind.ExclamationEqualsEqualsToken,\n ts.SyntaxKind.EqualsEqualsToken, ts.SyntaxKind.ExclamationEqualsToken, ts.SyntaxKind.InKeyword,\n ts.SyntaxKind.InstanceOfKeyword,\n]);\n\nfunction nameRenders(name: string): boolean {\n const lower = name.toLowerCase();\n return !CLASS_OR_STYLE_WORDS.has(lower) && !CLASS_OR_STYLE_SUFFIX.test(name) && !INTERNAL_RECORD_NAME.test(name) &&\n !NON_RENDERING_NAMES.has(lower) && !lower.startsWith(\"data-\");\n}\n\nfunction attributeRenders(tag: string, attribute: string): boolean {\n if (attribute.startsWith(\"aria-\")) return RENDERED_ARIA_ATTRIBUTES.has(attribute);\n if (/^on[A-Z]/.test(attribute) || !nameRenders(attribute)) return false;\n if (/^[a-z]/.test(tag) && !tag.includes(\".\")) return RENDERED_INTRINSIC_ATTRIBUTES.has(attribute);\n return !NON_RENDERING_COMPONENT_ATTRIBUTES.has(attribute.toLowerCase());\n}\n\ninterface Slot {\n where: string;\n singleWord: boolean;\n}\n\nfunction entityName(node: ts.Node): string | null {\n if (ts.isIdentifier(node) || ts.isPrivateIdentifier(node)) return node.text;\n if (ts.isStringLiteralLike(node) || ts.isNumericLiteral(node)) return node.text;\n if (ts.isPropertyAccessExpression(node)) {\n const object = entityName(node.expression);\n return object === null ? node.name.text : `${object}.${node.name.text}`;\n }\n if (ts.isCallExpression(node)) return entityName(node.expression);\n if (ts.isJsxNamespacedName(node)) return `${node.namespace.text}:${node.name.text}`;\n if (node.kind === ts.SyntaxKind.ThisKeyword) return \"this\";\n return null;\n}\n\nfunction lastName(name: string): string {\n return name.slice(name.lastIndexOf(\".\") + 1);\n}\n\n/** Where a string literal renders, or null when its position never renders. */\nfunction literalSlot(node: ts.Node): Slot | null {\n let slot: Slot | undefined;\n let child: ts.Node = node;\n for (let parent = node.parent; parent && !ts.isSourceFile(parent); child = parent, parent = parent.parent) {\n if (ts.isTypeNode(parent) || ts.isEnumMember(parent) || ts.isComputedPropertyName(parent)) return null;\n if (\n ts.isImportDeclaration(parent) || ts.isExportDeclaration(parent) ||\n ts.isExternalModuleReference(parent) || ts.isImportEqualsDeclaration(parent) ||\n ts.isThrowStatement(parent)\n ) return null;\n if (ts.isExpressionStatement(parent) && child === node) return null;\n if (ts.isCaseClause(parent) && parent.expression === child) return null;\n if (ts.isElementAccessExpression(parent) && parent.argumentExpression === child) return null;\n if (ts.isPropertyAssignment(parent) || ts.isPropertyDeclaration(parent)) {\n if (parent.name === child) return null;\n const key = entityName(parent.name);\n if (key !== null) {\n if (!nameRenders(key)) return null;\n slot ??= { where: `the ${key} field`, singleWord: COPY_NAME.test(key) };\n }\n } else if (ts.isJsxAttribute(parent)) {\n const attribute = entityName(parent.name) ?? \"\";\n const element = parent.parent.parent;\n if (!attributeRenders(entityName(element.tagName) ?? \"\", attribute)) return null;\n slot ??= { where: `the ${attribute} attribute`, singleWord: attribute === \"alt\" || COPY_NAME.test(attribute) };\n } else if (ts.isJsxElement(parent)) {\n if (CODE_ELEMENTS.has(entityName(parent.openingElement.tagName) ?? \"\")) return null;\n slot ??= { where: \"JSX text\", singleWord: true };\n } else if (ts.isJsxFragment(parent)) {\n slot ??= { where: \"JSX text\", singleWord: true };\n } else if (ts.isCallExpression(parent) || ts.isNewExpression(parent)) {\n if (parent.expression === child) continue;\n if (parent.expression.kind === ts.SyntaxKind.ImportKeyword) return null;\n const callee = entityName(parent.expression) ?? \"\";\n const skipped = ts.isNewExpression(parent)\n ? NON_RENDERING_CONSTRUCTORS.test(callee)\n : CLASS_UTILITIES.has(lastName(callee)) || NON_RENDERING_CALLS.test(callee) ||\n INTERNAL_RECORD_NAME.test(lastName(callee));\n if (skipped) return null;\n slot ??= { where: \"a rendered string\", singleWord: false };\n } else if (ts.isTaggedTemplateExpression(parent)) {\n if (CODE_TAGS.test(entityName(parent.tag) ?? \"\")) return null;\n } else if (ts.isBinaryExpression(parent)) {\n if (COMPARISONS.has(parent.operatorToken.kind)) return null;\n if (parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && parent.right === child) {\n const target = entityName(parent.left);\n if (target !== null && !nameRenders(lastName(target))) return null;\n }\n } else if (\n ts.isVariableDeclaration(parent) || ts.isParameter(parent) || ts.isBindingElement(parent) ||\n ts.isFunctionDeclaration(parent) || ts.isMethodDeclaration(parent)\n ) {\n const name = parent.name && ts.isIdentifier(parent.name) ? parent.name.text : null;\n if (name !== null && !nameRenders(name)) return null;\n if (name !== null && !ts.isFunctionDeclaration(parent) && !ts.isMethodDeclaration(parent)) {\n slot ??= { where: `the ${name} value`, singleWord: COPY_NAME.test(name) };\n }\n }\n }\n return slot ?? { where: \"a rendered string\", singleWord: false };\n}\n\nfunction insideCodeElement(node: ts.Node): boolean {\n for (let parent = node.parent; parent && !ts.isSourceFile(parent); parent = parent.parent) {\n if (ts.isJsxElement(parent) && CODE_ELEMENTS.has(entityName(parent.openingElement.tagName) ?? \"\")) return true;\n }\n return false;\n}\n\n/** Tags inside a string (rich text) do not render; blank them without moving offsets. */\nfunction blankTags(text: string): string {\n return text.replace(/<[^<>]*>/g, (tag) => \" \".repeat(tag.length));\n}\n\n/** Implementation wording in the rendered copy of a TypeScript, JavaScript or JSON source. */\nexport function findWordingInSource(source: ts.SourceFile): PublicCopyFinding[] {\n const text = source.text;\n const findings: PublicCopyFinding[] = [];\n const report = (value: string, offsets: (index: number) => number, slot: Slot) => {\n const match = findImplementationWording(value, { singleWord: slot.singleWord });\n if (match) findings.push({ line: lineAt(text, offsets(match.index)), where: slot.where, pattern: match.pattern });\n };\n const visit = (node: ts.Node) => {\n if (ts.isJsxText(node)) {\n if (!node.containsOnlyTriviaWhiteSpaces && !insideCodeElement(node)) {\n const start = node.end - node.text.length;\n report(node.text, (index) => start + index, { where: \"JSX text\", singleWord: true });\n }\n return;\n }\n if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n const slot = literalSlot(node);\n const start = node.getStart(source) + 1;\n if (slot) report(blankTags(node.text), (index) => start + index, slot);\n return;\n }\n if (ts.isTemplateExpression(node)) {\n const slot = literalSlot(node);\n if (slot) {\n const parts = [node.head, ...node.templateSpans.map((span) => span.literal)];\n const starts: number[] = [];\n let value = \"\";\n for (const [position, part] of parts.entries()) {\n if (position > 0) value += \" \";\n starts.push(value.length);\n value += part.text;\n }\n report(blankTags(value), (index) => {\n let position = starts.length - 1;\n while (position > 0 && starts[position]! > index) position -= 1;\n return parts[position]!.getStart(source) + 1 + (index - starts[position]!);\n }, slot);\n }\n }\n ts.forEachChild(node, visit);\n };\n visit(source);\n return findings;\n}\n\n/** Parse a JSON document with parent links so data values share the module rules. */\nexport function parseJsonSource(path: string, text: string): ts.SourceFile {\n return ts.createSourceFile(path, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.JSON);\n}\n\n// --- MDX and Markdown --------------------------------------------------------\n\n/** Frontmatter keys whose values are identifiers, dates or addresses. */\nconst NON_RENDERING_FRONTMATTER = /^(?:slug|date|datePublished|dateModified|published|publishedAt|updated|updatedAt|lastModified|draft|id|image|images|cover|coverImage|thumbnail|ogImage|src|href|url|canonical|layout|template|redirect|redirectFrom|aliases|order|weight|featured|noindex|robots|readingTime)$/i;\n\n/** Implementation wording in the rendered text of an MDX or Markdown document. */\nexport function findWordingInMarkdown(text: string): PublicCopyFinding[] {\n const findings: PublicCopyFinding[] = [];\n const frontmatter = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---[ \\t]*(?:\\r?\\n|$)/.exec(text);\n let bodyStart = 0;\n if (frontmatter) {\n bodyStart = frontmatter[0].length;\n let lastKey: string | null = null;\n let offset = text.indexOf(\"\\n\") + 1;\n for (const line of frontmatter[1]!.split(\"\\n\")) {\n const entry = /^\\s*(?:-\\s+)?(?:([\"']?)([\\w@$.-]+)\\1\\s*:(?=\\s|$))?\\s*(.*?)\\s*$/.exec(line.replace(/\\r$/, \"\"))!;\n if (entry[2]) lastKey = entry[2];\n const key = entry[2] ?? lastKey;\n const value = frontmatterValue(entry[3]!);\n if (key !== null && value !== \"\" && !NON_RENDERING_FRONTMATTER.test(key) && nameRenders(key)) {\n const match = findImplementationWording(value, { singleWord: COPY_NAME.test(key) });\n if (match) findings.push({ line: lineAt(text, offset), where: `the ${key} frontmatter`, pattern: match.pattern });\n }\n offset += line.length + 1;\n }\n }\n const { prose, esm } = renderedMarkdownText(text, bodyStart);\n if (esm.trim() !== \"\") {\n // ESM such as `export const metadata = { ... }` renders as page metadata.\n findings.push(...findWordingInSource(ts.createSourceFile(\"content.tsx\", esm, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX)));\n }\n let offset = 0;\n for (const line of prose.split(\"\\n\")) {\n const match = findImplementationWording(line, { singleWord: true });\n if (match && offset + match.index >= bodyStart) {\n findings.push({ line: lineAt(text, offset + match.index), where: \"the content\", pattern: match.pattern });\n }\n offset += line.length + 1;\n }\n return findings.sort((left, right) => left.line - right.line);\n}\n\n/** A frontmatter scalar or inline list as its rendered words (\"\" for block indicators and comments). */\nfunction frontmatterValue(raw: string): string {\n if (/^[|>][-+]?\\d*$/.test(raw) || raw.startsWith(\"#\")) return \"\";\n const list = /^\\[(.*)\\]$/.exec(raw);\n if (list) return list[1]!.replace(/[\"']/g, \" \");\n return raw.replace(/^([\"'])(.*)\\1$/, \"$2\");\n}\n\n/**\n * The document with everything that does not render as words blanked in place\n * (offsets and lines unchanged): frontmatter, code, ESM, comments, expressions,\n * tag syntax (rendered attribute values stay), link targets and Markdown markers.\n * The ESM blocks come back separately, blanked the same way, to be read as source.\n */\nfunction renderedMarkdownText(text: string, bodyStart: number): { prose: string; esm: string } {\n const out = text.split(\"\");\n const esmOut = text.replace(/[^\\n]/g, \" \").split(\"\");\n const blank = (from: number, to: number) => {\n for (let index = Math.max(from, 0); index < Math.min(to, out.length); index += 1) {\n if (out[index] !== \"\\n\") out[index] = \" \";\n }\n };\n blank(0, bodyStart);\n\n // Fenced code and ESM blocks, line by line.\n let fence: string | null = null;\n let esm = false;\n let offset = bodyStart;\n for (const line of text.slice(bodyStart).split(\"\\n\")) {\n const end = offset + line.length;\n const marker = /^ {0,3}(`{3,}|~{3,})/.exec(line)?.[1];\n if (fence !== null) {\n blank(offset, end);\n if (marker && marker[0] === fence[0] && marker.length >= fence.length && line.trim() === marker) fence = null;\n } else if (marker) {\n blank(offset, end);\n fence = marker;\n } else if (esm || /^(?:import|export)\\b/.test(line)) {\n for (let index = offset; index < end; index += 1) esmOut[index] = text[index]!;\n blank(offset, end);\n esm = line.trim() !== \"\";\n }\n offset = end + 1;\n }\n\n // Comments, expressions, inline code and tags.\n const skipBraces = (from: number): number => {\n let depth = 0;\n for (let index = from; index < text.length; index += 1) {\n const char = out[index];\n if (char === \"{\") depth += 1;\n else if (char === \"}\" && --depth === 0) return index + 1;\n }\n return -1;\n };\n let index = bodyStart;\n while (index < out.length) {\n const char = out[index]!;\n if (char === \"\\\\\" && index + 1 < out.length && out[index + 1] !== \"\\n\") {\n blank(index, index + 1);\n index += 2;\n } else if (char === \"`\") {\n let run = 1;\n while (out[index + run] === \"`\") run += 1;\n const close = text.indexOf(\"`\".repeat(run), index + run);\n if (close === -1) index += run;\n else {\n blank(index, close + run);\n index = close + run;\n }\n } else if (char === \"{\") {\n const end = skipBraces(index);\n if (end === -1) index += 1;\n else {\n blank(index, end);\n index = end;\n }\n } else if (char === \"<\" && text.startsWith(\"<!--\", index)) {\n const close = text.indexOf(\"-->\", index + 4);\n const end = close === -1 ? text.length : close + 3;\n blank(index, end);\n index = end;\n } else if (char === \"<\" && /[A-Za-z/]/.test(out[index + 1] ?? \"\")) {\n const end = blankTag(text, out, index, blank, skipBraces);\n index = end === -1 ? index + 1 : end;\n } else {\n index += 1;\n }\n }\n\n // Markdown syntax: reference definitions, link targets and markers.\n let rendered = out.join(\"\");\n rendered = rendered.replace(/^ {0,3}\\[[^\\]\\n]+\\]:[^\\n]*$/gm, (line) => \" \".repeat(line.length));\n rendered = rendered.replace(/(!?\\[)([^\\]\\n]*)(\\]\\([^)\\n]*\\)|\\]\\[[^\\]\\n]*\\])/g, (_match, open: string, label: string, target: string) =>\n `${\" \".repeat(open.length)}${label}${\" \".repeat(target.length)}`);\n rendered = rendered.replace(/[*~#>|]/g, \" \").replace(/(?<!\\w)_+|_+(?!\\w)/g, (match) => \" \".repeat(match.length));\n return { prose: rendered, esm: esmOut.join(\"\") };\n}\n\n/** Blank one JSX or HTML tag in place, keeping rendered attribute values; -1 if it is not a tag. */\nfunction blankTag(\n text: string,\n out: string[],\n start: number,\n blank: (from: number, to: number) => void,\n skipBraces: (from: number) => number,\n): number {\n const name = /^<\\/?([A-Za-z][\\w.:-]*)/.exec(text.slice(start, start + 200));\n if (!name) return -1;\n const tag = name[1]!;\n let index = start + name[0].length;\n const keep: [number, number][] = [];\n while (index < text.length) {\n while (/\\s/.test(text[index] ?? \"\")) {\n if (text.startsWith(\"\\n\\n\", index)) return -1;\n index += 1;\n }\n if (text.startsWith(\"/>\", index)) {\n index += 2;\n break;\n }\n if (text[index] === \">\") {\n index += 1;\n break;\n }\n if (text[index] === \"{\") {\n const end = skipBraces(index);\n if (end === -1) return -1;\n index = end;\n continue;\n }\n const attribute = /^[^\\s=>/{}]+/.exec(text.slice(index, index + 100))?.[0];\n if (!attribute) return -1;\n index += attribute.length;\n while (text[index] === \" \" || text[index] === \"\\t\") index += 1;\n if (text[index] !== \"=\") continue;\n index += 1;\n while (text[index] === \" \" || text[index] === \"\\t\") index += 1;\n const quote = text[index];\n if (quote === '\"' || quote === \"'\") {\n const close = text.indexOf(quote, index + 1);\n if (close === -1) return -1;\n if (attributeRenders(tag, attribute)) keep.push([index + 1, close]);\n index = close + 1;\n } else if (quote === \"{\") {\n const end = skipBraces(index);\n if (end === -1) return -1;\n index = end;\n } else {\n const value = /^[^\\s>]+/.exec(text.slice(index))?.[0] ?? \"\";\n index += value.length;\n }\n }\n const saved = keep.map(([from, to]) => out.slice(from, to));\n blank(start, index);\n keep.forEach(([from], position) => {\n saved[position]!.forEach((char, offset) => {\n out[from + offset] = char;\n });\n });\n return index;\n}\n"]}