@stonecrop/stonecrop 0.13.7 → 0.13.9

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.
@@ -4,7 +4,7 @@
4
4
  * @packageDocumentation
5
5
  */
6
6
 
7
- import type { SchemaTypes } from '@stonecrop/aform'
7
+ import type { DoctypeField } from '@stonecrop/schema'
8
8
  import type { LinkDeclaration } from '@stonecrop/schema'
9
9
  import type { List, Map as ImmutableMap } from 'immutable'
10
10
  import type { AnyStateNodeConfig } from 'xstate'
@@ -47,7 +47,7 @@ export class SchemaValidator {
47
47
  */
48
48
  validate(
49
49
  doctype: string,
50
- schema: List<SchemaTypes> | SchemaTypes[] | undefined,
50
+ schema: List<DoctypeField> | DoctypeField[] | undefined,
51
51
  workflow?: AnyStateNodeConfig,
52
52
  actions?: ImmutableMap<string, string[]> | Map<string, string[]>,
53
53
  links?: Record<string, LinkDeclaration>
@@ -102,7 +102,7 @@ export class SchemaValidator {
102
102
  * Validates that required schema properties are present
103
103
  * @internal
104
104
  */
105
- private validateRequiredProperties(doctype: string, schema: SchemaTypes[]): ValidationIssue[] {
105
+ private validateRequiredProperties(doctype: string, schema: DoctypeField[]): ValidationIssue[] {
106
106
  const issues: ValidationIssue[] = []
107
107
 
108
108
  for (const field of schema) {
@@ -118,8 +118,8 @@ export class SchemaValidator {
118
118
  continue
119
119
  }
120
120
 
121
- // Check for component or fieldtype
122
- if (!field.component && !('fieldtype' in field)) {
121
+ // ValueField requires fieldtype; fieldset/table have their own structural requirements
122
+ if (field.kind === 'field' && !field.component && !field.fieldtype) {
123
123
  issues.push({
124
124
  severity: ValidationSeverity.ERROR,
125
125
  rule: 'required-component-or-fieldtype',
@@ -129,16 +129,9 @@ export class SchemaValidator {
129
129
  })
130
130
  }
131
131
 
132
- // Validate nested schemas (recursively)
133
- if ('schema' in field) {
134
- // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 'schema' in field guard confirms property exists; SchemaTypes union narrowed at runtime
135
- const nestedSchema = (field as { schema: unknown }).schema
136
- // oxlint-disable typescript/no-unsafe-type-assertion -- Immutable List or plain array; toArray() returns SchemaTypes elements
137
- const nestedArray = (
138
- Array.isArray(nestedSchema) ? nestedSchema : (nestedSchema as { toArray?: () => unknown[] }).toArray?.() || []
139
- ) as SchemaTypes[]
140
- // oxlint-enable typescript/no-unsafe-type-assertion
141
- issues.push(...this.validateRequiredProperties(doctype, nestedArray))
132
+ // Validate nested schemas recursively (fieldset only; table columns are ColumnSchema not DoctypeField)
133
+ if (field.kind === 'fieldset') {
134
+ issues.push(...this.validateRequiredProperties(doctype, field.schema))
142
135
  }
143
136
  }
144
137
 
@@ -149,16 +142,12 @@ export class SchemaValidator {
149
142
  * Validates Link field targets exist in registry
150
143
  * @internal
151
144
  */
152
- private validateLinkFields(doctype: string, schema: SchemaTypes[], registry: Registry): ValidationIssue[] {
145
+ private validateLinkFields(doctype: string, schema: DoctypeField[], registry: Registry): ValidationIssue[] {
153
146
  const issues: ValidationIssue[] = []
154
147
 
155
148
  for (const field of schema) {
156
- // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 'fieldtype' in field guard confirms property exists; accessing unknown-typed fieldtype safely
157
- const fieldtype = 'fieldtype' in field ? (field as { fieldtype: unknown }).fieldtype : undefined
158
-
159
- // Check Link fields
160
- if (fieldtype === 'Link') {
161
- const options = 'options' in field ? (field as { options: unknown }).options : undefined
149
+ if (field.kind === 'field' && field.fieldtype === 'Link') {
150
+ const options = field.options
162
151
  if (!options) {
163
152
  issues.push({
164
153
  severity: ValidationSeverity.ERROR,
@@ -170,8 +159,6 @@ export class SchemaValidator {
170
159
  continue
171
160
  }
172
161
 
173
- // Check if target doctype exists in registry
174
- // Options should be a string representing the target doctype name
175
162
  const targetDoctype = typeof options === 'string' ? options : ''
176
163
  if (!targetDoctype) {
177
164
  issues.push({
@@ -197,16 +184,9 @@ export class SchemaValidator {
197
184
  }
198
185
  }
199
186
 
200
- // Recursively check nested schemas
201
- if ('schema' in field) {
202
- // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- 'schema' in field guard confirms property exists; SchemaTypes union narrowed at runtime
203
- const nestedSchema = (field as { schema: unknown }).schema
204
- // oxlint-disable typescript/no-unsafe-type-assertion -- Immutable List or plain array; toArray() returns SchemaTypes elements
205
- const nestedArray = (
206
- Array.isArray(nestedSchema) ? nestedSchema : (nestedSchema as { toArray?: () => unknown[] }).toArray?.() || []
207
- ) as SchemaTypes[]
208
- // oxlint-enable typescript/no-unsafe-type-assertion
209
- issues.push(...this.validateLinkFields(doctype, nestedArray, registry))
187
+ // Recursively check nested fieldset schemas
188
+ if (field.kind === 'fieldset') {
189
+ issues.push(...this.validateLinkFields(doctype, field.schema, registry))
210
190
  }
211
191
  }
212
192
 
@@ -220,15 +200,15 @@ export class SchemaValidator {
220
200
  private validateLinkDeclarations(
221
201
  doctype: string,
222
202
  links: Record<string, LinkDeclaration>,
223
- schema: SchemaTypes[],
203
+ schema: DoctypeField[],
224
204
  registry: Registry
225
205
  ): ValidationIssue[] {
226
206
  const issues: ValidationIssue[] = []
227
207
 
228
208
  // Build a map of Link fields by fieldname for quick lookup
229
- const linkFieldsByFieldname = new Map<string, SchemaTypes>()
209
+ const linkFieldsByFieldname = new Map<string, DoctypeField>()
230
210
  for (const field of schema) {
231
- if ('fieldtype' in field && field.fieldtype === 'Link') {
211
+ if (field.kind === 'field' && field.fieldtype === 'Link') {
232
212
  linkFieldsByFieldname.set(field.fieldname, field)
233
213
  }
234
214
  }
@@ -288,9 +268,8 @@ export class SchemaValidator {
288
268
  // Only check if link has fieldname set (otherwise it's a standalone link without a field)
289
269
  if (link.fieldname) {
290
270
  const linkField = linkFieldsByFieldname.get(link.fieldname)
291
- if (linkField) {
292
- const linkFieldOptions = 'options' in linkField ? (linkField as { options: unknown }).options : undefined
293
- const linkFieldTarget = typeof linkFieldOptions === 'string' ? linkFieldOptions : undefined
271
+ if (linkField && linkField.kind === 'field') {
272
+ const linkFieldTarget = typeof linkField.options === 'string' ? linkField.options : undefined
294
273
  if (linkFieldTarget && linkFieldTarget !== link.target) {
295
274
  issues.push({
296
275
  severity: ValidationSeverity.ERROR,
@@ -483,7 +462,7 @@ export function createValidator(registry: Registry, options?: Partial<ValidatorO
483
462
  */
484
463
  export function validateSchema(
485
464
  doctype: string,
486
- schema: List<SchemaTypes> | SchemaTypes[] | undefined,
465
+ schema: List<DoctypeField> | DoctypeField[] | undefined,
487
466
  registry: Registry,
488
467
  workflow?: AnyStateNodeConfig,
489
468
  actions?: ImmutableMap<string, string[]> | Map<string, string[]>
package/src/stonecrop.ts CHANGED
@@ -319,7 +319,6 @@ export class Stonecrop {
319
319
  // TODO: For custom fetch handlers, this returns false (not blocking), but the custom handler
320
320
  // may still be invoked by useLazyLink. Future: custom handlers should be able to declare they
321
321
  // satisfy blockWorkflows, or validation should reject custom + blockWorkflows: true.
322
- // See: relationships.md Phase 6 "Open Question: blockWorkflows + custom fetch"
323
322
  return link.fetch?.method === 'sync'
324
323
  }
325
324
 
@@ -1,4 +1,4 @@
1
- import type { SchemaTypes } from '@stonecrop/aform'
1
+ import type { ResolvedField } from '@stonecrop/aform'
2
2
  import type { Ref, ComputedRef } from 'vue'
3
3
 
4
4
  import type Doctype from '../doctype'
@@ -177,7 +177,7 @@ export type HSTStonecropReturn = BaseStonecropReturn & {
177
177
  * Resolved schema with nested Doctype fields expanded.
178
178
  * Use this to iterate over fields for rendering, excluding nested doctypes handled separately.
179
179
  */
180
- resolvedSchema: Ref<SchemaTypes[]>
180
+ resolvedSchema: Ref<ResolvedField[]>
181
181
  /**
182
182
  * Scaffold empty descendant records from defaults for all descendant links.
183
183
  * @param path - The HST path where initialized data should be stored
@@ -1,42 +1,21 @@
1
- import type { SchemaTypes } from '@stonecrop/aform'
2
- import type { FieldMeta, LinkDeclaration, WorkflowMeta } from '@stonecrop/schema'
1
+ import type { DoctypeField, LinkDeclaration, WorkflowMeta } from '@stonecrop/schema'
3
2
  import { List, Map } from 'immutable'
4
3
  import type { AnyStateNodeConfig, UnknownMachineConfig } from 'xstate'
5
4
 
6
5
  /**
7
- * Immutable Doctype type for Stonecrop instances
6
+ * Immutable Doctype type for Stonecrop instances. App authors should use
7
+ * `Doctype.fromObject()` rather than constructing this shape manually.
8
8
  * @public
9
9
  */
10
10
  export type ImmutableDoctype = {
11
- readonly schema?: List<SchemaTypes>
11
+ readonly schema?: List<DoctypeField>
12
12
  readonly workflow?: UnknownMachineConfig | AnyStateNodeConfig | WorkflowMeta
13
13
  readonly actions?: Map<string, string[]>
14
- readonly links?: Record<string, LinkDeclaration>
15
- }
16
-
17
- /**
18
- * Mutable Doctype type for Stonecrop instances
19
- * @public
20
- */
21
- export type MutableDoctype = {
22
- doctype?: string
23
- schema?: SchemaTypes[]
24
- workflow?: UnknownMachineConfig | AnyStateNodeConfig | WorkflowMeta
25
- actions?: Record<string, string[]>
26
- }
27
-
28
- /**
29
- * Schema type for Stonecrop instances
30
- * @public
31
- */
32
- export type Schema = {
33
- doctype: string
34
- schema: List<SchemaTypes>
35
14
  }
36
15
 
37
16
  /**
38
17
  * Plain object representation of doctype configuration for serialization/API responses.
39
- * Compatible with the DoctypeMeta type from \@stonecrop/schema.
18
+ * Extends DoctypeMeta with Stonecrop-specific properties: actions, slug, inherits.
40
19
  * @public
41
20
  */
42
21
  export type DoctypeConfig = {
@@ -45,7 +24,7 @@ export type DoctypeConfig = {
45
24
  /** URL-friendly slug (kebab-case) */
46
25
  slug?: string
47
26
  /** Field definitions (including link fields with fieldtype: 'Link') */
48
- fields?: (SchemaTypes | FieldMeta)[]
27
+ fields?: DoctypeField[]
49
28
  /** Relationship links to other doctypes */
50
29
  links?: Record<string, LinkDeclaration>
51
30
  /** Workflow configuration (XState format or simple WorkflowMeta) */