| id | 148 | |
|---|---|---|
| title | Named field-type shortcuts for inline schemas | |
| status | ✅ | |
| model | sonnet | |
| depends-on |
|
|
| summary | Ship a small CUE library of common field patterns (`date`, `datetime`, `email`, `url`, `filename`) and let inline schemas (plan 146) reference them by short name. Schemas in `proto.md` files import the same library. |
Make inline schemas (plan 146) shorter and more
readable for the common case. A user writing
created: date should not have to re-derive the
ISO-date regex; nor should three projects each
land on subtly different versions of the same
pattern.
mdbase ships a fixed list of named scalar types
(string, int, number, bool, date,
datetime, time, enum, link). mdsmith uses
CUE, which is more expressive but asks each
project to spell out its own date and email
patterns. The mdbase research records this gap as
S-2: not a missing capability, but a missing
ergonomic layer over CUE.
Plan 146 (inline schemas) is the trigger. Before
plan 146 the patterns can live in a shared
proto.md and be reused by import; after plan
146 each inline frontmatter: block re-derives
them.
- Replacing CUE. The shortcuts resolve to CUE expressions; everything CUE accepts is still accepted.
- Custom user-defined shortcuts. A real project
can already define one in its own
proto.mdschema. If user shortcuts become a real request, that is a separate plan. - Validating against system locale or timezone. Date and datetime patterns match strings of the expected ISO shape; semantic checks (is the day valid for the month) are out of scope.
A package lives at a stable, importable module path. Settled paths (on landing):
- On-disk source:
cue/types/types.cuein this repository, declaringpackage types. - CUE import path:
github.com/jeduden/mdsmith/types(reserved for future CUE-native consumers; the literalimportstatement is not yet wired up). - Distribution: embedded asset.
cue/types/types.gouses//go:embed types.cue;internal/schemareads the source for the drift test and seeds its runtime registry from the same definitions.
The initial vocabulary:
package types
#date: =~"^\\d{4}-\\d{2}-\\d{2}$"
#datetime: =~"^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(Z|[+-]\\d{2}:\\d{2})?$"
#time: =~"^\\d{2}:\\d{2}(:\\d{2})?$"
#email: =~"^[^@\\s]+@[^@\\s]+\\.[^@\\s]+$"
#url: =~"^https?://"
#filename: =~"^[A-Za-z0-9._-]+\\.md$"
#nonEmpty: string & != ""The contract a user sees is the import path and the
symbol names. Only one surface is wired up today:
the bare-name shortcut described below. A literal
import "github.com/jeduden/mdsmith/types" is
reserved for a future plan.
A proto.md schema imports the package and
references the definitions:
package proto
import "github.com/jeduden/mdsmith/types"
created: types.#date
modified: types.#datetime
homepage: types.#urlExisting proto.md schemas keep working. The
import is opt-in.
Inline schemas (plan 146) accept the unprefixed short name as a string value:
kinds:
rfc:
schema:
frontmatter:
created: date
modified: datetime
contact: email
homepage: urlThe loader splits values into two cases:
- Bare name — a YAML scalar that is a single identifier (no quotes, no operators, no whitespace). Must resolve in the registry, or the loader rejects the config with an error naming the field and the unknown name.
- Anything else — values containing
operators, quotes, parentheses, or whitespace
— passes through as raw CUE. So
status: '"open" | "done"'continues to work unchanged.
The split keeps intent unambiguous. A typo on a bare shortcut surfaces early. A real CUE expression is never silently re-read as a shortcut.
A field that needs both a shortcut and an extra constraint uses inline CUE syntax:
frontmatter:
created: 'date & >="2020-01-01"'The shortcut is parsed only when the value is exactly the bare short name. Anything more complex stays raw CUE.
- A new public package import path for the library.
- A new bare-name shortcut in inline-schema
frontmatter:values. - A documentation page listing the registered names and what each resolves to.
- ✅ Create the CUE source for the shortcut
library at
cue/types/types.cue, declaringpackage types. The CUE import pathgithub.com/jeduden/mdsmith/typesis documented but not yet wired up as a CUE module; the user-facing surface is the bare-name shortcut. - ✅ Ship the library via
go:embedincue/types/types.go. The runtime registry seeds from the same source, soproto.mdschemas resolve shortcuts with no network access — the library is in the binary. - ✅ Registry of short names → canonical CUE
expressions lives at
internal/schema/shortcuts.go(kept next tofrontmatterExpr, which is the single substitution point shared by inline and file-based parsing). - ✅
frontmatterExprininternal/schema/parse_inline.gocallsresolveBareNamefirst. Bare identifiers matching[a-zA-Z_][a-zA-Z0-9_-]*go through: registered shortcuts are substituted, CUE built-ins (string,int,bool, …) pass through verbatim, and unknown bare names error with the field path. Operators, whitespace, and quoted forms pass through unchanged. - ✅ Documentation page at
docs/reference/schema-types.mdlists every registered name, its canonical CUE, accept / reject examples, and an inline / proto.md usage walk-through. - ✅ Cross-linked from the file-kinds guide, the schemas guide, and the MDS020 README.
- ✅ Tests in
internal/schema/shortcuts_test.go:
- each shortcut accepts canonical inputs and
rejects clear violations
(
TestShortcutRegistry_CanonicalsCompileAndMatch); - a value containing operators (
"open" | "done",date & >="2020-01-01") is parsed as raw CUE (TestResolveBareName_IgnoresNonBareCandidates,TestParseInline_RawCUEPassesThroughUnchanged); - an unknown bare name errors with the field name
and the unknown identifier
(
TestParseInline_UnknownShortcutErrorNamesField); - an offline
proto.mdschema resolves through the embedded library (TestValidate_File_ShortcutWorksOffline); - the registry stays in sync with the embedded CUE
(
TestShortcutRegistry_MatchesEmbeddedCUE).
- The shortcut library defines
#date,#datetime,#time,#email,#url,#filename,#nonEmptyat the chosen import path. - An external
proto.mdschema resolves the shortcut library without network access — the library is embedded in the binary (TestValidate_File_ShortcutWorksOfflineininternal/schema/shortcuts_test.go). - An inline schema with
created: datevalidates2024-05-01and rejects2024-5-1(TestValidate_Inline_ShortcutAcceptsAndRejects). - An inline-schema value that is not a
registered bare name (
status: '"open" | "done"') is parsed as raw CUE without lookup (TestParseInline_RawCUEPassesThroughUnchanged). - An inline-schema value that looks like a
shortcut but is unknown (
created: iso-date) produces a config error naming the field and the unknown name (TestParseInline_UnknownShortcutErrorNamesField). - A new
docs/reference/schema-types.mdpage lists every registered name with the canonical CUE expression and an example. - All tests pass:
go test ./... -
go tool golangci-lint runreports no issues.