uniweb 0.12.55 → 0.12.57
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 +7 -7
- package/partials/agents.md +4 -2
- package/src/commands/build.js +17 -2
- package/src/commands/i18n.js +2 -1
- package/src/commands/publish.js +4 -1
- package/src/commands/register.js +11 -0
- package/src/framework-index.json +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.57",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,14 +41,14 @@
|
|
|
41
41
|
"js-yaml": "^4.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/core": "0.7.
|
|
45
|
-
"@uniweb/kit": "0.9.
|
|
46
|
-
"@uniweb/runtime": "0.8.
|
|
44
|
+
"@uniweb/core": "0.7.23",
|
|
45
|
+
"@uniweb/kit": "0.9.30",
|
|
46
|
+
"@uniweb/runtime": "0.8.29"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@uniweb/
|
|
50
|
-
"@uniweb/
|
|
51
|
-
"@uniweb/
|
|
49
|
+
"@uniweb/build": "0.14.37",
|
|
50
|
+
"@uniweb/content-reader": "1.1.14",
|
|
51
|
+
"@uniweb/semantic-parser": "1.1.18"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
54
|
"@uniweb/build": {
|
package/partials/agents.md
CHANGED
|
@@ -845,6 +845,8 @@ seo:
|
|
|
845
845
|
|
|
846
846
|
**Localized URLs:** On a multilingual site (`languages:` in site.yml), a page's `slug: { <lang>: <segment> }` gives it a native URL segment per language (`/about` → `/fr/a-propos`); the folder name stays the canonical route. Nested folders compose automatically, and localized URLs flow through navigation, the language switcher, and the sitemap.
|
|
847
847
|
|
|
848
|
+
**Draft languages:** `publishLanguages: [en, fr]` in site.yml lists which declared languages a published build ships — unlisted ones stay dev-previewable drafts. Absent field = publish all declared; the default language must be listed.
|
|
849
|
+
|
|
848
850
|
**Content-less containers:** Folders with `page.yml` but no markdown are structural groups. They appear in `getPageHierarchy()` with `hasContent: false` and their own title/label. When visited directly, the runtime auto-redirects to the first descendant with content. This supports hierarchical navigation (courses → modules → lessons) at any depth.
|
|
849
851
|
|
|
850
852
|
### Lists as Navigation Menus
|
|
@@ -1181,7 +1183,7 @@ function Article({ content, block }) {
|
|
|
1181
1183
|
|
|
1182
1184
|
Components can ignore keys in `content.data` they don't need — the same way unused `params` are ignored.
|
|
1183
1185
|
|
|
1184
|
-
**Declaring data schemas.** `meta.js` declares the schema for each `content.data` key with a single `data:` field — there is no separate `schemas:` key. Each entry's value is one of: a **named ref** (`'@/article'` resolves to this foundation's `foundation/schemas/article.{js,json,yml}`; `'@std/person'` is a shared standard), an **inline field map** (`{ field: { type, default } }`), or an **inline rich-form** (`{ fields: [...] }`, an editor form). Refs use Uniweb namespacing, resolved on disk at build time, never fetched: `@/name` (this foundation's own `foundation/schemas/`), `@std/name` (the shared standard schemas, shipped in the `@uniweb/schemas` package), and `@org/name` (an org's own schemas, from its `@org/schemas` package — define a schema once and share it across foundations). The schema is a hint: it supplies field defaults and drives the editor, not delivery (which is default-on). For an explicit opt-out (rare), set `data: false`.
|
|
1186
|
+
**Declaring data schemas.** `meta.js` declares the schema for each `content.data` key with a single `data:` field — there is no separate `schemas:` key. Each entry's value is one of: a **named ref** (`'@/article'` resolves to this foundation's `foundation/schemas/article.{js,json,yml,yaml}`; `'@std/person'` is a shared standard), an **inline field map** (`{ field: { type, default } }`), or an **inline rich-form** (`{ fields: [...] }`, an editor form). Refs use Uniweb namespacing, resolved on disk at build time, never fetched: `@/name` (this foundation's own `foundation/schemas/`), `@std/name` (the shared standard schemas, shipped in the `@uniweb/schemas` package), and `@org/name` (an org's own schemas, from its `@org/schemas` package — define a schema once and share it across foundations). The schema is a hint: it supplies field defaults and drives the editor, not delivery (which is default-on). For an explicit opt-out (rare), set `data: false`.
|
|
1185
1187
|
|
|
1186
1188
|
```js
|
|
1187
1189
|
// meta.js
|
|
@@ -1201,7 +1203,7 @@ export default {
|
|
|
1201
1203
|
export default { '@acme': '../shared/acme-schemas', '@brand': process.env.BRAND_SCHEMAS }
|
|
1202
1204
|
```
|
|
1203
1205
|
|
|
1204
|
-
Plain JS, so paths can be relative, absolute, or read from an env var. A routed scope wins over the package convention; `@/` and `@uniweb` are never routable; an empty value (e.g. an unset env var) falls back to the package convention.
|
|
1206
|
+
Plain JS, so paths can be relative, absolute, or read from an env var. A routed scope wins over the package convention; `@/` and `@uniweb` are never routable; an empty value (e.g. an unset env var) falls back to the package convention. A routed scope has no package fallback for a *missing* schema (it errors rather than silently load a different definition). To override a single schema — keeping the rest of the scope routed to the shared folder — add a per-schema key pointing at a file: `'@acme/person': './schemas/acme-person.yml'` (most-specific wins: file › directory › package).
|
|
1205
1207
|
|
|
1206
1208
|
**Validate your data.** `uniweb validate` checks your file-based data against these declared schemas — missing required fields, type/enum/format mismatches, nested fields — before you ship. Warns by default, `--strict` for a non-zero CI exit. It's distinct from `uniweb doctor` (which checks project structure): `validate` checks your *data* against the schemas you *declared*. Remote (`url:`), `ref`/`options`, and rich `sections`-form inputs are reported deferred — validate those against live data.
|
|
1207
1209
|
|
package/src/commands/build.js
CHANGED
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
classifyPackage,
|
|
61
61
|
isExtensionPackage,
|
|
62
62
|
} from '@uniweb/build'
|
|
63
|
+
import { resolveDefaultLocale, normalizeLanguageList } from '@uniweb/core/locale-config'
|
|
63
64
|
import { readSiteConfig } from '@uniweb/build/site'
|
|
64
65
|
import { readWorkspaceConfig, resolveGlob } from '../utils/config.js'
|
|
65
66
|
|
|
@@ -373,12 +374,26 @@ async function loadI18nConfig(projectDir, siteConfig = null) {
|
|
|
373
374
|
|
|
374
375
|
// Resolve locales (undefined/'*' → all available, array → specific)
|
|
375
376
|
const { resolveLocales } = await import('@uniweb/build/i18n')
|
|
376
|
-
|
|
377
|
+
let locales = await resolveLocales(config.languages, localesPath)
|
|
378
|
+
|
|
379
|
+
// Publish filter: build outputs are visitor artifacts. With an explicit
|
|
380
|
+
// `publishLanguages:`, only listed locales get dist/{locale}/ content,
|
|
381
|
+
// per-locale HTML, hreflang, and translated collections. Draft locales
|
|
382
|
+
// stay previewable in dev, which doesn't run this path. Intersecting the
|
|
383
|
+
// DISK-resolved list here also covers wildcard (`languages: '*'`) sites.
|
|
384
|
+
if (config.publishLanguages != null) {
|
|
385
|
+
const publishSet = new Set(normalizeLanguageList(config.publishLanguages))
|
|
386
|
+
const dropped = locales.filter((l) => !publishSet.has(l))
|
|
387
|
+
locales = locales.filter((l) => publishSet.has(l))
|
|
388
|
+
if (dropped.length > 0) {
|
|
389
|
+
info(`Skipping non-publishable locale(s): ${dropped.join(', ')} (not in publishLanguages)`)
|
|
390
|
+
}
|
|
391
|
+
}
|
|
377
392
|
|
|
378
393
|
if (locales.length === 0) return null
|
|
379
394
|
|
|
380
395
|
return {
|
|
381
|
-
defaultLocale: config
|
|
396
|
+
defaultLocale: resolveDefaultLocale(config),
|
|
382
397
|
locales,
|
|
383
398
|
localesDir,
|
|
384
399
|
}
|
package/src/commands/i18n.js
CHANGED
|
@@ -19,6 +19,7 @@ import { resolve, join, dirname, basename, relative } from 'path'
|
|
|
19
19
|
import { existsSync } from 'fs'
|
|
20
20
|
import { readFile, writeFile, mkdir, readdir, unlink, rename } from 'fs/promises'
|
|
21
21
|
import yaml from 'js-yaml'
|
|
22
|
+
import { resolveDefaultLocale } from '@uniweb/core/locale-config'
|
|
22
23
|
import {
|
|
23
24
|
isWorkspaceRoot,
|
|
24
25
|
findSites,
|
|
@@ -216,7 +217,7 @@ async function loadSiteConfig(siteRoot) {
|
|
|
216
217
|
const locales = await resolveLocales(config.languages, localesPath)
|
|
217
218
|
|
|
218
219
|
return {
|
|
219
|
-
defaultLocale: config
|
|
220
|
+
defaultLocale: resolveDefaultLocale(config),
|
|
220
221
|
locales,
|
|
221
222
|
localesDir,
|
|
222
223
|
...config.i18n,
|
package/src/commands/publish.js
CHANGED
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
rewriteBallAssets,
|
|
49
49
|
} from '@uniweb/build/site'
|
|
50
50
|
import { emitSyncPackages } from '@uniweb/build/uwx'
|
|
51
|
+
import { resolveDefaultLocale } from '@uniweb/core/locale-config'
|
|
51
52
|
|
|
52
53
|
import { BackendClient } from '../backend/client.js'
|
|
53
54
|
import { resolveSiteDir, resolveSiteBackend } from './deploy.js'
|
|
@@ -117,7 +118,9 @@ function languagesFromContent(siteContent) {
|
|
|
117
118
|
|
|
118
119
|
// Languages from site.yml — used only for the dry-run summary (no build yet).
|
|
119
120
|
function languagesFromSiteYml(siteYml) {
|
|
120
|
-
|
|
121
|
+
// Legacy `lang:` still honored between defaultLanguage and the shared
|
|
122
|
+
// `defaultLanguage || languages[0] || 'en'` rule.
|
|
123
|
+
const def = siteYml.defaultLanguage || siteYml.lang || resolveDefaultLocale(siteYml)
|
|
121
124
|
const locales = siteYml.i18n?.locales || siteYml.languages
|
|
122
125
|
if (!Array.isArray(locales) || locales.length === 0) return null
|
|
123
126
|
const norm = locales.map((l) => (typeof l === 'string' ? l : l?.value || l?.code)).filter(Boolean)
|
package/src/commands/register.js
CHANGED
|
@@ -454,6 +454,17 @@ async function runRegister(args = []) {
|
|
|
454
454
|
return { exitCode: 1 }
|
|
455
455
|
}
|
|
456
456
|
}
|
|
457
|
+
// Registering ≠ delivering the file. A registered schema is a content type
|
|
458
|
+
// authors use in the app; a FOUNDATION build still resolves '@scope/name' from
|
|
459
|
+
// disk (a package or a routed folder). This is the moment that belief forms —
|
|
460
|
+
// you just registered it — so correct it here, not in a doc nobody's reading.
|
|
461
|
+
if (!jsonMode && defined.length > 0 && scope) {
|
|
462
|
+
log('')
|
|
463
|
+
info('Registered schemas are content types authors can use in the Uniweb app.')
|
|
464
|
+
log(` ${colors.dim}Delivery is separate: a foundation that binds ${scope}/<name> resolves it from${colors.reset}`)
|
|
465
|
+
log(` ${colors.dim}disk — an ${scope}/schemas package, or a folder routed in schemas.config.js.${colors.reset}`)
|
|
466
|
+
}
|
|
467
|
+
|
|
457
468
|
if (jsonMode) {
|
|
458
469
|
// Join my authoritative submitted names with the backend's minted ids. Each
|
|
459
470
|
// response entry is `{ registered: { name, version, payload_model_uuid, … },
|
package/src/framework-index.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-07-
|
|
3
|
+
"generatedAt": "2026-07-23T17:37:49.259Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"@uniweb/build": {
|
|
6
|
-
"version": "0.14.
|
|
6
|
+
"version": "0.14.37",
|
|
7
7
|
"path": "framework/build",
|
|
8
8
|
"deps": [
|
|
9
9
|
"@uniweb/content-reader",
|
|
@@ -15,17 +15,17 @@
|
|
|
15
15
|
]
|
|
16
16
|
},
|
|
17
17
|
"@uniweb/content-reader": {
|
|
18
|
-
"version": "1.1.
|
|
18
|
+
"version": "1.1.14",
|
|
19
19
|
"path": "framework/content-reader",
|
|
20
20
|
"deps": []
|
|
21
21
|
},
|
|
22
22
|
"@uniweb/content-writer": {
|
|
23
|
-
"version": "0.2.
|
|
23
|
+
"version": "0.2.7",
|
|
24
24
|
"path": "framework/content-writer",
|
|
25
25
|
"deps": []
|
|
26
26
|
},
|
|
27
27
|
"@uniweb/core": {
|
|
28
|
-
"version": "0.7.
|
|
28
|
+
"version": "0.7.23",
|
|
29
29
|
"path": "framework/core",
|
|
30
30
|
"deps": [
|
|
31
31
|
"@uniweb/semantic-parser",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"deps": []
|
|
44
44
|
},
|
|
45
45
|
"@uniweb/kit": {
|
|
46
|
-
"version": "0.9.
|
|
46
|
+
"version": "0.9.30",
|
|
47
47
|
"path": "framework/kit",
|
|
48
48
|
"deps": [
|
|
49
49
|
"@uniweb/core",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"deps": []
|
|
62
62
|
},
|
|
63
63
|
"@uniweb/runtime": {
|
|
64
|
-
"version": "0.8.
|
|
64
|
+
"version": "0.8.29",
|
|
65
65
|
"path": "framework/runtime",
|
|
66
66
|
"deps": [
|
|
67
67
|
"@uniweb/core",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"deps": []
|
|
100
100
|
},
|
|
101
101
|
"@uniweb/unipress": {
|
|
102
|
-
"version": "0.4.
|
|
102
|
+
"version": "0.4.44",
|
|
103
103
|
"path": "framework/unipress",
|
|
104
104
|
"deps": [
|
|
105
105
|
"@uniweb/build",
|