@carlonicora/nextjs-jsonapi 1.111.2 → 1.112.1

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 (60) hide show
  1. package/dist/scripts/generate-web-module/__tests__/container.spec.js +2 -2
  2. package/dist/scripts/generate-web-module/__tests__/container.spec.js.map +1 -1
  3. package/dist/scripts/generate-web-module/__tests__/parent-detector.spec.d.ts +2 -0
  4. package/dist/scripts/generate-web-module/__tests__/parent-detector.spec.d.ts.map +1 -0
  5. package/dist/scripts/generate-web-module/__tests__/parent-detector.spec.js +17 -0
  6. package/dist/scripts/generate-web-module/__tests__/parent-detector.spec.js.map +1 -0
  7. package/dist/scripts/generate-web-module/__tests__/plumbing.spec.js +1 -2
  8. package/dist/scripts/generate-web-module/__tests__/plumbing.spec.js.map +1 -1
  9. package/dist/scripts/generate-web-module/__tests__/selector.spec.js +19 -14
  10. package/dist/scripts/generate-web-module/__tests__/selector.spec.js.map +1 -1
  11. package/dist/scripts/generate-web-module/generator.d.ts.map +1 -1
  12. package/dist/scripts/generate-web-module/generator.js +7 -2
  13. package/dist/scripts/generate-web-module/generator.js.map +1 -1
  14. package/dist/scripts/generate-web-module/templates/components/content.template.d.ts.map +1 -1
  15. package/dist/scripts/generate-web-module/templates/components/content.template.js +58 -8
  16. package/dist/scripts/generate-web-module/templates/components/content.template.js.map +1 -1
  17. package/dist/scripts/generate-web-module/templates/components/editor.template.js +3 -1
  18. package/dist/scripts/generate-web-module/templates/components/editor.template.js.map +1 -1
  19. package/dist/scripts/generate-web-module/templates/components/selector.template.d.ts +4 -0
  20. package/dist/scripts/generate-web-module/templates/components/selector.template.d.ts.map +1 -1
  21. package/dist/scripts/generate-web-module/templates/components/selector.template.js +55 -48
  22. package/dist/scripts/generate-web-module/templates/components/selector.template.js.map +1 -1
  23. package/dist/scripts/generate-web-module/templates/module.template.d.ts.map +1 -1
  24. package/dist/scripts/generate-web-module/templates/module.template.js +5 -3
  25. package/dist/scripts/generate-web-module/templates/module.template.js.map +1 -1
  26. package/dist/scripts/generate-web-module/templates/table-hook.template.js +6 -6
  27. package/dist/scripts/generate-web-module/templates/table-hook.template.js.map +1 -1
  28. package/dist/scripts/generate-web-module/transformers/i18n-generator.d.ts.map +1 -1
  29. package/dist/scripts/generate-web-module/transformers/i18n-generator.js +1 -0
  30. package/dist/scripts/generate-web-module/transformers/i18n-generator.js.map +1 -1
  31. package/dist/scripts/generate-web-module/transformers/parent-detector.d.ts +12 -5
  32. package/dist/scripts/generate-web-module/transformers/parent-detector.d.ts.map +1 -1
  33. package/dist/scripts/generate-web-module/transformers/parent-detector.js +13 -13
  34. package/dist/scripts/generate-web-module/transformers/parent-detector.js.map +1 -1
  35. package/dist/scripts/generate-web-module/types/field-mapping.types.d.ts +6 -3
  36. package/dist/scripts/generate-web-module/types/field-mapping.types.d.ts.map +1 -1
  37. package/dist/scripts/generate-web-module/types/field-mapping.types.js +17 -3
  38. package/dist/scripts/generate-web-module/types/field-mapping.types.js.map +1 -1
  39. package/dist/scripts/generate-web-module/utils/i18n-updater.d.ts.map +1 -1
  40. package/dist/scripts/generate-web-module/utils/i18n-updater.js +25 -26
  41. package/dist/scripts/generate-web-module/utils/i18n-updater.js.map +1 -1
  42. package/dist/scripts/generate-web-module/validators/json-schema-validator.d.ts.map +1 -1
  43. package/dist/scripts/generate-web-module/validators/json-schema-validator.js +3 -2
  44. package/dist/scripts/generate-web-module/validators/json-schema-validator.js.map +1 -1
  45. package/package.json +1 -1
  46. package/scripts/generate-web-module/__tests__/container.spec.ts +2 -2
  47. package/scripts/generate-web-module/__tests__/parent-detector.spec.ts +20 -0
  48. package/scripts/generate-web-module/__tests__/plumbing.spec.ts +1 -2
  49. package/scripts/generate-web-module/__tests__/selector.spec.ts +19 -14
  50. package/scripts/generate-web-module/generator.ts +6 -2
  51. package/scripts/generate-web-module/templates/components/content.template.ts +66 -8
  52. package/scripts/generate-web-module/templates/components/editor.template.ts +3 -1
  53. package/scripts/generate-web-module/templates/components/selector.template.ts +55 -48
  54. package/scripts/generate-web-module/templates/module.template.ts +6 -3
  55. package/scripts/generate-web-module/templates/table-hook.template.ts +6 -6
  56. package/scripts/generate-web-module/transformers/i18n-generator.ts +1 -0
  57. package/scripts/generate-web-module/transformers/parent-detector.ts +13 -14
  58. package/scripts/generate-web-module/types/field-mapping.types.ts +16 -3
  59. package/scripts/generate-web-module/utils/i18n-updater.ts +25 -30
  60. package/scripts/generate-web-module/validators/json-schema-validator.ts +3 -2
