@uniweb/build 0.14.5 → 0.14.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/package.json +10 -7
  2. package/src/generate-entry.js +6 -2
  3. package/src/hosts/index.js +0 -1
  4. package/src/hosts/s3-cloudfront.js +0 -5
  5. package/src/i18n/extract.js +15 -0
  6. package/src/index.js +12 -2
  7. package/src/prerender.js +14 -10
  8. package/src/resolve-data-schema.js +643 -0
  9. package/src/runtime-schema.js +82 -124
  10. package/src/schema.js +6 -0
  11. package/src/search/collections.js +54 -0
  12. package/src/site/assets.js +33 -1
  13. package/src/site/build-site-data.js +42 -3
  14. package/src/site/content-collector.js +24 -14
  15. package/src/site/data-fetcher.js +3 -4
  16. package/src/site/deploy-config-writer.js +1 -1
  17. package/src/site/deploy-config.js +1 -2
  18. package/src/site/nav-visibility.js +29 -0
  19. package/src/utils/classify-package.js +45 -1
  20. package/src/uwx/backfill.js +408 -0
  21. package/src/uwx/collection-source.js +124 -0
  22. package/src/uwx/collections-config.js +125 -0
  23. package/src/uwx/collections-project.js +331 -0
  24. package/src/uwx/collections.js +625 -0
  25. package/src/uwx/crc32.js +26 -0
  26. package/src/uwx/data-schema.js +263 -0
  27. package/src/uwx/entity-document.js +113 -0
  28. package/src/uwx/entity-types.js +15 -0
  29. package/src/uwx/folder.js +119 -0
  30. package/src/uwx/foundation-schema.js +166 -0
  31. package/src/uwx/identity.js +149 -0
  32. package/src/uwx/index.js +108 -0
  33. package/src/uwx/locale-sync.js +371 -0
  34. package/src/uwx/localize.js +21 -0
  35. package/src/uwx/manifest.js +123 -0
  36. package/src/uwx/package.js +124 -0
  37. package/src/uwx/project-writer.js +301 -0
  38. package/src/uwx/registry-package.js +195 -0
  39. package/src/uwx/site-project.js +583 -0
  40. package/src/uwx/site.js +627 -0
  41. package/src/uwx/sync-package.js +132 -0
  42. package/src/uwx/uuid.js +44 -0
  43. package/src/uwx/yaml-upsert.js +53 -0
  44. package/src/uwx/zip.js +135 -0
  45. package/src/validate-data.js +465 -0
  46. package/src/vite-foundation-plugin.js +1 -5
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@uniweb/build",
3
- "version": "0.14.5",
3
+ "version": "0.14.7",
4
4
  "description": "Build tooling for the Uniweb Component Web Platform",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./src/index.js",
8
8
  "./schema": "./src/schema.js",
9
+ "./validate": "./src/validate-data.js",
9
10
  "./images": "./src/images.js",
10
11
  "./generate-entry": "./src/generate-entry.js",
11
12
  "./vite-plugin": "./src/vite-foundation-plugin.js",
@@ -19,6 +20,7 @@
19
20
  "./hosts": "./src/hosts/index.js",
20
21
  "./i18n": "./src/i18n/index.js",
21
22
  "./search": "./src/search/index.js",
23
+ "./uwx": "./src/uwx/index.js",
22
24
  "./import-map-plugin": "./src/import-map-plugin.js"
23
25
  },
24
26
  "bin": {
@@ -49,20 +51,21 @@
49
51
  "node": ">=20.19"
50
52
  },
51
53
  "devDependencies": {
52
- "jest": "^29.7.0"
54
+ "vitest": "^4.1.7"
53
55
  },
54
56
  "dependencies": {
55
- "@citestyle/bibtex": "^1.0.0",
57
+ "@citestyle/bibtex": "^1.1.0",
56
58
  "esbuild": "^0.21.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.27.0",
57
59
  "js-yaml": "^4.1.0",
58
60
  "sharp": "^0.33.2",
59
61
  "yaml": "^2.5.0",
62
+ "@uniweb/content-writer": "0.2.5",
60
63
  "@uniweb/theming": "0.1.3"
61
64
  },
62
65
  "optionalDependencies": {
63
- "@uniweb/runtime": "0.8.14",
66
+ "@uniweb/runtime": "0.8.15",
64
67
  "@uniweb/schemas": "0.2.1",
65
- "@uniweb/content-reader": "1.1.11"
68
+ "@uniweb/content-reader": "1.1.12"
66
69
  },
67
70
  "peerDependencies": {
68
71
  "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
@@ -71,7 +74,7 @@
71
74
  "@tailwindcss/vite": "^4.0.0",
72
75
  "@vitejs/plugin-react": "^4.0.0 || ^5.0.0",
73
76
  "vite-plugin-svgr": "^4.0.0",
74
- "@uniweb/core": "0.7.11"
77
+ "@uniweb/core": "0.7.12"
75
78
  },
76
79
  "peerDependenciesMeta": {
77
80
  "vite": {
@@ -97,6 +100,6 @@
97
100
  }
98
101
  },
