@famgia/omnify-core 0.0.113 → 0.0.115

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/dist/index.cjs CHANGED
@@ -605,6 +605,8 @@ function parseJsonSchema(content, filePath) {
605
605
  }
606
606
  var VALID_SCHEMA_FIELDS = /* @__PURE__ */ new Set([
607
607
  "kind",
608
+ "target",
609
+ // For partial schemas
608
610
  "displayName",
609
611
  "titleIndex",
610
612
  "group",
@@ -641,6 +643,9 @@ function buildSchemaDefinition(data) {
641
643
  if (data.kind !== void 0) {
642
644
  schema.kind = data.kind;
643
645
  }
646
+ if (data.target !== void 0 && typeof data.target === "string") {
647
+ schema.target = data.target;
648
+ }
644
649
  if (data.displayName !== void 0 && (0, import_omnify_types.isLocalizedString)(data.displayName)) {
645
650
  schema.displayName = data.displayName;
646
651
  }
@@ -966,9 +971,14 @@ async function loadSchemas(directoryPath, options = {}) {
966
971
  }
967
972
  const schemaFiles = await findSchemaFiles(absoluteDir, extensions, recursive);
968
973
  const schemas = {};
974
+ const partialSchemas = [];
969
975
  const schemaLocations = {};
970
976
  for (const filePath of schemaFiles) {
971
977
  const schema = await loadSchema(filePath, { baseDir: absoluteDir });
978
+ if (schema.kind === "partial") {
979
+ partialSchemas.push(schema);
980
+ continue;
981
+ }
972
982
  const existingLocation = schemaLocations[schema.name];
973
983
  if (existingLocation !== void 0) {
974
984
  throw duplicateSchemaError(
@@ -980,6 +990,26 @@ async function loadSchemas(directoryPath, options = {}) {
980
990
  schemas[schema.name] = schema;
981
991
  schemaLocations[schema.name] = filePath;
982
992
  }
993
+ for (const partial of partialSchemas) {
994
+ const targetName = partial.target;
995
+ if (!targetName) {
996
+ console.warn(`Partial schema '${partial.name}' has no target, skipping`);
997
+ continue;
998
+ }
999
+ const target = schemas[targetName];
1000
+ if (!target) {
1001
+ console.warn(`Partial schema '${partial.name}' targets unknown schema '${targetName}', skipping`);
1002
+ continue;
1003
+ }
1004
+ const mergedProperties = {
1005
+ ...partial.properties ?? {},
1006
+ ...target.properties ?? {}
1007
+ };
1008
+ schemas[targetName] = {
1009
+ ...target,
1010
+ properties: mergedProperties
1011
+ };
1012
+ }
983
1013
  return schemas;
984
1014
  }
985
1015
  var FILE_SCHEMA_NAME = "File";
@@ -2831,6 +2861,62 @@ function validateEnumSchema(schema, filePath) {
2831
2861
  }
2832
2862
  return errors;
2833
2863
  }
2864
+ function validatePartialSchema(schema, filePath) {
2865
+ const errors = [];
2866
+ if (schema.kind !== "partial") {
2867
+ return errors;
2868
+ }
2869
+ if (!schema.target) {
2870
+ errors.push(
2871
+ validationError(
2872
+ "Partial schema requires a target schema name",
2873
+ buildLocation7(filePath),
2874
+ "Add target: SchemaName to specify which schema to extend"
2875
+ )
2876
+ );
2877
+ } else if (typeof schema.target !== "string") {
2878
+ errors.push(
2879
+ validationError(
2880
+ "Partial schema target must be a string",
2881
+ buildLocation7(filePath),
2882
+ "Example: target: User"
2883
+ )
2884
+ );
2885
+ }
2886
+ if (!schema.properties || Object.keys(schema.properties).length === 0) {
2887
+ errors.push(
2888
+ validationError(
2889
+ "Partial schema requires at least one property to extend the target",
2890
+ buildLocation7(filePath),
2891
+ "Add properties to extend the target schema"
2892
+ )
2893
+ );
2894
+ }
2895
+ if (schema.values && schema.values.length > 0) {
2896
+ errors.push(
2897
+ validationError(
2898
+ "Partial schema cannot have values (values are for enum schemas)",
2899
+ buildLocation7(filePath),
2900
+ "Remove values or change kind to enum"
2901
+ )
2902
+ );
2903
+ }
2904
+ if (schema.options) {
2905
+ const invalidOptions = ["id", "timestamps", "softDelete", "tableName"];
2906
+ for (const opt of invalidOptions) {
2907
+ if (schema.options[opt] !== void 0) {
2908
+ errors.push(
2909
+ validationError(
2910
+ `Partial schema cannot have option '${opt}' (table options belong to the target schema)`,
2911
+ buildLocation7(filePath),
2912
+ `Remove options.${opt} - table-level options should be in the target schema`
2913
+ )
2914
+ );
2915
+ }
2916
+ }
2917
+ }
2918
+ return errors;
2919
+ }
2834
2920
  function validateLocalizedString(fieldName, value, filePath, localeConfig, context) {
2835
2921
  const warnings = [];
2836
2922
  if (value === void 0 || !(0, import_omnify_types2.isLocaleMap)(value)) {
@@ -2905,6 +2991,10 @@ function validateSchema(schema, options = {}) {
2905
2991
  const enumErrors = validateEnumSchema(schema, schema.filePath);
2906
2992
  errors.push(...enumErrors);
2907
2993
  }
2994
+ if (schema.kind === "partial") {
2995
+ const partialErrors = validatePartialSchema(schema, schema.filePath);
2996
+ errors.push(...partialErrors);
2997
+ }
2908
2998
  if (schema.titleIndex && schema.properties) {
2909
2999
  if (!schema.properties[schema.titleIndex]) {
2910
3000
  errors.push(
@@ -2981,6 +3071,29 @@ function validateSchemas(schemas, options = {}) {
2981
3071
  }
2982
3072
  }
2983
3073
  }
3074
+ for (const schema of Object.values(schemas)) {
3075
+ if (schema.kind === "partial" && schema.target) {
3076
+ const targetExists = schemas[schema.target] !== void 0;
3077
+ if (!targetExists) {
3078
+ const error = validationError(
3079
+ `Partial schema '${schema.name}' targets non-existent schema '${schema.target}'`,
3080
+ buildLocation7(schema.filePath),
3081
+ `Available schemas: ${Object.keys(schemas).filter((n) => n !== schema.name).join(", ")}`
3082
+ );
3083
+ allErrors.push(error);
3084
+ const existingResult = schemaResults.find((r) => r.schemaName === schema.name);
3085
+ if (existingResult) {
3086
+ const updatedResult = {
3087
+ ...existingResult,
3088
+ valid: false,
3089
+ errors: [...existingResult.errors, error]
3090
+ };
3091
+ const index = schemaResults.indexOf(existingResult);
3092
+ schemaResults[index] = updatedResult;
3093
+ }
3094
+ }
3095
+ }
3096
+ }
2984
3097
  return {
2985
3098
  valid: allErrors.length === 0,
2986
3099
  errorCount: allErrors.length,