@@ -16,6 +16,8 @@ export const JSON_TO_TS_TYPE: Record<string, string> = {
16
16
  boolean: "boolean",
17
17
  date: "Date",
18
18
  any: "any",
19
+ // Rich-text BlockNote content hydrates into a block array (typed as any).
20
+ blocknote: "any",
19
21
  };
20
22
 
21
23
  /**
@@ -27,6 +29,8 @@ export const JSON_TO_ZOD_BASE: Record<string, string> = {
27
29
  boolean: "z.boolean()",
28
30
  date: "z.date()",
29
31
  any: "z.any()",
32
+ // BlockNote content is free-form; validated as any.
33
+ blocknote: "z.any()",
30
34
  };
31
35
 
32
36
  /**
@@ -98,6 +102,10 @@ export function getZodBase(jsonType: string): string {
98
102
  * Get form component for a field
99
103
  */
100
104
  export function getFormComponent(fieldName: string, fieldType: string): FormComponentType {
105
+ // Any field explicitly typed "blocknote" is a rich-text editor, regardless of name.
106
+ if (fieldType === "blocknote") {
107
+ return "BlockNoteEditor";
108
+ }
101
109
  // Check for special field names first, but only if the type is compatible
102
110
  // (e.g., "content" as a string field should NOT use BlockNoteEditor)
103
111
  if (SPECIAL_FIELD_COMPONENTS[fieldName]) {
@@ -113,11 +121,16 @@ export function getFormComponent(fieldName: string, fieldType: string): FormComp
113
121
  }
114
122
 
115
123
  /**
116
- * Check if a field indicates BlockNoteEditor should be used.
117
- * Only fields named "content" with non-primitive types (not string/number/boolean/date)
118
- * are treated as rich-content (JSON/BlockNote) fields.
124
+ * Check if a field indicates BlockNoteEditor should be used (rich-text content
125
+ * persisted as stringified JSON, hydrated into a block array).
126
+ *
127
+ * Two ways to flag a field as rich-text:
128
+ * - Explicit type "blocknote" — any field name, supports multiple per module.
129
+ * - Legacy: a field literally named "content" with a non-primitive type.
119
130
  */
120
131
  export function isContentField(fieldName: string, fieldType?: string): boolean {
132
+ // Explicit BlockNote type — the canonical, multi-field marker.
133
+ if (fieldType === "blocknote") return true;
121
134
  if (fieldName !== "content") return false;
122
135
  // If no type provided, assume it's a content field (backwards compat)
123
136
  if (!fieldType) return true;
@@ -68,44 +68,40 @@ export function updateI18n(
68
68
  entitiesUpdated = true;
69
69
  }
70
70
 
71
- // Check if module already exists in features
72
- const featuresAlreadyExist = messages.features && messages.features[lowercaseModuleName];
73
-
74
- if (featuresAlreadyExist) {
75
- // Features exist, but we may have added entities
76
- if (entitiesUpdated) {
77
- if (dryRun) {
78
- return {
79
- success: true,
80
- message: `[DRY RUN] Module ${names.camelCase} exists, would add entities.${lowercasePluralKey}`,
81
- alreadyExists: true,
82
- };
71
+ // Additively merge this module's feature keys (fields / relationships /
72
+ // sections), FILLING missing keys without overwriting existing translations.
73
+ // Handles a brand-new module AND an existing-but-incomplete block (e.g. one
74
+ // first generated before its fields were known — which previously stayed an
75
+ // empty `{ fields: {}, relationships: {} }` skeleton forever).
76
+ const mergeMissing = (target: Record<string, any>, source: Record<string, any>): Record<string, any> => {
77
+ const out = target && typeof target === "object" && !Array.isArray(target) ? { ...target } : {};
78
+ for (const k of Object.keys(source)) {
79
+ const v = source[k];
80
+ if (v && typeof v === "object" && !Array.isArray(v)) {
81
+ out[k] = mergeMissing(out[k], v);
82
+ } else if (out[k] === undefined) {
83
+ out[k] = v;
83
84
  }
84
-
85
- // Write updated content (entities were added)
86
- const updatedContent = JSON.stringify(messages, null, 2);
87
- fs.writeFileSync(messagesPath, updatedContent, "utf-8");
88
-
89
- return {
90
- success: true,
91
- message: `Module ${names.camelCase} exists, added entities.${lowercasePluralKey}`,
92
- alreadyExists: true,
93
- };
94
85
  }
86
+ return out;
87
+ };
88
+
89
+ if (!messages.features) {
90
+ messages.features = {};
91
+ }
92
+ const moduleBlock = moduleMessages.features[i18nKeys.moduleName];
93
+ const beforeFeatures = JSON.stringify(messages.features[lowercaseModuleName] ?? null);
94
+ messages.features[lowercaseModuleName] = mergeMissing(messages.features[lowercaseModuleName], moduleBlock);
95
+ const featuresUpdated = JSON.stringify(messages.features[lowercaseModuleName]) !== beforeFeatures;
95
96
 
97
+ if (!entitiesUpdated && !featuresUpdated) {
96
98
  return {
97
99
  success: true,
98
- message: `Module ${names.camelCase} already exists in messages/${language}.json`,
100
+ message: `Module ${names.camelCase} already up to date in messages/${language}.json`,
99
101
  alreadyExists: true,
100
102
  };
101
103
  }
102
104
 
103
- // Add to features section (new module)
104
- if (!messages.features) {
105
- messages.features = {};
106
- }
107
- messages.features[lowercaseModuleName] = moduleMessages.features[i18nKeys.moduleName];
108
-
109
105
  if (dryRun) {
110
106
  return {
111
107
  success: true,
@@ -113,7 +109,6 @@ export function updateI18n(
113
109
  };
114
110
  }
115
111
 
116
- // Write updated content with proper formatting
117
112
  const updatedContent = JSON.stringify(messages, null, 2);
118
113
  fs.writeFileSync(messagesPath, updatedContent, "utf-8");
119
114
 
@@ -106,8 +106,9 @@ export function validateJsonSchema(schema: any): ValidationError[] {
106
106
  });
107
107
  }
108
108
 
109
- // Validate known types
110
- const validTypes = ["string", "number", "boolean", "date", "any"];
109
+ // Validate known types (mirrors the backend CypherType set plus the
110
+ // frontend-facing "blocknote" rich-text marker)
111
+ const validTypes = ["string", "number", "boolean", "date", "datetime", "json", "any", "blocknote"];
111
112
  if (field.type && !validTypes.includes(field.type)) {
112
113
  errors.push({
113
114
  field: `fields[${index}].type`,