99
102
  "scripts": {
100
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
103
+ "test": "vitest run"
101
104
  }
102
105
  }
@@ -24,6 +24,7 @@ import { existsSync } from 'node:fs'
24
24
  import { join, dirname } from 'node:path'
25
25
  import { discoverComponents, discoverLayoutsInPath } from './schema.js'
26
26
  import { extractAllRuntimeSchemas, extractAllLayoutRuntimeSchemas } from './runtime-schema.js'
27
+ import { collectSchemaRefs, buildDataSchemaMap } from './resolve-data-schema.js'
27
28
 
28
29
  /**
29
30
  * Packages that may be bundled inside a foundation but require single-instance
@@ -299,8 +300,11 @@ export async function generateEntryPoint(srcDir, outputPath = null, options = {}
299
300
  // Check for foundation exports (props, vars, etc.)
300
301
  const foundationExports = detectFoundationExports(srcDir)
301
302
 
302
- // Extract per-component runtime metadata from meta.js files
303
- const meta = extractAllRuntimeSchemas(components)
303
+ // Resolve the data schemas referenced by section bindings, then extract
304
+ // per-component runtime metadata (which lean-extracts field defaults from
305
+ // the resolved schemas into meta.schemas[<key>]).
306
+ const dataSchemaMap = await buildDataSchemaMap(collectSchemaRefs(components), { srcDir })
307
+ const meta = extractAllRuntimeSchemas(components, dataSchemaMap)
304
308
 
305
309
  // Extract per-layout runtime metadata from meta.js files
306
310
  const layoutMeta = extractAllLayoutRuntimeSchemas(layouts)
@@ -36,7 +36,6 @@
36
36
  * `postBuild` is required. `deploy` is optional — adapters like
37
37
  * 'netlify' don't need it (Netlify deploys from git).
38
38
  *
39
- * See kb/framework/plans/static-host-deploy-adapters.md for the design.
40
39
  * Deferred (not in V1): user-defined adapters via `deploy.adapter:
41
40
  * ./my-adapter.js`. The current registry is a static built-in lookup.
42
41
  */
@@ -23,8 +23,6 @@
23
23
  * CloudFront Function itself are out of scope (one-time IaC). The first
24
24
  * deploy explains what the user still needs to do; subsequent deploys
25
25
  * just push files and invalidate.
26
- *
27
- * See kb/framework/plans/static-host-deploy-adapters.md for the design.
28
26
  */
29
27
 
30
28
  import { writeFile, unlink, readFile } from 'node:fs/promises'
@@ -80,9 +78,6 @@ const REDIRECTS_FILE = '_redirects'
80
78
  * to `uniweb deploy` against uniweb-edge), so the rule is:
81
79
  * - registry ref ('@ns/name@ver'), https:// URL, or { url } object → linked
82
80
  * - everything else (file: ref, workspace path) → standalone
83
- *
84
- * See kb/framework/architecture/site-foundation-runtime-model.md for
85
- * the standalone / linked vocabulary.
86
81
  */
