@uniweb/unipress 0.8.20 → 0.9.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/package.json +4 -4
- package/src/content-loader.js +55 -21
- package/src/templates-data.js +42 -42
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/unipress",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Compile a content directory into a document (PDF, EPUB, Paged.js HTML, Typst source bundle, DOCX, XLSX) using a Uniweb foundation. Five built-in templates: book, monograph, report, data-report, directory.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"react": "^19.0.0",
|
|
51
51
|
"react-dom": "^19.0.0",
|
|
52
52
|
"@uniweb/build": "^0.33.0",
|
|
53
|
-
"@uniweb/content-reader": "^1.2.4",
|
|
54
53
|
"@uniweb/runtime": "^0.13.5",
|
|
55
|
-
"@uniweb/
|
|
56
|
-
"@uniweb/
|
|
54
|
+
"@uniweb/semantic-parser": "^1.4.0",
|
|
55
|
+
"@uniweb/content-reader": "^1.2.4",
|
|
56
|
+
"@uniweb/core": "^0.16.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"vitest": "^4.1.7"
|
package/src/content-loader.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import { existsSync, readdirSync } from 'node:fs'
|
|
12
12
|
import { resolve, join, basename } from 'node:path'
|
|
13
|
-
import { collectSiteContent,
|
|
13
|
+
import { collectSiteContent, processQueries } from '@uniweb/build/content'
|
|
14
14
|
import { detectConfigFile, CONFIG_FILE_NAMES } from './document-yml.js'
|
|
15
15
|
import { ContentDirectoryError, DocumentYmlError } from './errors.js'
|
|
16
16
|
|
|
@@ -32,7 +32,7 @@ function attachData(section, schema, data) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function
|
|
35
|
+
function findQueryRecords(fetchConfig, resolved) {
|
|
36
36
|
if (!fetchConfig?.path || !fetchConfig?.schema) return null
|
|
37
37
|
const m = COLLECTION_PATH_RE.exec(fetchConfig.path)
|
|
38
38
|
if (!m) return null
|
|
@@ -51,7 +51,7 @@ function findCollectionRecords(fetchConfig, resolved) {
|
|
|
51
51
|
function attachSectionFetches(sections, resolved, cascade = null) {
|
|
52
52
|
if (!Array.isArray(sections)) return
|
|
53
53
|
for (const section of sections) {
|
|
54
|
-
const records =
|
|
54
|
+
const records = findQueryRecords(section.fetch, resolved)
|
|
55
55
|
if (records) attachData(section, section.fetch.schema, records)
|
|
56
56
|
if (cascade) attachData(section, cascade.schema, cascade.records)
|
|
57
57
|
if (Array.isArray(section.subsections) && section.subsections.length) {
|
|
@@ -65,7 +65,7 @@ function attachSectionFetches(sections, resolved, cascade = null) {
|
|
|
65
65
|
* `parsedContent.data` so the SSR render pipeline reads populated data
|
|
66
66
|
* synchronously (no `useFetched` round-trip; no `public/` directory).
|
|
67
67
|
*
|
|
68
|
-
* In a regular Uniweb site build, the Vite plugin runs `
|
|
68
|
+
* In a regular Uniweb site build, the Vite plugin runs `processQueries`
|
|
69
69
|
* + `writeCollectionFiles` and the runtime resolves `fetch:` declarations
|
|
70
70
|
* over HTTP at render time. Under `unipress compile` neither of those
|
|
71
71
|
* happens — there's no public dir, and SSR skips effects. We close the
|
|
@@ -81,15 +81,36 @@ function attachSectionFetches(sections, resolved, cascade = null) {
|
|
|
81
81
|
* fetches, refine configs, and array-form `fetch: [...]` declarations
|
|
82
82
|
* are left untouched (those have their own gaps; out of scope here).
|
|
83
83
|
*/
|
|
84
|
-
async function
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
84
|
+
async function resolveLocalQueries(siteContent, sitePath) {
|
|
85
|
+
// ⛔ **`config.queries`, not `config.collections`.** The build renamed both the
|
|
86
|
+
// payload key and the function on 2026-08-29 (`@uniweb/build` e442738, "no
|
|
87
|
+
// identifier in build says `collection` any more") and this file was not
|
|
88
|
+
// carried across — the same shape that left `hosting` reading a key nothing
|
|
89
|
+
// emits, noted in `framework/CLAUDE.md` § *Decoupling is the architecture*.
|
|
90
|
+
//
|
|
91
|
+
// ⚠️ **The crash was the lucky half.** `processCollections` being undefined
|
|
92
|
+
// only threw because our own fixture still declared the retired
|
|
93
|
+
// `site.yml::collections`, which is passed through verbatim as an unrecognised
|
|
94
|
+
// key. A CURRENT site declares `queries:`, so this read returned undefined,
|
|
95
|
+
// the guard below returned early, and unipress compiled documents with **no
|
|
96
|
+
// query data and no error** — silent, which is why four days passed.
|
|
97
|
+
//
|
|
98
|
+
// Local identifiers keep the older word deliberately: `framework/CLAUDE.md`
|
|
99
|
+
// says renaming those is churn. Only the two names that cross a package
|
|
100
|
+
// boundary had to move.
|
|
101
|
+
const queriesConfig = siteContent?.config?.queries
|
|
102
|
+
if (!queriesConfig || typeof queriesConfig !== 'object') return
|
|
103
|
+
if (Object.keys(queriesConfig).length === 0) return
|
|
104
|
+
|
|
105
|
+
// ⛔ Third arg is the ENTITIES POOL override, not the site root. Passing
|
|
106
|
+
// `sitePath` made the pool resolve to `<site>/{schema}/` instead of
|
|
107
|
+
// `<site>/entities/{schema}/`, so every query matched nothing. `null` takes
|
|
108
|
+
// the default, which is what a site without `paths.entities` wants — the
|
|
109
|
+
// same value `@uniweb/build`'s own plugin computes (`paths.entities || null`).
|
|
110
|
+
const resolved = await processQueries(
|
|
92
111
|
sitePath,
|
|
112
|
+
queriesConfig,
|
|
113
|
+
siteContent?.config?.paths?.entities || null,
|
|
93
114
|
'/',
|
|
94
115
|
)
|
|
95
116
|
|
|
@@ -97,7 +118,7 @@ async function resolveLocalCollections(siteContent, sitePath) {
|
|
|
97
118
|
// Page-level fetch cascades to every section on the page — top-level
|
|
98
119
|
// and nested alike. attachSectionFetches threads it through the whole
|
|
99
120
|
// section tree; a section's own fetch still takes priority.
|
|
100
|
-
const pageRecords =
|
|
121
|
+
const pageRecords = findQueryRecords(page.fetch, resolved)
|
|
101
122
|
const cascade = pageRecords
|
|
102
123
|
? { schema: page.fetch.schema, records: pageRecords }
|
|
103
124
|
: null
|
|
@@ -108,16 +129,29 @@ async function resolveLocalCollections(siteContent, sitePath) {
|
|
|
108
129
|
// (regardless of its own page's fetch declaration) can self-bootstrap
|
|
109
130
|
// — e.g., a Cite inset rendering inside a Chapter on page A needs the
|
|
110
131
|
// bibliography records that the Bibliography section declared on page
|
|
111
|
-
// B. Foundations read this via `block.website.config.
|
|
132
|
+
// B. Foundations read this via `block.website.config.recordsByQuery.<name>`
|
|
112
133
|
// as a synchronous fallback.
|
|
134
|
+
//
|
|
135
|
+
// ⭐ **`recordsByQuery`, because "collections" named nothing.** This key is
|
|
136
|
+
// unipress's own — written here, read only by unipress foundations, never
|
|
137
|
+
// emitted or read by `@uniweb/build`. It was called `collections`, which
|
|
138
|
+
// collided with the build's payload key of the same name and said nothing
|
|
139
|
+
// about what it held. *[Diego, 2026-09-02]* — "collect" as an act is fine;
|
|
140
|
+
// as a set of things it is useless, because it gives no sense of what KIND of
|
|
141
|
+
// things, where `records`, `queries` and `entities` each carry meaning.
|
|
142
|
+
//
|
|
143
|
+
// This holds **records, keyed by the query that resolved them**, and the name
|
|
144
|
+
// now says exactly that. ⚠️ Not `config.records`, which the framework already
|
|
145
|
+
// uses for live record URL patterns (`core/src/query-address.js`).
|
|
146
|
+
//
|
|
147
|
+
// The value is the record ARRAY directly, not `{ records: [...] }`. The
|
|
148
|
+
// wrapper existed to merge with a pre-existing `config.collections` from the
|
|
149
|
+
// build — which cannot happen now that the build emits `queries` — and
|
|
150
|
+
// `recordsByQuery.<name>.records` would have said "records" twice.
|
|
113
151
|
if (!siteContent.config) siteContent.config = {}
|
|
114
|
-
if (!siteContent.config.
|
|
152
|
+
if (!siteContent.config.recordsByQuery) siteContent.config.recordsByQuery = {}
|
|
115
153
|
for (const name of Object.keys(resolved)) {
|
|
116
|
-
|
|
117
|
-
siteContent.config.collections[name] = {
|
|
118
|
-
...(existing && typeof existing === 'object' ? existing : {}),
|
|
119
|
-
records: resolved[name],
|
|
120
|
-
}
|
|
154
|
+
siteContent.config.recordsByQuery[name] = resolved[name]
|
|
121
155
|
}
|
|
122
156
|
}
|
|
123
157
|
|
|
@@ -196,7 +230,7 @@ export async function loadContent(dir, options = {}) {
|
|
|
196
230
|
throw err
|
|
197
231
|
}
|
|
198
232
|
|
|
199
|
-
await
|
|
233
|
+
await resolveLocalQueries(content, sitePath)
|
|
200
234
|
|
|
201
235
|
// Cross-reference registry is built AFTER the foundation loads, in
|
|
202
236
|
// orchestrator.loadAndInit, so foundation-declared `xref.kinds`
|