pagegraph 0.12.0 → 0.13.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.
- package/README.md +277 -25
- package/dist/audit.d.ts +2 -2
- package/dist/audit.js +4 -4
- package/dist/build-only/audit.js +1 -1
- package/dist/build-only/claims.d.ts +1 -0
- package/dist/build-only/claims.js +6 -0
- package/dist/build-only/claims.js.map +1 -0
- package/dist/build-only/config.js +1 -1
- package/dist/build-only/oxlint.d.ts +1 -0
- package/dist/build-only/oxlint.js +6 -0
- package/dist/build-only/oxlint.js.map +1 -0
- package/dist/build-only/tanstack-start.js +1 -1
- package/dist/build-only/vite.js +1 -1
- package/dist/{checks-uZk5Em9A.js → checks-BS-aDXB_.js} +2 -2
- package/dist/checks-BS-aDXB_.js.map +1 -0
- package/dist/claims-Bch7Lxlo.d.ts +92 -0
- package/dist/claims-Bv7voeEV.js +431 -0
- package/dist/claims-Bv7voeEV.js.map +1 -0
- package/dist/claims.d.ts +94 -0
- package/dist/claims.js +2 -0
- package/dist/cli.js +10095 -8318
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +4 -24
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/{content-kcEnQdfi.js → content-CHd0X4s6.js} +2 -2
- package/dist/{content-kcEnQdfi.js.map → content-CHd0X4s6.js.map} +1 -1
- package/dist/{content-B1cPtL8b.d.ts → content-DgNr7apS.d.ts} +4 -5
- package/dist/declare-D5o7hwmv.js.map +1 -1
- package/dist/document-CztEu3Vd.d.ts +109 -0
- package/dist/document-Dvemcv7V.js +379 -0
- package/dist/document-Dvemcv7V.js.map +1 -0
- package/dist/facts-1OKclPOk.js +115 -0
- package/dist/facts-1OKclPOk.js.map +1 -0
- package/dist/{declare-DVgdEdOL.d.ts → graph-D1PIndsC.d.ts} +117 -6
- package/dist/{graph-Bcsourlv.js → graph-DMNOLXLu.js} +23 -13
- package/dist/graph-DMNOLXLu.js.map +1 -0
- package/dist/index-C5w9ripz.d.ts +204 -0
- package/dist/index.d.ts +6 -160
- package/dist/index.js +37 -5
- package/dist/index.js.map +1 -1
- package/dist/inline-BbS93GAT.js +682 -0
- package/dist/inline-BbS93GAT.js.map +1 -0
- package/dist/llms-Dhr_5u2O.js +19 -0
- package/dist/llms-Dhr_5u2O.js.map +1 -0
- package/dist/markdown-C6dRE9zD.js +168 -0
- package/dist/markdown-C6dRE9zD.js.map +1 -0
- package/dist/markdown-path-lJB9BAVZ.js +6 -0
- package/dist/markdown-path-lJB9BAVZ.js.map +1 -0
- package/dist/{message-DT_CjUdt.js → message-CuBjgZ74.js} +2 -2
- package/dist/{message-DT_CjUdt.js.map → message-CuBjgZ74.js.map} +1 -1
- package/dist/oxlint.d.ts +58 -0
- package/dist/oxlint.js +202 -0
- package/dist/oxlint.js.map +1 -0
- package/dist/page-heads-BfjWQvau.d.ts +108 -0
- package/dist/{page-heads-6y-CARRQ.js → page-heads-BgbaIjj9.js} +3 -3
- package/dist/page-heads-BgbaIjj9.js.map +1 -0
- package/dist/{projections-DeEFe7XT.d.ts → projections-Bk-qOOsR.d.ts} +2 -2
- package/dist/react.d.ts +3 -2
- package/dist/react.js +2 -1
- package/dist/react.js.map +1 -1
- package/dist/tanstack-start/index.d.ts +29 -13
- package/dist/tanstack-start/index.js +391 -42
- package/dist/tanstack-start/index.js.map +1 -1
- package/dist/tanstack-start/markdown.d.ts +12 -0
- package/dist/tanstack-start/markdown.js +149 -0
- package/dist/tanstack-start/markdown.js.map +1 -0
- package/dist/tanstack-start/prerender-worker.d.ts +2 -0
- package/dist/tanstack-start/prerender-worker.js +7 -0
- package/dist/tanstack-start/prerender-worker.js.map +1 -0
- package/dist/tanstack-start/react.d.ts +7 -0
- package/dist/tanstack-start/react.js +12 -0
- package/dist/tanstack-start/react.js.map +1 -0
- package/dist/tanstack-start/server.d.ts +9 -3
- package/dist/tanstack-start/server.js +26 -2
- package/dist/tanstack-start/server.js.map +1 -1
- package/dist/{vite-graph-loader-01p1WxEq.js → vite-graph-loader-CsGiYNWE.js} +6 -5
- package/dist/vite-graph-loader-CsGiYNWE.js.map +1 -0
- package/dist/vite-graph-loader-DZCwejuJ.d.ts +133 -0
- package/package.json +44 -3
- package/dist/checks-uZk5Em9A.js.map +0 -1
- package/dist/graph-Bcsourlv.js.map +0 -1
- package/dist/graph-BxCY90vq.d.ts +0 -104
- package/dist/graph-CBIY71w6.d.ts +0 -57
- package/dist/page-heads-6y-CARRQ.js.map +0 -1
- package/dist/page-heads-DNkjMUEN.d.ts +0 -21
- package/dist/vite-graph-loader-01p1WxEq.js.map +0 -1
- package/dist/vite-graph-loader-Btgjz5RH.d.ts +0 -56
package/dist/oxlint.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
//#region src/oxlint/no-bare-text.js
|
|
2
|
+
function importedDocumentNames(program) {
|
|
3
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
4
|
+
const suppressNames = /* @__PURE__ */ new Set();
|
|
5
|
+
let runtimeImport = false;
|
|
6
|
+
for (const declaration of program.body) {
|
|
7
|
+
if (declaration.type !== "ImportDeclaration" || declaration.source.value !== "pagegraph/react" || declaration.importKind === "type") continue;
|
|
8
|
+
if (declaration.specifiers.length === 0) runtimeImport = true;
|
|
9
|
+
for (const specifier of declaration.specifiers) if (specifier.type === "ImportSpecifier" && specifier.importKind !== "type") {
|
|
10
|
+
const imported = specifier.imported.name ?? specifier.imported.value;
|
|
11
|
+
if ([
|
|
12
|
+
"T",
|
|
13
|
+
"Title",
|
|
14
|
+
"ForHumans"
|
|
15
|
+
].includes(imported)) suppressNames.add(specifier.local.name);
|
|
16
|
+
runtimeImport = true;
|
|
17
|
+
} else if (specifier.type === "ImportNamespaceSpecifier") {
|
|
18
|
+
namespaces.add(specifier.local.name);
|
|
19
|
+
runtimeImport = true;
|
|
20
|
+
} else if (specifier.type === "ImportDefaultSpecifier") runtimeImport = true;
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
namespaces,
|
|
24
|
+
suppressNames,
|
|
25
|
+
runtimeImport
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function jsxName(node) {
|
|
29
|
+
if (node.type === "JSXIdentifier") return [node.name];
|
|
30
|
+
if (node.type === "JSXMemberExpression") return [...jsxName(node.object), node.property.name];
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
function matchesFiles(filename, files) {
|
|
34
|
+
if (!files?.length) return true;
|
|
35
|
+
const normalized = filename.replaceAll("\\", "/");
|
|
36
|
+
return files.some((pattern) => {
|
|
37
|
+
const escaped = pattern.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
38
|
+
return new RegExp(`(?:^|/)${escaped.replaceAll("**", "§").replaceAll("*", "[^/]*").replaceAll("§", ".*")}$`).test(normalized);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function* literalLabels(expression, stringsOnly = false) {
|
|
42
|
+
switch (expression.type) {
|
|
43
|
+
case "Literal":
|
|
44
|
+
if (typeof expression.value === "string" || !stringsOnly && typeof expression.value === "number") yield expression;
|
|
45
|
+
break;
|
|
46
|
+
case "ConditionalExpression":
|
|
47
|
+
yield* literalLabels(expression.consequent, stringsOnly);
|
|
48
|
+
yield* literalLabels(expression.alternate, stringsOnly);
|
|
49
|
+
break;
|
|
50
|
+
case "LogicalExpression":
|
|
51
|
+
if (expression.operator !== "&&") yield* literalLabels(expression.left, stringsOnly);
|
|
52
|
+
yield* literalLabels(expression.right, stringsOnly);
|
|
53
|
+
break;
|
|
54
|
+
case "BinaryExpression":
|
|
55
|
+
if (expression.operator === "+") {
|
|
56
|
+
yield* literalLabels(expression.left, true);
|
|
57
|
+
yield* literalLabels(expression.right, true);
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
case "TemplateLiteral":
|
|
61
|
+
if (expression.quasis.some((part) => part.value.raw.trim())) yield expression;
|
|
62
|
+
for (const interpolation of expression.expressions) yield* literalLabels(interpolation, true);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
var no_bare_text_default = {
|
|
66
|
+
meta: {
|
|
67
|
+
type: "problem",
|
|
68
|
+
docs: { description: "Require customer-facing text to use pagegraph primitives." },
|
|
69
|
+
schema: [{
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: { files: {
|
|
72
|
+
type: "array",
|
|
73
|
+
items: { type: "string" }
|
|
74
|
+
} },
|
|
75
|
+
additionalProperties: false
|
|
76
|
+
}]
|
|
77
|
+
},
|
|
78
|
+
create(context) {
|
|
79
|
+
const files = context.options[0]?.files;
|
|
80
|
+
if (!matchesFiles(context.filename, files)) return {};
|
|
81
|
+
let active = false;
|
|
82
|
+
let names;
|
|
83
|
+
const suppressedRanges = [];
|
|
84
|
+
const attributeExpressions = /* @__PURE__ */ new Set();
|
|
85
|
+
const report = (node) => context.report({
|
|
86
|
+
node,
|
|
87
|
+
message: "Wrap customer-facing text in T, Title, or ForHumans."
|
|
88
|
+
});
|
|
89
|
+
const isSuppressed = (node) => suppressedRanges.some(([start, end]) => node.start >= start && node.end <= end);
|
|
90
|
+
return {
|
|
91
|
+
Program(node) {
|
|
92
|
+
const imports = importedDocumentNames(node);
|
|
93
|
+
active = imports.runtimeImport;
|
|
94
|
+
names = imports;
|
|
95
|
+
},
|
|
96
|
+
JSXElement(node) {
|
|
97
|
+
const parts = jsxName(node.openingElement.name);
|
|
98
|
+
const suppressed = parts.length === 1 && names.suppressNames.has(parts[0]) || parts.length === 2 && names.namespaces.has(parts[0]) && [
|
|
99
|
+
"T",
|
|
100
|
+
"Title",
|
|
101
|
+
"ForHumans"
|
|
102
|
+
].includes(parts[1]);
|
|
103
|
+
if (active && suppressed) suppressedRanges.push([node.start, node.end]);
|
|
104
|
+
},
|
|
105
|
+
JSXText(node) {
|
|
106
|
+
if (active && !isSuppressed(node) && node.value.trim()) report(node);
|
|
107
|
+
},
|
|
108
|
+
JSXAttribute(node) {
|
|
109
|
+
if (active && node.value?.type === "JSXExpressionContainer") attributeExpressions.add(node.value.start);
|
|
110
|
+
},
|
|
111
|
+
JSXExpressionContainer(node) {
|
|
112
|
+
if (active && !attributeExpressions.has(node.start) && !isSuppressed(node)) for (const label of literalLabels(node.expression)) report(label);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
//#endregion
|
|
118
|
+
//#region src/oxlint/t-children.js
|
|
119
|
+
const INLINE_TAGS = /* @__PURE__ */ new Set([
|
|
120
|
+
"em",
|
|
121
|
+
"strong",
|
|
122
|
+
"a",
|
|
123
|
+
"code",
|
|
124
|
+
"br"
|
|
125
|
+
]);
|
|
126
|
+
function importedTNames(program) {
|
|
127
|
+
const named = /* @__PURE__ */ new Set();
|
|
128
|
+
const facts = /* @__PURE__ */ new Set();
|
|
129
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
130
|
+
for (const declaration of program.body) {
|
|
131
|
+
if (declaration.type !== "ImportDeclaration" || declaration.source.value !== "pagegraph/react" || declaration.importKind === "type") continue;
|
|
132
|
+
for (const specifier of declaration.specifiers) if (specifier.type === "ImportSpecifier" && specifier.importKind !== "type") {
|
|
133
|
+
const imported = specifier.imported.name ?? specifier.imported.value;
|
|
134
|
+
if (imported === "T" || imported === "Title") named.add(specifier.local.name);
|
|
135
|
+
if (imported === "Fact") facts.add(specifier.local.name);
|
|
136
|
+
} else if (specifier.type === "ImportNamespaceSpecifier") namespaces.add(specifier.local.name);
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
named,
|
|
140
|
+
facts,
|
|
141
|
+
namespaces
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function parts(node) {
|
|
145
|
+
if (node.type === "JSXIdentifier") return [node.name];
|
|
146
|
+
if (node.type === "JSXMemberExpression") return [...parts(node.object), node.property.name];
|
|
147
|
+
return [];
|
|
148
|
+
}
|
|
149
|
+
function isT(node, names) {
|
|
150
|
+
const path = parts(node);
|
|
151
|
+
return path.length === 1 && names.named.has(path[0]) || path.length === 2 && names.namespaces.has(path[0]) && ["T", "Title"].includes(path[1]);
|
|
152
|
+
}
|
|
153
|
+
function allowedElement(node, names) {
|
|
154
|
+
const path = parts(node);
|
|
155
|
+
if (path.length === 1 && INLINE_TAGS.has(path[0])) return true;
|
|
156
|
+
if (path.length === 1 && names.facts.has(path[0])) return true;
|
|
157
|
+
return path.length === 2 && names.namespaces.has(path[0]) && path[1] === "Fact";
|
|
158
|
+
}
|
|
159
|
+
//#endregion
|
|
160
|
+
//#region src/oxlint/index.js
|
|
161
|
+
var oxlint_default = {
|
|
162
|
+
meta: { name: "pagegraph" },
|
|
163
|
+
rules: {
|
|
164
|
+
"no-bare-text": no_bare_text_default,
|
|
165
|
+
"t-children": {
|
|
166
|
+
meta: {
|
|
167
|
+
type: "problem",
|
|
168
|
+
docs: { description: "Restrict T and Title children to plain text and approved inline content." }
|
|
169
|
+
},
|
|
170
|
+
create(context) {
|
|
171
|
+
const stack = [];
|
|
172
|
+
let names;
|
|
173
|
+
return {
|
|
174
|
+
Program(node) {
|
|
175
|
+
names = importedTNames(node);
|
|
176
|
+
},
|
|
177
|
+
JSXElement(node) {
|
|
178
|
+
const parent = stack.at(-1);
|
|
179
|
+
if (parent?.insideT && !allowedElement(node.openingElement.name, names)) context.report({
|
|
180
|
+
node: node.openingElement.name,
|
|
181
|
+
message: "T and Title accept text, em, strong, a, code, br, and Fact only."
|
|
182
|
+
});
|
|
183
|
+
stack.push({ insideT: isT(node.openingElement.name, names) || Boolean(parent?.insideT) });
|
|
184
|
+
},
|
|
185
|
+
"JSXElement:exit"() {
|
|
186
|
+
stack.pop();
|
|
187
|
+
},
|
|
188
|
+
JSXFragment(node) {
|
|
189
|
+
if (stack.at(-1)?.insideT) context.report({
|
|
190
|
+
node,
|
|
191
|
+
message: "T and Title accept text, em, strong, a, code, br, and Fact only; fragments are not supported."
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
//#endregion
|
|
200
|
+
export { oxlint_default as default };
|
|
201
|
+
|
|
202
|
+
//# sourceMappingURL=oxlint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oxlint.js","names":["noBareText","tChildren"],"sources":["../src/oxlint/no-bare-text.js","../src/oxlint/t-children.js","../src/oxlint/index.js"],"sourcesContent":["function importedDocumentNames(program) {\n const namespaces = new Set();\n const suppressNames = new Set();\n let runtimeImport = false;\n for (const declaration of program.body) {\n if (\n declaration.type !== \"ImportDeclaration\" ||\n declaration.source.value !== \"pagegraph/react\" ||\n declaration.importKind === \"type\"\n )\n continue;\n if (declaration.specifiers.length === 0) runtimeImport = true;\n for (const specifier of declaration.specifiers) {\n if (specifier.type === \"ImportSpecifier\" && specifier.importKind !== \"type\") {\n const imported = specifier.imported.name ?? specifier.imported.value;\n if ([\"T\", \"Title\", \"ForHumans\"].includes(imported)) suppressNames.add(specifier.local.name);\n runtimeImport = true;\n } else if (specifier.type === \"ImportNamespaceSpecifier\") {\n namespaces.add(specifier.local.name);\n runtimeImport = true;\n } else if (specifier.type === \"ImportDefaultSpecifier\") runtimeImport = true;\n }\n }\n return { namespaces, suppressNames, runtimeImport };\n}\n\nfunction jsxName(node) {\n if (node.type === \"JSXIdentifier\") return [node.name];\n if (node.type === \"JSXMemberExpression\") return [...jsxName(node.object), node.property.name];\n return [];\n}\n\nfunction matchesFiles(filename, files) {\n if (!files?.length) return true;\n const normalized = filename.replaceAll(\"\\\\\", \"/\");\n return files.some((pattern) => {\n const escaped = pattern.replace(/[|\\\\{}()[\\]^$+?.]/g, \"\\\\$&\");\n const regex = new RegExp(\n `(?:^|/)${escaped.replaceAll(\"**\", \"§\").replaceAll(\"*\", \"[^/]*\").replaceAll(\"§\", \".*\")}$`,\n );\n return regex.test(normalized);\n });\n}\n\nfunction* literalLabels(expression, stringsOnly = false) {\n switch (expression.type) {\n case \"Literal\":\n if (\n typeof expression.value === \"string\" ||\n (!stringsOnly && typeof expression.value === \"number\")\n )\n yield expression;\n break;\n case \"ConditionalExpression\":\n yield* literalLabels(expression.consequent, stringsOnly);\n yield* literalLabels(expression.alternate, stringsOnly);\n break;\n case \"LogicalExpression\":\n // A truthy string on the left of && is only a guard, never the returned child.\n if (expression.operator !== \"&&\") yield* literalLabels(expression.left, stringsOnly);\n yield* literalLabels(expression.right, stringsOnly);\n break;\n case \"BinaryExpression\":\n // Comparisons and numeric arithmetic consume their literals rather than displaying them.\n if (expression.operator === \"+\") {\n yield* literalLabels(expression.left, true);\n yield* literalLabels(expression.right, true);\n }\n break;\n case \"TemplateLiteral\":\n if (expression.quasis.some((part) => part.value.raw.trim())) yield expression;\n for (const interpolation of expression.expressions) yield* literalLabels(interpolation, true);\n break;\n }\n}\n\nexport default {\n meta: {\n type: \"problem\",\n docs: { description: \"Require customer-facing text to use pagegraph primitives.\" },\n schema: [\n {\n type: \"object\",\n properties: { files: { type: \"array\", items: { type: \"string\" } } },\n additionalProperties: false,\n },\n ],\n },\n create(context) {\n const files = context.options[0]?.files;\n if (!matchesFiles(context.filename, files)) return {};\n let active = false;\n let names;\n const suppressedRanges = [];\n const attributeExpressions = new Set();\n const report = (node) =>\n context.report({ node, message: \"Wrap customer-facing text in T, Title, or ForHumans.\" });\n const isSuppressed = (node) =>\n suppressedRanges.some(([start, end]) => node.start >= start && node.end <= end);\n return {\n Program(node) {\n const imports = importedDocumentNames(node);\n active = imports.runtimeImport;\n names = imports;\n },\n JSXElement(node) {\n const parts = jsxName(node.openingElement.name);\n const suppressed =\n (parts.length === 1 && names.suppressNames.has(parts[0])) ||\n (parts.length === 2 &&\n names.namespaces.has(parts[0]) &&\n [\"T\", \"Title\", \"ForHumans\"].includes(parts[1]));\n if (active && suppressed) suppressedRanges.push([node.start, node.end]);\n },\n JSXText(node) {\n if (active && !isSuppressed(node) && node.value.trim()) report(node);\n },\n JSXAttribute(node) {\n // Exempt the prop value itself; nested JSX has its own children to check.\n if (active && node.value?.type === \"JSXExpressionContainer\")\n attributeExpressions.add(node.value.start);\n },\n JSXExpressionContainer(node) {\n if (active && !attributeExpressions.has(node.start) && !isSuppressed(node))\n for (const label of literalLabels(node.expression)) report(label);\n },\n };\n },\n};\n","const INLINE_TAGS = new Set([\"em\", \"strong\", \"a\", \"code\", \"br\"]);\n\nfunction importedTNames(program) {\n const named = new Set();\n const facts = new Set();\n const namespaces = new Set();\n for (const declaration of program.body) {\n if (\n declaration.type !== \"ImportDeclaration\" ||\n declaration.source.value !== \"pagegraph/react\" ||\n declaration.importKind === \"type\"\n )\n continue;\n for (const specifier of declaration.specifiers) {\n if (specifier.type === \"ImportSpecifier\" && specifier.importKind !== \"type\") {\n const imported = specifier.imported.name ?? specifier.imported.value;\n if (imported === \"T\" || imported === \"Title\") named.add(specifier.local.name);\n if (imported === \"Fact\") facts.add(specifier.local.name);\n } else if (specifier.type === \"ImportNamespaceSpecifier\")\n namespaces.add(specifier.local.name);\n }\n }\n return { named, facts, namespaces };\n}\n\nfunction parts(node) {\n if (node.type === \"JSXIdentifier\") return [node.name];\n if (node.type === \"JSXMemberExpression\") return [...parts(node.object), node.property.name];\n return [];\n}\n\nfunction isT(node, names) {\n const path = parts(node);\n return (\n (path.length === 1 && names.named.has(path[0])) ||\n (path.length === 2 && names.namespaces.has(path[0]) && [\"T\", \"Title\"].includes(path[1]))\n );\n}\n\nfunction allowedElement(node, names) {\n const path = parts(node);\n if (path.length === 1 && INLINE_TAGS.has(path[0])) return true;\n if (path.length === 1 && names.facts.has(path[0])) return true;\n return path.length === 2 && names.namespaces.has(path[0]) && path[1] === \"Fact\";\n}\n\nexport default {\n meta: {\n type: \"problem\",\n docs: { description: \"Restrict T and Title children to plain text and approved inline content.\" },\n },\n create(context) {\n const stack = [];\n let names;\n return {\n Program(node) {\n names = importedTNames(node);\n },\n JSXElement(node) {\n const parent = stack.at(-1);\n if (parent?.insideT && !allowedElement(node.openingElement.name, names)) {\n context.report({\n node: node.openingElement.name,\n message: \"T and Title accept text, em, strong, a, code, br, and Fact only.\",\n });\n }\n stack.push({ insideT: isT(node.openingElement.name, names) || Boolean(parent?.insideT) });\n },\n \"JSXElement:exit\"() {\n stack.pop();\n },\n JSXFragment(node) {\n if (stack.at(-1)?.insideT)\n context.report({\n node,\n message:\n \"T and Title accept text, em, strong, a, code, br, and Fact only; fragments are not supported.\",\n });\n },\n };\n },\n};\n","import noBareText from \"./no-bare-text.js\";\nimport tChildren from \"./t-children.js\";\n\nexport default {\n meta: { name: \"pagegraph\" },\n rules: { \"no-bare-text\": noBareText, \"t-children\": tChildren },\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { a as SeoGraph, s as SeoNode } from "./graph-D1PIndsC.js";
|
|
2
|
+
//#region src/markdown/document.d.ts
|
|
3
|
+
type InlineNode = string | {
|
|
4
|
+
readonly fact: string;
|
|
5
|
+
readonly text: string;
|
|
6
|
+
} | {
|
|
7
|
+
readonly tag: "em" | "strong" | "a" | "code" | "br";
|
|
8
|
+
readonly href?: string;
|
|
9
|
+
readonly children: ReadonlyArray<InlineNode>;
|
|
10
|
+
};
|
|
11
|
+
interface Message {
|
|
12
|
+
readonly hash: string;
|
|
13
|
+
readonly tree: ReadonlyArray<InlineNode>;
|
|
14
|
+
readonly text: string;
|
|
15
|
+
readonly source: string;
|
|
16
|
+
readonly facts: ReadonlyArray<string>;
|
|
17
|
+
readonly audience: "all" | "agents" | "humans";
|
|
18
|
+
}
|
|
19
|
+
interface VisualDocument {
|
|
20
|
+
readonly type: "visual";
|
|
21
|
+
readonly text: string;
|
|
22
|
+
readonly source: string;
|
|
23
|
+
readonly audience: Message["audience"];
|
|
24
|
+
}
|
|
25
|
+
type BodyEntry = {
|
|
26
|
+
readonly type: "message";
|
|
27
|
+
readonly message: Message;
|
|
28
|
+
} | VisualDocument;
|
|
29
|
+
interface SectionItem {
|
|
30
|
+
readonly title?: Message;
|
|
31
|
+
/** Destination recorded from the item's rendered Section.Item.Link anchor. */
|
|
32
|
+
readonly href?: string;
|
|
33
|
+
readonly body: ReadonlyArray<BodyEntry>;
|
|
34
|
+
readonly cells: ReadonlyArray<Message>;
|
|
35
|
+
readonly source: string;
|
|
36
|
+
readonly audience: Message["audience"];
|
|
37
|
+
}
|
|
38
|
+
interface SectionDocument {
|
|
39
|
+
/** Captured with human-only messages included for offline custom serializers. */
|
|
40
|
+
readonly claimsMarkdown?: string;
|
|
41
|
+
readonly evidence?: boolean;
|
|
42
|
+
readonly kind: string;
|
|
43
|
+
readonly id: string;
|
|
44
|
+
readonly title?: Message;
|
|
45
|
+
readonly language?: string;
|
|
46
|
+
readonly body: ReadonlyArray<BodyEntry>;
|
|
47
|
+
readonly items: ReadonlyArray<SectionItem>;
|
|
48
|
+
readonly source: string;
|
|
49
|
+
readonly audience: Message["audience"];
|
|
50
|
+
}
|
|
51
|
+
interface PageDocument {
|
|
52
|
+
readonly path: string;
|
|
53
|
+
readonly hash: string;
|
|
54
|
+
readonly title: string;
|
|
55
|
+
readonly description: string;
|
|
56
|
+
readonly sections: ReadonlyArray<SectionDocument>;
|
|
57
|
+
readonly messages: ReadonlyArray<Message>;
|
|
58
|
+
readonly facts: ReadonlyArray<string>;
|
|
59
|
+
}
|
|
60
|
+
/** The document includes resolved values; source relocation alone is not a content edit. */
|
|
61
|
+
declare function hashDocument(document: Omit<PageDocument, "hash">): string;
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/markdown/facts.d.ts
|
|
64
|
+
type Json = null | boolean | number | string | ReadonlyArray<Json> | {
|
|
65
|
+
readonly [key: string]: Json;
|
|
66
|
+
};
|
|
67
|
+
interface FactDefinition {
|
|
68
|
+
readonly kind: "number" | "money" | "list" | "text";
|
|
69
|
+
readonly value: Json;
|
|
70
|
+
readonly text: string;
|
|
71
|
+
readonly items?: ReadonlyArray<string>;
|
|
72
|
+
}
|
|
73
|
+
type Facts = Readonly<Record<string, FactDefinition>>;
|
|
74
|
+
/** Register code-owned values for ordinary React rendering as well as capture. */
|
|
75
|
+
declare function defineFacts<const F extends Facts>(facts: F): F;
|
|
76
|
+
declare const fact: {
|
|
77
|
+
number(value: number, options?: Intl.NumberFormatOptions): FactDefinition;
|
|
78
|
+
money(value: number, options?: {
|
|
79
|
+
currency?: string;
|
|
80
|
+
per?: string;
|
|
81
|
+
}): FactDefinition;
|
|
82
|
+
list<T extends Json>(values: ReadonlyArray<T>, options?: {
|
|
83
|
+
format: (value: T) => string;
|
|
84
|
+
}): FactDefinition;
|
|
85
|
+
text(value: string): FactDefinition;
|
|
86
|
+
};
|
|
87
|
+
declare function resolveFact(id: string, facts?: Facts): FactDefinition;
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/core/page-heads.d.ts
|
|
90
|
+
/** Plain document metadata, without framework or schema dependencies. */
|
|
91
|
+
interface PageHead {
|
|
92
|
+
readonly path: string;
|
|
93
|
+
readonly title: string;
|
|
94
|
+
readonly description: string;
|
|
95
|
+
}
|
|
96
|
+
interface PageHeadsOptions {
|
|
97
|
+
/** Path globs: `*` matches a segment, `**` matches across segments. */
|
|
98
|
+
readonly exclude?: ReadonlyArray<string>;
|
|
99
|
+
/** Exclude noindex pages and redirects. Parameter templates are always excluded. Defaults to true. */
|
|
100
|
+
readonly indexable?: boolean;
|
|
101
|
+
}
|
|
102
|
+
/** Select page nodes before the host resolves metadata; sitemap-disabled hubs remain pages. */
|
|
103
|
+
declare function selectPageHeadNodes(graph: SeoGraph, options?: PageHeadsOptions): Array<SeoNode>;
|
|
104
|
+
/** Extract resolved heads, naming the selected page when metadata is missing or blank. */
|
|
105
|
+
declare function pageHeads(graph: SeoGraph, options?: PageHeadsOptions): Array<PageHead>;
|
|
106
|
+
//#endregion
|
|
107
|
+
export { hashDocument as _, FactDefinition as a, fact as c, InlineNode as d, Message as f, VisualDocument as g, SectionItem as h, selectPageHeadNodes as i, resolveFact as l, SectionDocument as m, PageHeadsOptions as n, Facts as o, PageDocument as p, pageHeads as r, defineFacts as s, PageHead as t, BodyEntry as u };
|
|
108
|
+
//# sourceMappingURL=page-heads-BfjWQvau.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as globToRegExp } from "./checks-
|
|
1
|
+
import { a as globToRegExp } from "./checks-BS-aDXB_.js";
|
|
2
2
|
//#region src/core/page-heads.ts
|
|
3
3
|
/** Select page nodes before the host resolves metadata; sitemap-disabled hubs remain pages. */
|
|
4
4
|
function selectPageHeadNodes(graph, options = {}) {
|
|
5
5
|
const excludes = (options.exclude ?? []).map(globToRegExp);
|
|
6
|
-
return [...graph.nodes.values()].filter((node) => node.kind !== "layout" && (node.policy.sitemap !== void 0 || node.instance !== void 0) && !excludes.some((pattern) => pattern.test(node.path)) && (options.indexable === false ||
|
|
6
|
+
return [...graph.nodes.values()].filter((node) => node.kind !== "layout" && !node.path.includes("$") && (node.policy.sitemap !== void 0 || node.instance !== void 0) && !excludes.some((pattern) => pattern.test(node.path)) && (options.indexable === false || node.policy.redirectTo === void 0 && !node.policy.robots?.toLowerCase().split(/[\s,]+/).includes("noindex")));
|
|
7
7
|
}
|
|
8
8
|
/** Extract resolved heads, naming the selected page when metadata is missing or blank. */
|
|
9
9
|
function pageHeads(graph, options = {}) {
|
|
@@ -22,4 +22,4 @@ function pageHeads(graph, options = {}) {
|
|
|
22
22
|
//#endregion
|
|
23
23
|
export { selectPageHeadNodes as n, pageHeads as t };
|
|
24
24
|
|
|
25
|
-
//# sourceMappingURL=page-heads-
|
|
25
|
+
//# sourceMappingURL=page-heads-BgbaIjj9.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-heads-BgbaIjj9.js","names":[],"sources":["../src/core/page-heads.ts"],"sourcesContent":["import { globToRegExp } from \"./checks\";\nimport type { SeoGraph, SeoNode } from \"./graph\";\n\n/** Plain document metadata, without framework or schema dependencies. */\nexport interface PageHead {\n readonly path: string;\n readonly title: string;\n readonly description: string;\n}\n\nexport interface PageHeadsOptions {\n /** Path globs: `*` matches a segment, `**` matches across segments. */\n readonly exclude?: ReadonlyArray<string>;\n /** Exclude noindex pages and redirects. Parameter templates are always excluded. Defaults to true. */\n readonly indexable?: boolean;\n}\n\n/** Select page nodes before the host resolves metadata; sitemap-disabled hubs remain pages. */\nexport function selectPageHeadNodes(graph: SeoGraph, options: PageHeadsOptions = {}): Array<SeoNode> {\n const excludes = (options.exclude ?? []).map(globToRegExp);\n return [...graph.nodes.values()].filter((node) =>\n node.kind !== \"layout\" &&\n !node.path.includes(\"$\") &&\n (node.policy.sitemap !== undefined || node.instance !== undefined) &&\n !excludes.some((pattern) => pattern.test(node.path)) &&\n (options.indexable === false || (\n node.policy.redirectTo === undefined &&\n !node.policy.robots?.toLowerCase().split(/[\\s,]+/).includes(\"noindex\")\n )),\n );\n}\n\n/** Extract resolved heads, naming the selected page when metadata is missing or blank. */\nexport function pageHeads(graph: SeoGraph, options: PageHeadsOptions = {}): Array<PageHead> {\n return selectPageHeadNodes(graph, options).map((node) => {\n const title = node.head?.title;\n const description = node.head?.description;\n if (!title?.trim()) throw new Error(`Invalid page head for ${node.path}: missing title`);\n if (!description?.trim()) throw new Error(`Invalid page head for ${node.path}: missing description`);\n return { path: node.path, title, description };\n });\n}\n"],"mappings":";;;AAkBA,SAAgB,oBAAoB,OAAiB,UAA4B,CAAC,GAAmB;CACnG,MAAM,YAAY,QAAQ,WAAW,CAAC,EAAA,CAAG,IAAI,YAAY;CACzD,OAAO,CAAC,GAAG,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,QAAQ,SACvC,KAAK,SAAS,YACd,CAAC,KAAK,KAAK,SAAS,GAAG,MACtB,KAAK,OAAO,YAAY,KAAA,KAAa,KAAK,aAAa,KAAA,MACxD,CAAC,SAAS,MAAM,YAAY,QAAQ,KAAK,KAAK,IAAI,CAAC,MAClD,QAAQ,cAAc,SACrB,KAAK,OAAO,eAAe,KAAA,KAC3B,CAAC,KAAK,OAAO,QAAQ,YAAY,CAAC,CAAC,MAAM,QAAQ,CAAC,CAAC,SAAS,SAAS,EAEzE;AACF;;AAGA,SAAgB,UAAU,OAAiB,UAA4B,CAAC,GAAoB;CAC1F,OAAO,oBAAoB,OAAO,OAAO,CAAC,CAAC,KAAK,SAAS;EACvD,MAAM,QAAQ,KAAK,MAAM;EACzB,MAAM,cAAc,KAAK,MAAM;EAC/B,IAAI,CAAC,OAAO,KAAK,GAAG,MAAM,IAAI,MAAM,yBAAyB,KAAK,KAAK,gBAAgB;EACvF,IAAI,CAAC,aAAa,KAAK,GAAG,MAAM,IAAI,MAAM,yBAAyB,KAAK,KAAK,sBAAsB;EACnG,OAAO;GAAE,MAAM,KAAK;GAAM;GAAO;EAAY;CAC/C,CAAC;AACH"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as SeoGraph, r as SeoEdge, s as SeoNode } from "./graph-
|
|
1
|
+
import { a as SeoGraph, r as SeoEdge, s as SeoNode } from "./graph-D1PIndsC.js";
|
|
2
2
|
//#region src/core/projections.d.ts
|
|
3
3
|
interface ProjectionConfig {
|
|
4
4
|
origin: string;
|
|
@@ -75,4 +75,4 @@ declare function renderRobots(_graph: SeoGraph, cfg: RobotsConfig): string;
|
|
|
75
75
|
declare function inspectNode(graph: SeoGraph, path: string): NodeReport | undefined;
|
|
76
76
|
//#endregion
|
|
77
77
|
export { inspectNode as a, renderRobots as c, contentSignal as i, renderSitemap as l, ProjectionConfig as n, isSitemapEligible as o, RobotsConfig as r, lastModified as s, NodeReport as t };
|
|
78
|
-
//# sourceMappingURL=projections-
|
|
78
|
+
//# sourceMappingURL=projections-Bk-qOOsR.d.ts.map
|
package/dist/react.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as WithContext, C as FAQPage, D as Service, E as Organization, O as Thing, S as BreadcrumbList, T as ItemList, f as JsonLdDocument, g as SeoFaq, j as IdReference, k as WebSite, v as SeoPageHead, w as Graph, x as Article } from "./graph-D1PIndsC.js";
|
|
2
|
+
import { a as Fact, c as ForHumans, d as Title, f as Visual, g as useCapturePage, h as messageText, i as DocumentProvider, l as Section, m as finishDocument, n as CaptureRequest, o as FactId, p as createCollector, r as Collector, s as ForAgents, t as CaptureAnchor, u as T } from "./document-CztEu3Vd.js";
|
|
2
3
|
import { AnyRouteMatch } from "@tanstack/react-router";
|
|
3
4
|
//#region src/react/json-ld-composition.d.ts
|
|
4
5
|
/** Any schema.org entity accepted by `schema-dts`. */
|
|
@@ -223,5 +224,5 @@ declare function Breadcrumbs({ className }: {
|
|
|
223
224
|
className?: string | undefined;
|
|
224
225
|
}): import("react").JSX.Element | null;
|
|
225
226
|
//#endregion
|
|
226
|
-
export { type ArticleParams, type BreadcrumbItem, Breadcrumbs, type CrumbTrailItem, type ItemListEntry, type JsonLd, type JsonLdDocument, type JsonLdEntityIds, type JsonLdEntry, type JsonLdNode, type JsonLdTransform, type JsonLdTransformContext, type JsonLdTransformResult, type Seo, type SeoConfig, type SeoFaq, type SeoHead, type SeoHeadCtx, type SeoJsonLdConfig, type SeoOrganization, type SeoPageHead, type SeoPostalAddress, type SeoSite, type SeoWebsite, type ServiceParams, composeJsonLd, createSeo, defineJsonLd, extendJsonLd, jsonLdGraph, jsonLdRef, resolveCrumbTrail };
|
|
227
|
+
export { type ArticleParams, type BreadcrumbItem, Breadcrumbs, CaptureAnchor, CaptureRequest, type Collector, type CrumbTrailItem, DocumentProvider, Fact, type FactId, ForAgents, ForHumans, type ItemListEntry, type JsonLd, type JsonLdDocument, type JsonLdEntityIds, type JsonLdEntry, type JsonLdNode, type JsonLdTransform, type JsonLdTransformContext, type JsonLdTransformResult, Section, type Seo, type SeoConfig, type SeoFaq, type SeoHead, type SeoHeadCtx, type SeoJsonLdConfig, type SeoOrganization, type SeoPageHead, type SeoPostalAddress, type SeoSite, type SeoWebsite, type ServiceParams, T, Title, Visual, composeJsonLd, createCollector, createSeo, defineJsonLd, extendJsonLd, finishDocument, jsonLdGraph, jsonLdRef, messageText, resolveCrumbTrail, useCapturePage };
|
|
227
228
|
//# sourceMappingURL=react.d.ts.map
|
package/dist/react.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { t as applyTitleTemplate } from "./declare-D5o7hwmv.js";
|
|
2
|
+
import { a as ForAgents, c as T, d as createCollector, f as finishDocument, i as Fact, l as Title, m as useCapturePage, n as CaptureRequest, o as ForHumans, p as messageText, r as DocumentProvider, s as Section, t as CaptureAnchor, u as Visual } from "./document-Dvemcv7V.js";
|
|
2
3
|
import { Link, useMatches } from "@tanstack/react-router";
|
|
3
4
|
import { Fragment } from "react";
|
|
4
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -415,6 +416,6 @@ function createSeo(config) {
|
|
|
415
416
|
};
|
|
416
417
|
}
|
|
417
418
|
//#endregion
|
|
418
|
-
export { Breadcrumbs, composeJsonLd, createSeo, defineJsonLd, extendJsonLd, jsonLdGraph, jsonLdRef, resolveCrumbTrail };
|
|
419
|
+
export { Breadcrumbs, CaptureAnchor, CaptureRequest, DocumentProvider, Fact, ForAgents, ForHumans, Section, T, Title, Visual, composeJsonLd, createCollector, createSeo, defineJsonLd, extendJsonLd, finishDocument, jsonLdGraph, jsonLdRef, messageText, resolveCrumbTrail, useCapturePage };
|
|
419
420
|
|
|
420
421
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","names":["composeJsonLd","composeEntries"],"sources":["../src/react/breadcrumbs.tsx","../src/react/site.ts","../src/react/json-ld-composition.ts","../src/react/json-ld.ts","../src/react/create-seo.ts"],"sourcesContent":["import type { AnyRouteMatch } from \"@tanstack/react-router\";\nimport { Link, useMatches } from \"@tanstack/react-router\";\nimport { Fragment } from \"react\";\n\nexport interface CrumbTrailItem {\n name: string;\n path: string;\n}\n\n/**\n * Walk the match chain in order, keeping matches that declare `staticData.seo.crumb`,\n * resolving string | fn form. Shared by <Breadcrumbs/> and seoHead's BreadcrumbList.\n */\nexport function resolveCrumbTrail(matches: ReadonlyArray<AnyRouteMatch>): Array<CrumbTrailItem> {\n const trail: Array<CrumbTrailItem> = [];\n for (const match of matches) {\n const crumb = match.staticData.seo?.crumb;\n if (crumb === undefined) continue;\n const name = typeof crumb === \"function\" ? crumb(match) : crumb;\n trail.push({ name, path: match.pathname });\n }\n return trail;\n}\n\nexport function Breadcrumbs({ className }: { className?: string | undefined }) {\n const trail = resolveCrumbTrail(useMatches());\n if (trail.length < 2) return null;\n\n const lastIndex = trail.length - 1;\n return (\n <nav aria-label=\"Breadcrumb\" className={className}>\n <ol className=\"text-muted-foreground flex items-center gap-2 font-mono text-[11px] tracking-wide uppercase\">\n {trail.map((item, index) => {\n const isLast = index === lastIndex;\n return (\n <Fragment key={item.path}>\n {index > 0 ? (\n <li aria-hidden=\"true\" className=\"text-muted-foreground/50\">\n /\n </li>\n ) : null}\n <li\n aria-current={isLast ? \"page\" : undefined}\n className={isLast ? \"text-foreground truncate\" : undefined}\n >\n {isLast ? (\n item.name\n ) : (\n <Link to={item.path} className=\"hover:text-foreground transition-colors\">\n {item.name}\n </Link>\n )}\n </li>\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n}\n","/**\n * Site identity — the values a package cannot know about its host.\n *\n * Bound once through {@link createSeo}, so the ~30 route call sites that render\n * a head never thread an origin or a brand name through their arguments.\n * Everything here is a *value*; the schema construction it feeds lives in\n * `json-ld.ts`.\n */\n\nimport type { SeoHead } from \"./create-seo\";\nimport type { SeoJsonLdConfig } from \"./json-ld-composition\";\n\n/** Absolute URL for an origin-relative path; an already-absolute URL passes through. */\nexport function absoluteUrl(origin: string, pathOrUrl: string): string {\n return pathOrUrl.startsWith(\"http\") ? pathOrUrl : `${origin}${pathOrUrl}`;\n}\n\nexport interface SeoSite {\n /** Brand name: Organization/WebSite `name`, Article publisher, Service provider default. */\n name: string;\n /** Organization `logo`. Origin-relative path or absolute URL. */\n logo: string;\n /** Article `publisher.logo` (Google wants an ImageObject distinct from the brand mark). */\n publisherLogo: string;\n /** Article `image` when the instance declares none. */\n defaultImage: string;\n /** Article `author` when the instance declares none. */\n defaultAuthor: { name: string; url?: string | undefined };\n}\n\n/** Public mailing address rendered as a schema.org PostalAddress. */\nexport interface SeoPostalAddress {\n streetAddress: string;\n addressLocality: string;\n addressRegion: string;\n postalCode: string;\n addressCountry: string;\n}\n\n/** The site-wide Organization entity (Knowledge Graph). */\nexport interface SeoOrganization {\n legalName?: string | undefined;\n description: string;\n sameAs: ReadonlyArray<string>;\n contactPoint: { contactType: string; email: string };\n address?: SeoPostalAddress | undefined;\n}\n\n/** The site-wide WebSite entity (sitelinks search box). */\nexport interface SeoWebsite {\n /** Origin-relative search target carrying the `{search_term_string}` placeholder. */\n searchPath: string;\n}\n\nexport interface SeoConfig {\n /** Canonical origin, no trailing slash — e.g. `https://example.com`. */\n origin: string;\n site: SeoSite;\n organization: SeoOrganization;\n website: SeoWebsite;\n jsonLd?: SeoJsonLdConfig | undefined;\n /**\n * Last-mile override for every head `seoHead` renders, e.g. to append\n * site-specific meta. Runs after the canonical, title template, and JSON-LD.\n */\n transformHead?: ((head: SeoHead) => SeoHead) | undefined;\n}\n","import type {\n Article,\n BreadcrumbList,\n FAQPage,\n Graph,\n IdReference,\n ItemList,\n Organization,\n Service,\n Thing,\n WebSite,\n WithContext,\n} from \"schema-dts\";\n\n/** Any schema.org entity accepted by `schema-dts`. */\nexport type JsonLdNode = Extract<Thing, object>;\n\nimport type { JsonLdDocument } from \"../core/declare\";\n\nexport type { JsonLdDocument };\n\nexport interface JsonLdEntityIds {\n organization: string;\n website: string;\n}\n\nexport type JsonLdEntry =\n | {\n kind: \"organization\";\n source: \"generated\";\n document: WithContext<Organization>;\n }\n | { kind: \"website\"; source: \"generated\"; document: WithContext<WebSite> }\n | { kind: \"article\"; source: \"generated\"; document: WithContext<Article> }\n | { kind: \"service\"; source: \"generated\"; document: WithContext<Service> }\n | { kind: \"faq\"; source: \"generated\"; document: WithContext<FAQPage> }\n | {\n kind: \"breadcrumb\";\n source: \"generated\";\n document: WithContext<BreadcrumbList>;\n }\n | { kind: \"item-list\"; source: \"generated\"; document: WithContext<ItemList> }\n | { kind: \"custom\"; source: \"site\" | \"page\"; document: JsonLdDocument };\n\nexport interface JsonLdTransformContext {\n /** Canonical site origin configured through `createSeo`. */\n origin: string;\n /** Stable identifiers for the plugin's generated site entities. */\n entityIds: JsonLdEntityIds;\n /** Canonical page URL when composition happens for a route. */\n canonical?: string | undefined;\n}\n\n/** Return no document to suppress an entry, one to replace it, or an array to expand it. */\nexport type JsonLdTransformResult =\n | JsonLdDocument\n | ReadonlyArray<JsonLdDocument>\n | false\n | null\n | undefined;\n\nexport type JsonLdTransform = (\n entry: JsonLdEntry,\n context: JsonLdTransformContext,\n) => JsonLdTransformResult;\n\nexport interface SeoJsonLdConfig {\n /** Custom entities included by `generateSiteGraphSchema`. */\n site?:\n | ReadonlyArray<JsonLdDocument>\n | ((entityIds: JsonLdEntityIds) => ReadonlyArray<JsonLdDocument>)\n | undefined;\n /** Open composition hook for generated and custom entries. */\n transform?: JsonLdTransform | undefined;\n}\n\n/** Add the schema.org context to an entity while preserving its concrete type. */\nexport function defineJsonLd<const Node extends JsonLdNode & object>(\n node: Node,\n): Node & { \"@context\": \"https://schema.org\" } {\n return { \"@context\": \"https://schema.org\", ...node };\n}\n\n/** Reference a canonical entity declared elsewhere in the same graph or page. */\nexport function jsonLdRef(id: string): IdReference {\n return { \"@id\": id };\n}\n\n/** Extend a generated or custom document without rebuilding its existing properties. */\nexport function extendJsonLd<\n const Document extends JsonLdDocument,\n const Extension extends object,\n>(document: Document, extension: Extension): Document & Extension {\n return { ...(document as unknown as object), ...extension } as Document &\n Extension;\n}\n\nconst documentNodes = (document: JsonLdDocument): ReadonlyArray<JsonLdNode> => {\n if (\"@graph\" in document) {\n return document[\"@graph\"] as ReadonlyArray<JsonLdNode>;\n }\n const { \"@context\": _context, ...node } = document as unknown as Record<\n string,\n unknown\n >;\n return [node as JsonLdNode];\n};\n\n/** Compose related schema.org documents into one graph without nested `@context` values. */\nexport function jsonLdGraph(documents: ReadonlyArray<JsonLdDocument>): Graph {\n return {\n \"@context\": \"https://schema.org\",\n \"@graph\": documents.flatMap(documentNodes),\n };\n}\n\n/** Apply an optional zero/one/many transform while preserving entry order. */\nexport function composeJsonLd(\n entries: ReadonlyArray<JsonLdEntry>,\n context: JsonLdTransformContext,\n transform?: JsonLdTransform,\n): Array<JsonLdDocument> {\n if (transform === undefined) {\n return entries.map((entry) => entry.document as JsonLdDocument);\n }\n\n return entries.flatMap((entry) => {\n const result = transform(entry, context);\n if (result === undefined || result === null || result === false) return [];\n return Array.isArray(result) ? [...result] : [result as JsonLdDocument];\n });\n}\n","/**\n * JSON-LD structured-data generators.\n *\n * schema.org payloads typed against `schema-dts`, which is a types-only devDep —\n * it erases at build, so this module keeps the entry's zero-runtime-dep rule.\n * The brand values (name, logo, sameAs, the Organization description) are the\n * host's, and arrive through {@link SeoConfig}; the schema construction is ours.\n *\n * @see https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data\n * @see https://schema.org/\n */\n\nimport type {\n Article,\n BreadcrumbList,\n FAQPage,\n Graph,\n ItemList,\n Organization,\n Person,\n Question,\n Service,\n WebSite,\n WithContext,\n} from \"schema-dts\";\n\nimport {\n composeJsonLd as composeEntries,\n jsonLdGraph,\n jsonLdRef,\n type JsonLdDocument,\n type JsonLdEntityIds,\n type JsonLdEntry,\n} from \"./json-ld-composition\";\nimport type { SeoFaq } from \"../core/declare\";\nimport { absoluteUrl, type SeoConfig } from \"./site\";\n\nexport interface ServiceParams {\n name: string;\n description: string;\n serviceType: string;\n provider?: string | undefined;\n areaServed?: string | undefined;\n}\n\n\nexport interface BreadcrumbItem {\n name: string;\n url: string;\n}\n\nexport interface ItemListEntry {\n name: string;\n url: string;\n}\n\nexport interface ArticleParams {\n headline: string;\n description: string;\n image?: string | undefined;\n datePublished: string;\n dateModified?: string | undefined;\n author: {\n name: string;\n url?: string | undefined;\n };\n url: string;\n}\n\n/** The JSON-LD generators, bound to one site identity. */\nexport interface JsonLd {\n readonly entityIds: JsonLdEntityIds;\n /** Brand entity for the Knowledge Graph. Render site-wide (root layout). */\n generateOrganizationSchema: () => WithContext<Organization>;\n /** WebSite entity with a sitelinks search box. Render on the homepage. */\n generateWebsiteSchema: () => WithContext<WebSite>;\n generateServiceSchema: (params: ServiceParams) => WithContext<Service>;\n generateFAQPageSchema: (faqs: SeoFaq[]) => WithContext<FAQPage>;\n generateBreadcrumbSchema: (\n items: BreadcrumbItem[],\n ) => WithContext<BreadcrumbList>;\n /** Describe a visibly rendered, ordered collection of canonical pages. */\n generateItemListSchema: (\n name: string,\n items: ReadonlyArray<ItemListEntry>,\n ) => WithContext<ItemList>;\n generateArticleSchema: (params: ArticleParams) => WithContext<Article>;\n /** Compose the Organization, WebSite, and configured site entities into one graph. */\n generateSiteGraphSchema: () => Graph | undefined;\n /** Apply the configured transform to generated or custom entries. */\n composeJsonLd: (\n entries: ReadonlyArray<JsonLdEntry>,\n context?: { canonical?: string | undefined },\n ) => Array<JsonLdDocument>;\n}\n\nexport function createJsonLd(config: SeoConfig): JsonLd {\n const { origin, site, organization, website } = config;\n const organizationId = `${origin}/#organization`;\n const websiteId = `${origin}/#website`;\n const entityIds = { organization: organizationId, website: websiteId };\n\n const generateOrganizationSchema = (): WithContext<Organization> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"Organization\",\n \"@id\": organizationId,\n name: site.name,\n ...(organization.legalName === undefined\n ? {}\n : { legalName: organization.legalName }),\n url: origin,\n logo: absoluteUrl(origin, site.logo),\n description: organization.description,\n sameAs: [...organization.sameAs],\n contactPoint: {\n \"@type\": \"ContactPoint\",\n contactType: organization.contactPoint.contactType,\n email: organization.contactPoint.email,\n },\n ...(organization.address === undefined\n ? {}\n : {\n address: {\n \"@type\": \"PostalAddress\" as const,\n ...organization.address,\n },\n }),\n });\n\n const generateWebsiteSchema = (): WithContext<WebSite> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"WebSite\",\n \"@id\": websiteId,\n name: site.name,\n url: origin,\n publisher: jsonLdRef(organizationId),\n potentialAction: {\n \"@type\": \"SearchAction\",\n target: {\n \"@type\": \"EntryPoint\",\n urlTemplate: absoluteUrl(origin, website.searchPath),\n },\n query: \"required name=search_term_string\",\n },\n });\n\n const generateServiceSchema = (\n params: ServiceParams,\n ): WithContext<Service> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"Service\",\n name: params.name,\n description: params.description,\n serviceType: params.serviceType,\n provider: {\n \"@type\": \"Organization\",\n ...(params.provider === undefined\n ? { \"@id\": organizationId, url: origin }\n : {}),\n name: params.provider ?? site.name,\n },\n areaServed: params.areaServed ?? \"Worldwide\",\n });\n\n const generateFAQPageSchema = (faqs: SeoFaq[]): WithContext<FAQPage> => {\n const questions: Question[] = faqs.map((faq) => ({\n \"@type\": \"Question\",\n name: faq.question,\n acceptedAnswer: {\n \"@type\": \"Answer\",\n text: faq.answer,\n },\n }));\n\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"FAQPage\",\n mainEntity: questions,\n };\n };\n\n const generateBreadcrumbSchema = (\n items: BreadcrumbItem[],\n ): WithContext<BreadcrumbList> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"BreadcrumbList\",\n itemListElement: items.map((item, index) => ({\n \"@type\": \"ListItem\",\n position: index + 1,\n name: item.name,\n item: `${origin}${item.url}`,\n })),\n });\n\n const generateItemListSchema = (\n name: string,\n items: ReadonlyArray<ItemListEntry>,\n ): WithContext<ItemList> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"ItemList\",\n name,\n numberOfItems: items.length,\n itemListElement: items.map((item, index) => ({\n \"@type\": \"ListItem\",\n position: index + 1,\n name: item.name,\n url: `${origin}${item.url}`,\n })),\n });\n\n const generateArticleSchema = (\n params: ArticleParams,\n ): WithContext<Article> => {\n const authorSchema: Person = {\n \"@type\": \"Person\",\n name: params.author.name,\n ...(params.author.url && { url: params.author.url }),\n };\n\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"Article\",\n headline: params.headline,\n description: params.description,\n // Deliberately NOT absolutized: a declared instance image lands verbatim\n // (og:image is where the absolute form is required, and seoHead does that).\n image: params.image ?? absoluteUrl(origin, site.defaultImage),\n datePublished: params.datePublished,\n dateModified: params.dateModified ?? params.datePublished,\n author: authorSchema,\n publisher: {\n \"@type\": \"Organization\",\n \"@id\": organizationId,\n name: site.name,\n logo: {\n \"@type\": \"ImageObject\",\n url: absoluteUrl(origin, site.publisherLogo),\n },\n },\n mainEntityOfPage: {\n \"@type\": \"WebPage\",\n \"@id\": params.url,\n },\n };\n };\n\n const composeJsonLd: JsonLd[\"composeJsonLd\"] = (entries, context = {}) =>\n composeEntries(\n entries,\n {\n origin,\n entityIds,\n ...(context.canonical === undefined\n ? {}\n : { canonical: context.canonical }),\n },\n config.jsonLd?.transform,\n );\n\n const generateSiteGraphSchema = (): Graph | undefined => {\n const configuredSite =\n typeof config.jsonLd?.site === \"function\"\n ? config.jsonLd.site(entityIds)\n : (config.jsonLd?.site ?? []);\n const entries: Array<JsonLdEntry> = [\n {\n kind: \"organization\",\n source: \"generated\",\n document: generateOrganizationSchema(),\n },\n {\n kind: \"website\",\n source: \"generated\",\n document: generateWebsiteSchema(),\n },\n ...configuredSite.map(\n (document): JsonLdEntry => ({\n kind: \"custom\",\n source: \"site\",\n document,\n }),\n ),\n ];\n const documents = composeJsonLd(entries);\n return documents.length === 0 ? undefined : jsonLdGraph(documents);\n };\n\n return {\n entityIds,\n generateOrganizationSchema,\n generateWebsiteSchema,\n generateServiceSchema,\n generateFAQPageSchema,\n generateBreadcrumbSchema,\n generateItemListSchema,\n generateArticleSchema,\n generateSiteGraphSchema,\n composeJsonLd,\n };\n}\n","/**\n * The render layer: one route's SEO declaration plus its per-instance content,\n * composed into the meta/link descriptors TanStack Router renders into <head>,\n * with the JSON-LD that page warrants.\n *\n * {@link createSeo} binds the site identity once (see `site.ts`) and returns\n * the bound API, so a route file calls `seoHead(ctx, instance)` and never sees\n * an origin or a brand name.\n */\n\nimport type { AnyRouteMatch, MetaDescriptor } from \"@tanstack/react-router\";\n\nimport { applyTitleTemplate, type SeoPageHead } from \"../core/declare\";\n\nimport { resolveCrumbTrail } from \"./breadcrumbs\";\nimport type { JsonLdDocument, JsonLdEntry } from \"./json-ld-composition\";\nimport { absoluteUrl, type SeoConfig } from \"./site\";\nimport { createJsonLd, type JsonLd } from \"./json-ld\";\n\n/** Structural subset of TanStack's head() ctx — the leaf match plus the full chain. */\nexport interface SeoHeadCtx {\n matches: ReadonlyArray<AnyRouteMatch>;\n match: AnyRouteMatch;\n}\n\nexport interface SeoHead {\n meta: NonNullable<AnyRouteMatch[\"meta\"]>;\n links: Array<{ rel: \"canonical\"; href: string }>;\n}\n\n/** The render API, bound to one site identity. */\nexport interface Seo extends JsonLd {\n seoHead: (ctx: SeoHeadCtx, instance: SeoPageHead) => SeoHead;\n /**\n * `head()` for a static route that declares its head in `staticData.seo.head`:\n *\n * ```ts\n * createFileRoute(\"/pricing\")({\n * staticData: { seo: { kind: \"page\", sitemap, head: { title, description, faqs } } },\n * head: seo.head,\n * })\n * ```\n *\n * The graph, `pageHeads`, and the checks read the same declaration.\n *\n * Generic so TanStack infers nothing from it: a `head` typed with\n * `AnyRouteMatch` would make the route's search and loader types `any`, and\n * that spreads through the route tree.\n */\n head: <Ctx extends SeoHeadCtx>(ctx: Ctx) => SeoHead;\n}\n\n/** Strip a trailing slash from a pathname, keeping the root \"/\" intact. */\nfunction normalizePathname(pathname: string): string {\n return pathname.length > 1 && pathname.endsWith(\"/\")\n ? pathname.slice(0, -1)\n : pathname;\n}\n\nexport function createSeo(config: SeoConfig): Seo {\n const { origin, site } = config;\n const jsonLd = createJsonLd(config);\n\n const seoHead = (ctx: SeoHeadCtx, instance: SeoPageHead): SeoHead => {\n const canonical = `${origin}${instance.canonicalPath ?? normalizePathname(ctx.match.pathname)}`;\n const title = applyTitleTemplate(ctx.match.staticData.seo?.titleTemplate, instance.title);\n const resolvedOgTitle = instance.ogTitle ?? title;\n const resolvedOgDescription =\n instance.ogDescription ?? instance.description;\n const routeSeo = ctx.match.staticData.seo;\n const { article } = instance;\n const jsonLdEntries: Array<JsonLdEntry> = [];\n\n const meta: Array<MetaDescriptor> = [\n { title },\n { name: \"description\", content: instance.description },\n { property: \"og:title\", content: resolvedOgTitle },\n { property: \"og:description\", content: resolvedOgDescription },\n { property: \"og:type\", content: article ? \"article\" : \"website\" },\n { property: \"og:url\", content: canonical },\n { name: \"twitter:card\", content: \"summary_large_image\" },\n { name: \"twitter:title\", content: resolvedOgTitle },\n { name: \"twitter:description\", content: resolvedOgDescription },\n ];\n\n const robots = instance.robots ?? routeSeo?.robots;\n if (robots !== undefined) {\n meta.push({ name: \"robots\", content: robots });\n }\n\n if (article) {\n if (article.tags?.length) {\n meta.push({ name: \"keywords\", content: article.tags.join(\", \") });\n }\n meta.push(\n { property: \"article:published_time\", content: article.publishedAt },\n {\n property: \"article:modified_time\",\n content: article.modifiedAt ?? article.publishedAt,\n },\n );\n if (article.image !== undefined) {\n const imageUrl = absoluteUrl(origin, article.image);\n meta.push(\n { property: \"og:image\", content: imageUrl },\n { name: \"twitter:image\", content: imageUrl },\n );\n }\n }\n\n if (article) {\n jsonLdEntries.push({\n kind: \"article\",\n source: \"generated\",\n document: jsonLd.generateArticleSchema({\n headline: resolvedOgTitle,\n description: instance.description,\n image: article.image,\n datePublished: article.publishedAt,\n dateModified: article.modifiedAt ?? article.publishedAt,\n author: article.author ?? site.defaultAuthor,\n url: canonical,\n }),\n });\n }\n\n if (!article && instance.keywords) {\n meta.push({ name: \"keywords\", content: instance.keywords.join(\", \") });\n }\n\n if (instance.service) {\n jsonLdEntries.push({\n kind: \"service\",\n source: \"generated\",\n document: jsonLd.generateServiceSchema({\n name: instance.service.name,\n description: instance.service.description ?? instance.description,\n serviceType: instance.service.serviceType,\n }),\n });\n }\n\n if (instance.faqs) {\n jsonLdEntries.push({\n kind: \"faq\",\n source: \"generated\",\n document: jsonLd.generateFAQPageSchema([...instance.faqs]),\n });\n }\n\n if (instance.itemList) {\n jsonLdEntries.push({\n kind: \"item-list\",\n source: \"generated\",\n document: jsonLd.generateItemListSchema(\n instance.itemList.name,\n instance.itemList.items,\n ),\n });\n }\n\n // TanStack accumulates every matched route's head output. Only the current leaf\n // owns the BreadcrumbList; otherwise each parent repeats a progressively stale\n // trail alongside the leaf's canonical trail on nested pages.\n const isLeafMatch = ctx.matches.at(-1)?.id === ctx.match.id;\n const trail = isLeafMatch\n ? (instance.breadcrumbs ?? resolveCrumbTrail(ctx.matches))\n : [];\n if (trail.length >= 2) {\n jsonLdEntries.push({\n kind: \"breadcrumb\",\n source: \"generated\",\n document: jsonLd.generateBreadcrumbSchema(\n trail.map((item) => ({ name: item.name, url: item.path })),\n ),\n });\n }\n\n if (instance.jsonLd) {\n jsonLdEntries.push(\n ...instance.jsonLd.map(\n (document): JsonLdEntry => ({\n kind: \"custom\",\n source: \"page\",\n document,\n }),\n ),\n );\n }\n\n for (const document of jsonLd.composeJsonLd(jsonLdEntries, { canonical })) {\n meta.push({ \"script:ld+json\": document });\n }\n\n // React's head types (JSX.IntrinsicElements['meta']) model only <meta> attributes;\n // TanStack renders `script:ld+json` entries as JSON-LD <script> tags at runtime. The\n // installed @tanstack/react-router augments leaf head meta to those JSX attributes, so\n // the JSON-LD entries are asserted to it (same pattern as an inline root JSON-LD).\n const head: SeoHead = {\n meta: meta as NonNullable<AnyRouteMatch[\"meta\"]>,\n links: [{ rel: \"canonical\", href: canonical }],\n };\n return config.transformHead === undefined ? head : config.transformHead(head);\n };\n\n const head = <Ctx extends SeoHeadCtx>(ctx: Ctx): SeoHead => {\n const declared = ctx.match.staticData.seo?.head;\n if (declared === undefined) {\n throw new Error(`seo.head needs staticData.seo.head on route ${ctx.match.routeId}`);\n }\n return seoHead(ctx, declared);\n };\n\n return { seoHead, head, ...jsonLd };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react.js","names":["composeJsonLd","composeEntries"],"sources":["../src/react/breadcrumbs.tsx","../src/react/site.ts","../src/react/json-ld-composition.ts","../src/react/json-ld.ts","../src/react/create-seo.ts"],"sourcesContent":["import type { AnyRouteMatch } from \"@tanstack/react-router\";\nimport { Link, useMatches } from \"@tanstack/react-router\";\nimport { Fragment } from \"react\";\n\nexport interface CrumbTrailItem {\n name: string;\n path: string;\n}\n\n/**\n * Walk the match chain in order, keeping matches that declare `staticData.seo.crumb`,\n * resolving string | fn form. Shared by <Breadcrumbs/> and seoHead's BreadcrumbList.\n */\nexport function resolveCrumbTrail(matches: ReadonlyArray<AnyRouteMatch>): Array<CrumbTrailItem> {\n const trail: Array<CrumbTrailItem> = [];\n for (const match of matches) {\n const crumb = match.staticData.seo?.crumb;\n if (crumb === undefined) continue;\n const name = typeof crumb === \"function\" ? crumb(match) : crumb;\n trail.push({ name, path: match.pathname });\n }\n return trail;\n}\n\nexport function Breadcrumbs({ className }: { className?: string | undefined }) {\n const trail = resolveCrumbTrail(useMatches());\n if (trail.length < 2) return null;\n\n const lastIndex = trail.length - 1;\n return (\n <nav aria-label=\"Breadcrumb\" className={className}>\n <ol className=\"text-muted-foreground flex items-center gap-2 font-mono text-[11px] tracking-wide uppercase\">\n {trail.map((item, index) => {\n const isLast = index === lastIndex;\n return (\n <Fragment key={item.path}>\n {index > 0 ? (\n <li aria-hidden=\"true\" className=\"text-muted-foreground/50\">\n /\n </li>\n ) : null}\n <li\n aria-current={isLast ? \"page\" : undefined}\n className={isLast ? \"text-foreground truncate\" : undefined}\n >\n {isLast ? (\n item.name\n ) : (\n <Link to={item.path} className=\"hover:text-foreground transition-colors\">\n {item.name}\n </Link>\n )}\n </li>\n </Fragment>\n );\n })}\n </ol>\n </nav>\n );\n}\n","/**\n * Site identity — the values a package cannot know about its host.\n *\n * Bound once through {@link createSeo}, so the ~30 route call sites that render\n * a head never thread an origin or a brand name through their arguments.\n * Everything here is a *value*; the schema construction it feeds lives in\n * `json-ld.ts`.\n */\n\nimport type { SeoHead } from \"./create-seo\";\nimport type { SeoJsonLdConfig } from \"./json-ld-composition\";\n\n/** Absolute URL for an origin-relative path; an already-absolute URL passes through. */\nexport function absoluteUrl(origin: string, pathOrUrl: string): string {\n return pathOrUrl.startsWith(\"http\") ? pathOrUrl : `${origin}${pathOrUrl}`;\n}\n\nexport interface SeoSite {\n /** Brand name: Organization/WebSite `name`, Article publisher, Service provider default. */\n name: string;\n /** Organization `logo`. Origin-relative path or absolute URL. */\n logo: string;\n /** Article `publisher.logo` (Google wants an ImageObject distinct from the brand mark). */\n publisherLogo: string;\n /** Article `image` when the instance declares none. */\n defaultImage: string;\n /** Article `author` when the instance declares none. */\n defaultAuthor: { name: string; url?: string | undefined };\n}\n\n/** Public mailing address rendered as a schema.org PostalAddress. */\nexport interface SeoPostalAddress {\n streetAddress: string;\n addressLocality: string;\n addressRegion: string;\n postalCode: string;\n addressCountry: string;\n}\n\n/** The site-wide Organization entity (Knowledge Graph). */\nexport interface SeoOrganization {\n legalName?: string | undefined;\n description: string;\n sameAs: ReadonlyArray<string>;\n contactPoint: { contactType: string; email: string };\n address?: SeoPostalAddress | undefined;\n}\n\n/** The site-wide WebSite entity (sitelinks search box). */\nexport interface SeoWebsite {\n /** Origin-relative search target carrying the `{search_term_string}` placeholder. */\n searchPath: string;\n}\n\nexport interface SeoConfig {\n /** Canonical origin, no trailing slash — e.g. `https://example.com`. */\n origin: string;\n site: SeoSite;\n organization: SeoOrganization;\n website: SeoWebsite;\n jsonLd?: SeoJsonLdConfig | undefined;\n /**\n * Last-mile override for every head `seoHead` renders, e.g. to append\n * site-specific meta. Runs after the canonical, title template, and JSON-LD.\n */\n transformHead?: ((head: SeoHead) => SeoHead) | undefined;\n}\n","import type {\n Article,\n BreadcrumbList,\n FAQPage,\n Graph,\n IdReference,\n ItemList,\n Organization,\n Service,\n Thing,\n WebSite,\n WithContext,\n} from \"schema-dts\";\n\n/** Any schema.org entity accepted by `schema-dts`. */\nexport type JsonLdNode = Extract<Thing, object>;\n\nimport type { JsonLdDocument } from \"../core/declare\";\n\nexport type { JsonLdDocument };\n\nexport interface JsonLdEntityIds {\n organization: string;\n website: string;\n}\n\nexport type JsonLdEntry =\n | {\n kind: \"organization\";\n source: \"generated\";\n document: WithContext<Organization>;\n }\n | { kind: \"website\"; source: \"generated\"; document: WithContext<WebSite> }\n | { kind: \"article\"; source: \"generated\"; document: WithContext<Article> }\n | { kind: \"service\"; source: \"generated\"; document: WithContext<Service> }\n | { kind: \"faq\"; source: \"generated\"; document: WithContext<FAQPage> }\n | {\n kind: \"breadcrumb\";\n source: \"generated\";\n document: WithContext<BreadcrumbList>;\n }\n | { kind: \"item-list\"; source: \"generated\"; document: WithContext<ItemList> }\n | { kind: \"custom\"; source: \"site\" | \"page\"; document: JsonLdDocument };\n\nexport interface JsonLdTransformContext {\n /** Canonical site origin configured through `createSeo`. */\n origin: string;\n /** Stable identifiers for the plugin's generated site entities. */\n entityIds: JsonLdEntityIds;\n /** Canonical page URL when composition happens for a route. */\n canonical?: string | undefined;\n}\n\n/** Return no document to suppress an entry, one to replace it, or an array to expand it. */\nexport type JsonLdTransformResult =\n | JsonLdDocument\n | ReadonlyArray<JsonLdDocument>\n | false\n | null\n | undefined;\n\nexport type JsonLdTransform = (\n entry: JsonLdEntry,\n context: JsonLdTransformContext,\n) => JsonLdTransformResult;\n\nexport interface SeoJsonLdConfig {\n /** Custom entities included by `generateSiteGraphSchema`. */\n site?:\n | ReadonlyArray<JsonLdDocument>\n | ((entityIds: JsonLdEntityIds) => ReadonlyArray<JsonLdDocument>)\n | undefined;\n /** Open composition hook for generated and custom entries. */\n transform?: JsonLdTransform | undefined;\n}\n\n/** Add the schema.org context to an entity while preserving its concrete type. */\nexport function defineJsonLd<const Node extends JsonLdNode & object>(\n node: Node,\n): Node & { \"@context\": \"https://schema.org\" } {\n return { \"@context\": \"https://schema.org\", ...node };\n}\n\n/** Reference a canonical entity declared elsewhere in the same graph or page. */\nexport function jsonLdRef(id: string): IdReference {\n return { \"@id\": id };\n}\n\n/** Extend a generated or custom document without rebuilding its existing properties. */\nexport function extendJsonLd<\n const Document extends JsonLdDocument,\n const Extension extends object,\n>(document: Document, extension: Extension): Document & Extension {\n return { ...(document as unknown as object), ...extension } as Document &\n Extension;\n}\n\nconst documentNodes = (document: JsonLdDocument): ReadonlyArray<JsonLdNode> => {\n if (\"@graph\" in document) {\n return document[\"@graph\"] as ReadonlyArray<JsonLdNode>;\n }\n const { \"@context\": _context, ...node } = document as unknown as Record<\n string,\n unknown\n >;\n return [node as JsonLdNode];\n};\n\n/** Compose related schema.org documents into one graph without nested `@context` values. */\nexport function jsonLdGraph(documents: ReadonlyArray<JsonLdDocument>): Graph {\n return {\n \"@context\": \"https://schema.org\",\n \"@graph\": documents.flatMap(documentNodes),\n };\n}\n\n/** Apply an optional zero/one/many transform while preserving entry order. */\nexport function composeJsonLd(\n entries: ReadonlyArray<JsonLdEntry>,\n context: JsonLdTransformContext,\n transform?: JsonLdTransform,\n): Array<JsonLdDocument> {\n if (transform === undefined) {\n return entries.map((entry) => entry.document as JsonLdDocument);\n }\n\n return entries.flatMap((entry) => {\n const result = transform(entry, context);\n if (result === undefined || result === null || result === false) return [];\n return Array.isArray(result) ? [...result] : [result as JsonLdDocument];\n });\n}\n","/**\n * JSON-LD structured-data generators.\n *\n * schema.org payloads typed against `schema-dts`, which is a types-only devDep —\n * it erases at build, so this module keeps the entry's zero-runtime-dep rule.\n * The brand values (name, logo, sameAs, the Organization description) are the\n * host's, and arrive through {@link SeoConfig}; the schema construction is ours.\n *\n * @see https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data\n * @see https://schema.org/\n */\n\nimport type {\n Article,\n BreadcrumbList,\n FAQPage,\n Graph,\n ItemList,\n Organization,\n Person,\n Question,\n Service,\n WebSite,\n WithContext,\n} from \"schema-dts\";\n\nimport {\n composeJsonLd as composeEntries,\n jsonLdGraph,\n jsonLdRef,\n type JsonLdDocument,\n type JsonLdEntityIds,\n type JsonLdEntry,\n} from \"./json-ld-composition\";\nimport type { SeoFaq } from \"../core/declare\";\nimport { absoluteUrl, type SeoConfig } from \"./site\";\n\nexport interface ServiceParams {\n name: string;\n description: string;\n serviceType: string;\n provider?: string | undefined;\n areaServed?: string | undefined;\n}\n\n\nexport interface BreadcrumbItem {\n name: string;\n url: string;\n}\n\nexport interface ItemListEntry {\n name: string;\n url: string;\n}\n\nexport interface ArticleParams {\n headline: string;\n description: string;\n image?: string | undefined;\n datePublished: string;\n dateModified?: string | undefined;\n author: {\n name: string;\n url?: string | undefined;\n };\n url: string;\n}\n\n/** The JSON-LD generators, bound to one site identity. */\nexport interface JsonLd {\n readonly entityIds: JsonLdEntityIds;\n /** Brand entity for the Knowledge Graph. Render site-wide (root layout). */\n generateOrganizationSchema: () => WithContext<Organization>;\n /** WebSite entity with a sitelinks search box. Render on the homepage. */\n generateWebsiteSchema: () => WithContext<WebSite>;\n generateServiceSchema: (params: ServiceParams) => WithContext<Service>;\n generateFAQPageSchema: (faqs: SeoFaq[]) => WithContext<FAQPage>;\n generateBreadcrumbSchema: (\n items: BreadcrumbItem[],\n ) => WithContext<BreadcrumbList>;\n /** Describe a visibly rendered, ordered collection of canonical pages. */\n generateItemListSchema: (\n name: string,\n items: ReadonlyArray<ItemListEntry>,\n ) => WithContext<ItemList>;\n generateArticleSchema: (params: ArticleParams) => WithContext<Article>;\n /** Compose the Organization, WebSite, and configured site entities into one graph. */\n generateSiteGraphSchema: () => Graph | undefined;\n /** Apply the configured transform to generated or custom entries. */\n composeJsonLd: (\n entries: ReadonlyArray<JsonLdEntry>,\n context?: { canonical?: string | undefined },\n ) => Array<JsonLdDocument>;\n}\n\nexport function createJsonLd(config: SeoConfig): JsonLd {\n const { origin, site, organization, website } = config;\n const organizationId = `${origin}/#organization`;\n const websiteId = `${origin}/#website`;\n const entityIds = { organization: organizationId, website: websiteId };\n\n const generateOrganizationSchema = (): WithContext<Organization> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"Organization\",\n \"@id\": organizationId,\n name: site.name,\n ...(organization.legalName === undefined\n ? {}\n : { legalName: organization.legalName }),\n url: origin,\n logo: absoluteUrl(origin, site.logo),\n description: organization.description,\n sameAs: [...organization.sameAs],\n contactPoint: {\n \"@type\": \"ContactPoint\",\n contactType: organization.contactPoint.contactType,\n email: organization.contactPoint.email,\n },\n ...(organization.address === undefined\n ? {}\n : {\n address: {\n \"@type\": \"PostalAddress\" as const,\n ...organization.address,\n },\n }),\n });\n\n const generateWebsiteSchema = (): WithContext<WebSite> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"WebSite\",\n \"@id\": websiteId,\n name: site.name,\n url: origin,\n publisher: jsonLdRef(organizationId),\n potentialAction: {\n \"@type\": \"SearchAction\",\n target: {\n \"@type\": \"EntryPoint\",\n urlTemplate: absoluteUrl(origin, website.searchPath),\n },\n query: \"required name=search_term_string\",\n },\n });\n\n const generateServiceSchema = (\n params: ServiceParams,\n ): WithContext<Service> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"Service\",\n name: params.name,\n description: params.description,\n serviceType: params.serviceType,\n provider: {\n \"@type\": \"Organization\",\n ...(params.provider === undefined\n ? { \"@id\": organizationId, url: origin }\n : {}),\n name: params.provider ?? site.name,\n },\n areaServed: params.areaServed ?? \"Worldwide\",\n });\n\n const generateFAQPageSchema = (faqs: SeoFaq[]): WithContext<FAQPage> => {\n const questions: Question[] = faqs.map((faq) => ({\n \"@type\": \"Question\",\n name: faq.question,\n acceptedAnswer: {\n \"@type\": \"Answer\",\n text: faq.answer,\n },\n }));\n\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"FAQPage\",\n mainEntity: questions,\n };\n };\n\n const generateBreadcrumbSchema = (\n items: BreadcrumbItem[],\n ): WithContext<BreadcrumbList> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"BreadcrumbList\",\n itemListElement: items.map((item, index) => ({\n \"@type\": \"ListItem\",\n position: index + 1,\n name: item.name,\n item: `${origin}${item.url}`,\n })),\n });\n\n const generateItemListSchema = (\n name: string,\n items: ReadonlyArray<ItemListEntry>,\n ): WithContext<ItemList> => ({\n \"@context\": \"https://schema.org\",\n \"@type\": \"ItemList\",\n name,\n numberOfItems: items.length,\n itemListElement: items.map((item, index) => ({\n \"@type\": \"ListItem\",\n position: index + 1,\n name: item.name,\n url: `${origin}${item.url}`,\n })),\n });\n\n const generateArticleSchema = (\n params: ArticleParams,\n ): WithContext<Article> => {\n const authorSchema: Person = {\n \"@type\": \"Person\",\n name: params.author.name,\n ...(params.author.url && { url: params.author.url }),\n };\n\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"Article\",\n headline: params.headline,\n description: params.description,\n // Deliberately NOT absolutized: a declared instance image lands verbatim\n // (og:image is where the absolute form is required, and seoHead does that).\n image: params.image ?? absoluteUrl(origin, site.defaultImage),\n datePublished: params.datePublished,\n dateModified: params.dateModified ?? params.datePublished,\n author: authorSchema,\n publisher: {\n \"@type\": \"Organization\",\n \"@id\": organizationId,\n name: site.name,\n logo: {\n \"@type\": \"ImageObject\",\n url: absoluteUrl(origin, site.publisherLogo),\n },\n },\n mainEntityOfPage: {\n \"@type\": \"WebPage\",\n \"@id\": params.url,\n },\n };\n };\n\n const composeJsonLd: JsonLd[\"composeJsonLd\"] = (entries, context = {}) =>\n composeEntries(\n entries,\n {\n origin,\n entityIds,\n ...(context.canonical === undefined\n ? {}\n : { canonical: context.canonical }),\n },\n config.jsonLd?.transform,\n );\n\n const generateSiteGraphSchema = (): Graph | undefined => {\n const configuredSite =\n typeof config.jsonLd?.site === \"function\"\n ? config.jsonLd.site(entityIds)\n : (config.jsonLd?.site ?? []);\n const entries: Array<JsonLdEntry> = [\n {\n kind: \"organization\",\n source: \"generated\",\n document: generateOrganizationSchema(),\n },\n {\n kind: \"website\",\n source: \"generated\",\n document: generateWebsiteSchema(),\n },\n ...configuredSite.map(\n (document): JsonLdEntry => ({\n kind: \"custom\",\n source: \"site\",\n document,\n }),\n ),\n ];\n const documents = composeJsonLd(entries);\n return documents.length === 0 ? undefined : jsonLdGraph(documents);\n };\n\n return {\n entityIds,\n generateOrganizationSchema,\n generateWebsiteSchema,\n generateServiceSchema,\n generateFAQPageSchema,\n generateBreadcrumbSchema,\n generateItemListSchema,\n generateArticleSchema,\n generateSiteGraphSchema,\n composeJsonLd,\n };\n}\n","/**\n * The render layer: one route's SEO declaration plus its per-instance content,\n * composed into the meta/link descriptors TanStack Router renders into <head>,\n * with the JSON-LD that page warrants.\n *\n * {@link createSeo} binds the site identity once (see `site.ts`) and returns\n * the bound API, so a route file calls `seoHead(ctx, instance)` and never sees\n * an origin or a brand name.\n */\n\nimport type { AnyRouteMatch, MetaDescriptor } from \"@tanstack/react-router\";\n\nimport { applyTitleTemplate, type SeoPageHead } from \"../core/declare\";\n\nimport { resolveCrumbTrail } from \"./breadcrumbs\";\nimport type { JsonLdDocument, JsonLdEntry } from \"./json-ld-composition\";\nimport { absoluteUrl, type SeoConfig } from \"./site\";\nimport { createJsonLd, type JsonLd } from \"./json-ld\";\n\n/** Structural subset of TanStack's head() ctx — the leaf match plus the full chain. */\nexport interface SeoHeadCtx {\n matches: ReadonlyArray<AnyRouteMatch>;\n match: AnyRouteMatch;\n}\n\nexport interface SeoHead {\n meta: NonNullable<AnyRouteMatch[\"meta\"]>;\n links: Array<{ rel: \"canonical\"; href: string }>;\n}\n\n/** The render API, bound to one site identity. */\nexport interface Seo extends JsonLd {\n seoHead: (ctx: SeoHeadCtx, instance: SeoPageHead) => SeoHead;\n /**\n * `head()` for a static route that declares its head in `staticData.seo.head`:\n *\n * ```ts\n * createFileRoute(\"/pricing\")({\n * staticData: { seo: { kind: \"page\", sitemap, head: { title, description, faqs } } },\n * head: seo.head,\n * })\n * ```\n *\n * The graph, `pageHeads`, and the checks read the same declaration.\n *\n * Generic so TanStack infers nothing from it: a `head` typed with\n * `AnyRouteMatch` would make the route's search and loader types `any`, and\n * that spreads through the route tree.\n */\n head: <Ctx extends SeoHeadCtx>(ctx: Ctx) => SeoHead;\n}\n\n/** Strip a trailing slash from a pathname, keeping the root \"/\" intact. */\nfunction normalizePathname(pathname: string): string {\n return pathname.length > 1 && pathname.endsWith(\"/\")\n ? pathname.slice(0, -1)\n : pathname;\n}\n\nexport function createSeo(config: SeoConfig): Seo {\n const { origin, site } = config;\n const jsonLd = createJsonLd(config);\n\n const seoHead = (ctx: SeoHeadCtx, instance: SeoPageHead): SeoHead => {\n const canonical = `${origin}${instance.canonicalPath ?? normalizePathname(ctx.match.pathname)}`;\n const title = applyTitleTemplate(ctx.match.staticData.seo?.titleTemplate, instance.title);\n const resolvedOgTitle = instance.ogTitle ?? title;\n const resolvedOgDescription =\n instance.ogDescription ?? instance.description;\n const routeSeo = ctx.match.staticData.seo;\n const { article } = instance;\n const jsonLdEntries: Array<JsonLdEntry> = [];\n\n const meta: Array<MetaDescriptor> = [\n { title },\n { name: \"description\", content: instance.description },\n { property: \"og:title\", content: resolvedOgTitle },\n { property: \"og:description\", content: resolvedOgDescription },\n { property: \"og:type\", content: article ? \"article\" : \"website\" },\n { property: \"og:url\", content: canonical },\n { name: \"twitter:card\", content: \"summary_large_image\" },\n { name: \"twitter:title\", content: resolvedOgTitle },\n { name: \"twitter:description\", content: resolvedOgDescription },\n ];\n\n const robots = instance.robots ?? routeSeo?.robots;\n if (robots !== undefined) {\n meta.push({ name: \"robots\", content: robots });\n }\n\n if (article) {\n if (article.tags?.length) {\n meta.push({ name: \"keywords\", content: article.tags.join(\", \") });\n }\n meta.push(\n { property: \"article:published_time\", content: article.publishedAt },\n {\n property: \"article:modified_time\",\n content: article.modifiedAt ?? article.publishedAt,\n },\n );\n if (article.image !== undefined) {\n const imageUrl = absoluteUrl(origin, article.image);\n meta.push(\n { property: \"og:image\", content: imageUrl },\n { name: \"twitter:image\", content: imageUrl },\n );\n }\n }\n\n if (article) {\n jsonLdEntries.push({\n kind: \"article\",\n source: \"generated\",\n document: jsonLd.generateArticleSchema({\n headline: resolvedOgTitle,\n description: instance.description,\n image: article.image,\n datePublished: article.publishedAt,\n dateModified: article.modifiedAt ?? article.publishedAt,\n author: article.author ?? site.defaultAuthor,\n url: canonical,\n }),\n });\n }\n\n if (!article && instance.keywords) {\n meta.push({ name: \"keywords\", content: instance.keywords.join(\", \") });\n }\n\n if (instance.service) {\n jsonLdEntries.push({\n kind: \"service\",\n source: \"generated\",\n document: jsonLd.generateServiceSchema({\n name: instance.service.name,\n description: instance.service.description ?? instance.description,\n serviceType: instance.service.serviceType,\n }),\n });\n }\n\n if (instance.faqs) {\n jsonLdEntries.push({\n kind: \"faq\",\n source: \"generated\",\n document: jsonLd.generateFAQPageSchema([...instance.faqs]),\n });\n }\n\n if (instance.itemList) {\n jsonLdEntries.push({\n kind: \"item-list\",\n source: \"generated\",\n document: jsonLd.generateItemListSchema(\n instance.itemList.name,\n instance.itemList.items,\n ),\n });\n }\n\n // TanStack accumulates every matched route's head output. Only the current leaf\n // owns the BreadcrumbList; otherwise each parent repeats a progressively stale\n // trail alongside the leaf's canonical trail on nested pages.\n const isLeafMatch = ctx.matches.at(-1)?.id === ctx.match.id;\n const trail = isLeafMatch\n ? (instance.breadcrumbs ?? resolveCrumbTrail(ctx.matches))\n : [];\n if (trail.length >= 2) {\n jsonLdEntries.push({\n kind: \"breadcrumb\",\n source: \"generated\",\n document: jsonLd.generateBreadcrumbSchema(\n trail.map((item) => ({ name: item.name, url: item.path })),\n ),\n });\n }\n\n if (instance.jsonLd) {\n jsonLdEntries.push(\n ...instance.jsonLd.map(\n (document): JsonLdEntry => ({\n kind: \"custom\",\n source: \"page\",\n document,\n }),\n ),\n );\n }\n\n for (const document of jsonLd.composeJsonLd(jsonLdEntries, { canonical })) {\n meta.push({ \"script:ld+json\": document });\n }\n\n // React's head types (JSX.IntrinsicElements['meta']) model only <meta> attributes;\n // TanStack renders `script:ld+json` entries as JSON-LD <script> tags at runtime. The\n // installed @tanstack/react-router augments leaf head meta to those JSX attributes, so\n // the JSON-LD entries are asserted to it (same pattern as an inline root JSON-LD).\n const head: SeoHead = {\n meta: meta as NonNullable<AnyRouteMatch[\"meta\"]>,\n links: [{ rel: \"canonical\", href: canonical }],\n };\n return config.transformHead === undefined ? head : config.transformHead(head);\n };\n\n const head = <Ctx extends SeoHeadCtx>(ctx: Ctx): SeoHead => {\n const declared = ctx.match.staticData.seo?.head;\n if (declared === undefined) {\n throw new Error(`seo.head needs staticData.seo.head on route ${ctx.match.routeId}`);\n }\n return seoHead(ctx, declared);\n };\n\n return { seoHead, head, ...jsonLd };\n}\n"],"mappings":"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"}
|