87
82
  function detectFoundationMode(siteContent) {
88
83
  const foundation = siteContent?.config?.foundation
@@ -143,6 +143,21 @@ function extractFromSection(section, pageRoute, units) {
143
143
  * @param {Object} context - Current context (page, section)
144
144
  * @param {Object} units - Units accumulator
145
145
  */
146
+ /**
147
+ * Extract the translatable units from a SINGLE ProseMirror content doc, keyed by
148
+ * the same 8-char hash the site-wide extractor uses. Reused by the sync producer
149
+ * to build a section's per-locale structural translation map (so there is one
150
+ * extraction implementation, not a second copy).
151
+ *
152
+ * @param {Object} doc - a ProseMirror document (`{ type: 'doc', content: [...] }`)
153
+ * @returns {Object} `{ [hash]: { source, field, contexts } }`
154
+ */
155
+ export function extractUnitsFromDoc(doc) {
156
+ const units = {}
157
+ if (doc && doc.content) extractFromProseMirrorDoc(doc, { page: '', section: '' }, units)
158
+ return units
159
+ }
160
+
146
161
  function extractFromProseMirrorDoc(doc, context, units) {
147
162
  if (!doc.content) return
148
163
 
package/src/index.js CHANGED
@@ -14,6 +14,13 @@ export {
14
14
  getExposedComponents,
15
15
  } from './schema.js'
16
16
 
17
+ // Data-conformance checking (your content vs the schemas your foundation declares)
18
+ export {
19
+ validateItem,
20
+ validateDataInputs,
21
+ isStaticallyCheckable,
22
+ } from './validate-data.js'
23
+
17
24
  // Entry point generation
18
25
  export {
19
26
  generateEntryPoint,
@@ -53,8 +60,11 @@ export { defineSiteConfig, detectFoundationType } from './site/config.js'
53
60
  // Foundation source root resolution (reads package.json::main)
54
61
  export { resolveFoundationSrcDir, resolveFoundationSrcPath } from './utils/foundation-source-root.js'
55
62
 
56
- // Package classification (foundation vs site)
57
- export { classifyPackage, isExtensionPackage } from './utils/classify-package.js'
63
+ // Package classification (foundation vs site vs standalone schemas package)
64
+ export { classifyPackage, isExtensionPackage, isSchemasPackage } from './utils/classify-package.js'
65
+
66
+ // Standalone schemas-package discovery (the foundation-less register input)
67
+ export { collectStandaloneSchemas } from './resolve-data-schema.js'
58
68
 
59
69
  // Default export is the combined Vite plugin
60
70
  export { default } from './vite-foundation-plugin.js'
package/src/prerender.js CHANGED
@@ -11,7 +11,7 @@ import { readFile, writeFile, mkdir } from 'node:fs/promises'
11
11
  import { existsSync, readdirSync, statSync } from 'node:fs'
12
12
  import { join, dirname, resolve } from 'node:path'
13
13
  import { pathToFileURL } from 'node:url'
14
- import { executeFetch, mergeDataIntoContent, singularize } from './site/data-fetcher.js'
14
+ import { executeFetch, mergeDataIntoContent } from './site/data-fetcher.js'
15
15
  import { shouldSplitContent } from './site/split-content.js'
16
16
  import { getAdapter } from './hosts/index.js'
17
17
  import { detectCiContext } from './hosts/detect-ci-context.js'
@@ -25,21 +25,29 @@ import { detectCiContext } from './hosts/detect-ci-context.js'
25
25
  * 2. Project root with dist subdir (dev layout, e.g., project/effects/dist/entry.js)
26
26
  * 3. Original URL (absolute or remote — let import() handle it)
27
27
  */
28
- function resolveExtensionPath(url, distDir, projectRoot) {
28
+ export function resolveExtensionPath(url, distDir, projectRoot) {
29
29
  // Only resolve URLs that look like root-relative paths
30
30
  if (url.startsWith('/')) {
31
31
  // Try dist directory first (production: files copied to site/dist/)
32
32
  const distPath = join(distDir, url)
33
33
  if (existsSync(distPath)) return distPath
34
34
 
35
- // Try project root with dist subdir (dev layout: effects/dist/entry.js)
36
- // "/effects/entry.js" "effects/dist/entry.js"
35
+ // Workspace layouts: "/effects/entry.js" → "<pkg>/dist/entry.js", checked
36
+ // both at the project root and under an `extensions/` parent — the standard
37
+ // multi-foundation layout puts extensions in `extensions/<name>/`, so the
38
+ // bare-root candidate alone misses the built module and prerender can't load
39
+ // the extension.
37
40
  const parts = url.slice(1).split('/')
38
41
  if (parts.length >= 2) {
39
42
  const pkgName = parts[0]
40
43
  const rest = parts.slice(1).join('/')
41
- const devPath = join(projectRoot, pkgName, 'dist', rest)
42
- if (existsSync(devPath)) return devPath
44
+ const candidates = [
45
+ join(projectRoot, pkgName, 'dist', rest),
46
+ join(projectRoot, 'extensions', pkgName, 'dist', rest),
47
+ ]
48
+ for (const devPath of candidates) {
49
+ if (existsSync(devPath)) return devPath
50
+ }
43
51
  }
44
52
  }
45
53
 
@@ -164,7 +172,6 @@ function expandDynamicPages(pages, pageFetchedData, onProgress) {
164
172
 
165
173
  const items = parentData.data
166
174
  const schema = parentData.schema
167
- const singularSchema = singularize(schema)
168
175
 
169
176
  onProgress(` Expanding ${page.route} → ${items.length} pages from ${schema}`)
170
177
 
@@ -192,7 +199,6 @@ function expandDynamicPages(pages, pageFetchedData, onProgress) {
192
199
  paramName,
193
200
  paramValue,
194
201
  schema, // Plural: 'articles'
195
- singularSchema, // Singular: 'article'
196
202
  currentItem: item, // The item for this specific route
197
203
  allItems: items, // All items from parent
198
204
  }
@@ -405,7 +411,6 @@ function getOutputPath(distDir, route) {
405
411
  * @param {function} options.onProgress - Progress callback
406
412
  * @param {string} [options.host] - Name of the host adapter whose postBuild
407
413
  * hook runs after pages are written. Default: 'cloudflare-pages'.
408
- * See kb/framework/plans/static-host-deploy-adapters.md.
409
414
  * @returns {Promise<{pages: number, files: string[]}>}
410
415
  */
411
416
  export async function prerenderSite(siteDir, options = {}) {
@@ -705,7 +710,6 @@ export async function prerenderSite(siteDir, options = {}) {
705
710
  // distributionId, …) at deploy time, it passes deploy.yml's resolved
706
711
  // target to the adapter's deploy hook directly. postBuild consumes
707
712
  // only the host name and the ciContext (artifact provenance).
708
- // See kb/framework/plans/static-host-deploy-adapters.md.
709
713
  const ciContext = detectCiContext()
710
714
  const hostName = hostOverride || ciContext?.host || 'cloudflare-pages'
711
715
  const adapter = getAdapter(hostName)