You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(spec): state the grammar PluginSchema.version enforces instead of claiming SemVer (#17463)
`PluginSchema.version` (`kernel/plugin.zod.ts`) was described `"Semantic
Version"`, bare, and `PluginLoader.isValidSemanticVersion` (`packages/core`)
carried that name — while the one regex they share, character for character,
accepts eight strings SemVer 2.0.0 forbids:
§2 leading zeroes in the numeric core — 01.1.1, 1.01.1, 1.1.01
§9 empty / leading-zero prerelease ids — 1.0.0-0123, 1.0.0-alpha..1,
1.0.0-alpha.., 1.0.0-.
§10 degenerate build metadata — 1.0.0+.
Neither regex moves here, in either direction, and all eight keep parsing.
The accept set is frozen: the leading-zero half predates the widening that
gave this key its suffix groups — the original /^\d+\.\d+\.\d+$/ admitted
01.1.1 too, because \d+ always has — so narrowing to the official SemVer
regex would refuse plugin objects that load today, which the ruling on this
key forbids. With one side of the declared/enforced pair frozen, the repair
is on the other side: the claim.
- the describe() states the shape (major.minor.patch, optional -prerelease
and +build) and disclaims the standard it exceeds, following
ManifestSchema.version, which already spells (major.minor.patch) rather
than leaning on the word SemVer
- isValidSemanticVersion becomes isSemverShapedVersion, because a predicate
named for SemVer that answers a wider grammar gets misused by the next
caller no matter what its docblock says. The symbol is private and
package-internal — measured against the built dist/index.d.ts: TS2305 on
a named import, TS2341 on member access, while a public member on the
same class compiles — so nothing published is removed
- all eight forms are pinned as ACCEPTED on both declarations, so a future
edit that "corrects" the grammar fails on purpose, and the describe() is
pinned against reverting to the bare claim
content/docs/references/kernel/plugin.mdx is regenerated (build-docs.ts);
packages/spec/json-schema/ is gitignored and carries the same string.
Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
Co-authored-by: Claude <noreply@anthropic.com>
| §2 — numeric identifiers MUST NOT include leading zeroes |`01.1.1`, `1.01.1`, `1.1.01`|
12
+
| §9 — prerelease identifiers MUST NOT be empty or carry leading zeroes |`1.0.0-0123`, `1.0.0-alpha..1`, `1.0.0-alpha..`, `1.0.0-.`|
13
+
| §10 — build-metadata identifiers MUST NOT be empty |`1.0.0+.`|
14
+
15
+
**No accepted value moved, in either direction.** The regex is byte-for-byte what it was; the `describe()` string is what changed. The leading-zero half is older than the recent widening — the original `/^\d+\.\d+\.\d+$/` admitted `01.1.1` too, because `\d+` always has — so tightening the key to the official SemVer regex would refuse plugin objects that load today, which the ruling on this key forbids. With the accept set frozen, the only side of the declared/enforced pair still free to move is the claim, and the bare `"Semantic Version"` was the false half: it named a standard this key does not implement.
16
+
17
+
The replacement states the shape an author can predict a verdict from — `major.minor.patch` with an optional `-prerelease` and an optional `+build` suffix — and disclaims the standard it exceeds rather than merely dropping the word. This follows `ManifestSchema.version`, which already spells `(major.minor.patch)` explicitly rather than leaning on "SemVer".
18
+
19
+
**What consumers see.** The `description` on `version` in the shipped `json-schema/` tree and on the generated `kernel/plugin` reference page. No `pattern`, no `type`, no accepted or rejected value changes, so a tool that validates against this schema behaves identically.
20
+
21
+
All eight forms are now pinned as **accepted** — in `packages/spec` (`plugin.test.ts`) and in `packages/core` (`plugin-loader.test.ts`, `plugin-contract-enforcement.test.ts`) — so the honesty is enforced rather than narrated, and a future edit that "corrects" the grammar to be standards-compliant fails those pins on purpose.
22
+
23
+
`@objectstack/core` is deliberately **not** listed above. Its `PluginLoader` predicate was renamed `isValidSemanticVersion` to `isSemverShapedVersion` in the same change, for the same reason, but the symbol is `private` and package-internal: measured against the built `dist/index.d.ts`, `import { isValidSemanticVersion } from '@objectstack/core'` is TS2305 (no exported member) and `loader.isValidSemanticVersion` is TS2341 (private), while a public member on the same class compiles. Nothing published moves.
Copy file name to clipboardExpand all lines: content/docs/references/kernel/plugin.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,7 @@ const result = PluginSchema.parse(data);
31
31
|**staticPath**|`string`| optional | Absolute path to static assets (Required for type="ui") |
32
32
|**slug**|`string`| optional | URL path segment (Required for type="ui") |
33
33
|**default**|`boolean`| optional | Serve at root path (Only one "ui" plugin can be default) |
34
-
|**version**|`string`| optional |Semantic Version |
34
+
|**version**|`string`| optional | Version: major.minor.patch, with an optional -prerelease and an optional +build suffix. Looser than SemVer 2.0.0 — leading zeroes (01.1.1) and empty identifiers (1.0.0-alpha..1) are accepted.|
// TSDoc spells `(major.minor.patch)` rather than leaning on the word SemVer),
208
+
// so an author reading it can predict the verdict on their own string. The
209
+
// eight forbidden forms are pinned as ACCEPTED in `plugin.test.ts` — stated
210
+
// and enforced, not narrated — and `PluginLoader`'s predicate was renamed
211
+
// `isSemverShapedVersion` in the same change, for the same reason.
212
+
version: z.string().regex(/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/).optional().describe('Version: major.minor.patch, with an optional -prerelease and an optional +build suffix. Looser than SemVer 2.0.0 — leading zeroes (01.1.1) and empty identifiers (1.0.0-alpha..1) are accepted.'),
0 commit comments