@uniweb/build 0.11.4 → 0.11.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniweb/build",
3
- "version": "0.11.4",
3
+ "version": "0.11.6",
4
4
  "description": "Build tooling for the Uniweb Component Web Platform",
5
5
  "type": "module",
6
6
  "exports": {
@@ -58,8 +58,8 @@
58
58
  "@uniweb/theming": "0.1.3"
59
59
  },
60
60
  "optionalDependencies": {
61
+ "@uniweb/runtime": "0.8.8",
61
62
  "@uniweb/content-reader": "1.1.7",
62
- "@uniweb/runtime": "0.8.6",
63
63
  "@uniweb/schemas": "0.2.1"
64
64
  },
65
65
  "peerDependencies": {
@@ -69,7 +69,7 @@
69
69
  "@tailwindcss/vite": "^4.0.0",
70
70
  "@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
71
71
  "vite-plugin-svgr": "^4.0.0",
72
- "@uniweb/core": "0.7.5"
72
+ "@uniweb/core": "0.7.7"
73
73
  },
74
74
  "peerDependenciesMeta": {
75
75
  "vite": {
@@ -31,8 +31,9 @@ export {
31
31
  singularize,
32
32
  } from '../site/data-fetcher.js'
33
33
 
34
- // Cross-reference registry. Walks the document tree, finds every
35
- // block-level element with a {#id} attribute, registers the id with
36
- // its inferred kind + counter. Consumed by the framework's <Ref>
37
- // component to render `[#id]` cross-references.
38
- export { buildXrefRegistry } from '../site/xref-registry.js'
34
+ // Cross-reference registry moved out of build into kit
35
+ // (@uniweb/kit/xref). Foundations that need cross-references import
36
+ // `buildXrefRegistry` from there and re-export it via
37
+ // `foundation.xref.build`; the runtime calls it during initialization
38
+ // (setup.js / ssr-renderer.js). See framework/kit/src/xref/registry.js
39
+ // for the implementation.
@@ -1,153 +0,0 @@
1
- /**
2
- * Cross-reference registry — populated at content-collection time.
3
- *
4
- * Walks the parsed document tree to find every block-level element
5
- * carrying a {#id} attribute, infers the element's kind from its node
6
- * type, and records the entry with a per-kind counter. The result
7
- * attaches to siteContent.xref and is consumed by the framework's
8
- * <Ref> component to render `[#id]` cross-references.
9
- *
10
- * Built-in kinds:
11
- * - heading → 'section' (hierarchical counter: 1, 1.1, 1.1.1, 2, …)
12
- * - image → 'figure' (flat arabic counter)
13
- * - math_display → 'equation' (flat arabic counter)
14
- * - table → 'table' (flat arabic counter)
15
- *
16
- * Foundation extensions: foundations may declare additional kinds via
17
- * `foundation.xref.kinds`. The id-collection pass uses the foundation's
18
- * declared `prefix` (e.g. `thm` → `theorem`) to classify ids that don't
19
- * land on a built-in element type.
20
- *
21
- * The registry is per-document, not per-page: counters span the whole
22
- * document so authors get consistent numbering even when their document
23
- * spans multiple pages. (For page-local counter resets, foundations can
24
- * declare `resetOn: 'chapter'` on a kind — applied during render, not
25
- * here.)
26
- *
27
- * Output shape:
28
- * {
29
- * entries: {
30
- * <id>: {
31
- * id, // the id itself
32
- * kind, // 'figure' | 'equation' | 'section' | 'table' | <foundation-declared>
33
- * counter, // number for flat kinds, dotted string for hierarchical
34
- * counterText, // displayable counter ('3', '3.2')
35
- * sourcePath, // page route the id was declared on (for back-refs)
36
- * },
37
- * },
38
- * }
39
- */
40
-
41
- const KIND_BY_TYPE = {
42
- heading: 'section',
43
- image: 'figure',
44
- math_display: 'equation',
45
- table: 'table',
46
- }
47
-
48
- export function buildXrefRegistry(siteContent, options = {}) {
49
- const { foundationKinds = {}, onWarn = (msg) => console.warn(msg) } = options
50
-
51
- const entries = {}
52
- const flatCounters = {} // kind -> next integer counter (figure, equation, table, foundation-declared kinds)
53
- const sectionStack = [] // hierarchical counters per heading level
54
-
55
- // Index foundation prefixes for id-prefix inference.
56
- const prefixToKind = {}
57
- for (const [kind, meta] of Object.entries(foundationKinds)) {
58
- if (meta?.prefix) prefixToKind[meta.prefix] = kind
59
- }
60
-
61
- function nextFlat(kind) {
62
- flatCounters[kind] = (flatCounters[kind] || 0) + 1
63
- return flatCounters[kind]
64
- }
65
-
66
- // Track the shallowest heading depth seen — chapter content commonly
67
- // starts at h2 (chapter title is rendered separately as h1 by the
68
- // foundation), so the first encountered level becomes the document's
69
- // top counter level. Re-anchoring: if a later heading appears at a
70
- // shallower level than `topLevel`, drop topLevel down to match.
71
- let topLevel = null
72
-
73
- function nextHierarchical(level) {
74
- if (topLevel == null || level < topLevel) topLevel = level
75
- const depth = level - topLevel + 1 // 1-based depth from the document's top level
76
-
77
- // Trim deeper levels when surfacing back to a shallower heading.
78
- while (sectionStack.length >= depth) sectionStack.pop()
79
- while (sectionStack.length < depth - 1) sectionStack.push(1) // implicit parents start at 1
80
- sectionStack.push((sectionStack[depth - 1] || 0) + 1)
81
- sectionStack.length = depth
82
- return sectionStack.slice().join('.')
83
- }
84
-
85
- function inferKind(node) {
86
- // 1. Node-type-based: built-ins.
87
- const builtin = KIND_BY_TYPE[node.type]
88
- if (builtin) return builtin
89
- // 2. Explicit kind attribute on the node ({.kind} or kind=…).
90
- if (node.attrs?.kind && (KIND_BY_TYPE[node.attrs.kind] || foundationKinds[node.attrs.kind])) {
91
- return node.attrs.kind
92
- }
93
- // 3. Foundation-declared prefix on the id.
94
- const id = node.attrs?.id
95
- if (id && id.includes('-')) {
96
- const prefix = id.slice(0, id.indexOf('-'))
97
- if (prefixToKind[prefix]) return prefixToKind[prefix]
98
- }
99
- return null
100
- }
101
-
102
- function visit(node, sourcePath) {
103
- if (!node || typeof node !== 'object') return
104
-
105
- // Headings get a hierarchical counter regardless of whether they
106
- // carry an id — the {#id} just labels them; the counter itself is
107
- // assigned by tree position.
108
- let counter = null
109
- let counterText = null
110
- if (node.type === 'heading') {
111
- const level = Math.max(1, Math.min(6, node.attrs?.level || 1))
112
- counterText = nextHierarchical(level)
113
- counter = counterText
114
- }
115
-
116
- const id = node.attrs?.id
117
- if (id) {
118
- const kind = inferKind(node)
119
- if (!kind) {
120
- onWarn(`[xref] {#${id}} on unrecognized element type "${node.type}" — ignored`)
121
- } else if (entries[id]) {
122
- onWarn(`[xref] duplicate id "${id}" — keeping first registration`)
123
- } else {
124
- if (counter == null) {
125
- counter = nextFlat(kind)
126
- counterText = String(counter)
127
- }
128
- entries[id] = { id, kind, counter, counterText, sourcePath: sourcePath || '' }
129
- }
130
- } else if (node.type === 'heading') {
131
- // Heading without an id still advances the counter — but we don't
132
- // register it (no way to reference it). The advance is needed so
133
- // that the *next* labeled heading gets the right hierarchical
134
- // counter.
135
- // counter already computed above; just no entry.
136
- }
137
-
138
- if (Array.isArray(node.content)) {
139
- for (const child of node.content) visit(child, sourcePath)
140
- }
141
- }
142
-
143
- for (const page of siteContent.pages || []) {
144
- for (const section of page.sections || []) {
145
- const content = section.content
146
- if (content?.type === 'doc' && Array.isArray(content.content)) {
147
- for (const child of content.content) visit(child, page.route)
148
- }
149
- }
150
- }
151
-
152
- return { entries }
153
- }