@famgia/omnify-core 0.0.13 → 0.0.16
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 +207 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -12
- package/dist/index.d.ts +19 -12
- package/dist/index.js +204 -34
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ErrorCode, ErrorLocation, OmnifyErrorInfo, LoadedSchema, SchemaCollection, SchemaDefinition, PropertyDefinition, PluginLogger,
|
|
1
|
+
import { ErrorCode, ErrorLocation, OmnifyErrorInfo, LoadedSchema, SchemaCollection, SchemaDefinition, CustomTypeDefinition, LocaleConfig, PropertyDefinition, PluginLogger, GeneratorDefinition, OmnifyPlugin, GeneratorOutput, SchemaChange, OmnifyConfig, LocalizedString, AssociationDefinition } from '@famgia/omnify-types';
|
|
2
2
|
export { AssociationRelation, CustomTypeDefinition, DatabaseConfig, ErrorCode, ErrorLocation, LoadedSchema, OmnifyConfig, OmnifyErrorInfo, OmnifyPlugin, OutputConfig, PropertyDefinition, PropertyType, Result, SchemaCollection, SchemaDefinition, SchemaOptions, err, ok } from '@famgia/omnify-types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -364,21 +364,27 @@ type DatabaseDriver = 'mysql' | 'postgres' | 'sqlite' | 'sqlserver';
|
|
|
364
364
|
interface ValidationOptions {
|
|
365
365
|
/** Whether to treat warnings as errors */
|
|
366
366
|
readonly strict?: boolean;
|
|
367
|
-
/**
|
|
367
|
+
/**
|
|
368
|
+
* Custom type names registered by plugins.
|
|
369
|
+
* @deprecated Use customTypeDefinitions for full validation support
|
|
370
|
+
*/
|
|
368
371
|
readonly customTypes?: readonly string[];
|
|
372
|
+
/**
|
|
373
|
+
* Full custom type definitions from plugins.
|
|
374
|
+
* Provides validFields for proper field validation.
|
|
375
|
+
*/
|
|
376
|
+
readonly customTypeDefinitions?: ReadonlyMap<string, CustomTypeDefinition>;
|
|
369
377
|
/** Whether to validate associations (requires all schemas) */
|
|
370
378
|
readonly validateAssociations?: boolean;
|
|
371
379
|
/** Database driver for compatibility checking */
|
|
372
380
|
readonly databaseDriver?: DatabaseDriver;
|
|
381
|
+
/**
|
|
382
|
+
* Locale configuration for validating localized strings.
|
|
383
|
+
* When provided, warns if displayName/description uses locales not in the configured list.
|
|
384
|
+
*/
|
|
385
|
+
readonly localeConfig?: LocaleConfig;
|
|
373
386
|
}
|
|
374
387
|
|
|
375
|
-
/**
|
|
376
|
-
* @famgia/omnify-core - Schema Validator
|
|
377
|
-
*
|
|
378
|
-
* Validates schema definitions for correctness and consistency.
|
|
379
|
-
* Uses class-based type system for extensible validation.
|
|
380
|
-
*/
|
|
381
|
-
|
|
382
388
|
/**
|
|
383
389
|
* Validates a property type.
|
|
384
390
|
*/
|
|
@@ -624,9 +630,10 @@ declare class PluginManager {
|
|
|
624
630
|
/**
|
|
625
631
|
* Runs all registered generators in topological order.
|
|
626
632
|
* @param schemas - The schemas to generate from
|
|
633
|
+
* @param changes - Schema changes detected from lock file comparison
|
|
627
634
|
* @returns Result with all generated outputs
|
|
628
635
|
*/
|
|
629
|
-
runGenerators(schemas: SchemaCollection): Promise<GeneratorRunResult>;
|
|
636
|
+
runGenerators(schemas: SchemaCollection, changes?: readonly SchemaChange[]): Promise<GeneratorRunResult>;
|
|
630
637
|
/**
|
|
631
638
|
* Clears all registered plugins, types, and generators.
|
|
632
639
|
*/
|
|
@@ -866,8 +873,8 @@ interface GeneratedFile {
|
|
|
866
873
|
interface SchemaMetadata {
|
|
867
874
|
/** Schema name */
|
|
868
875
|
name: string;
|
|
869
|
-
/** Display name */
|
|
870
|
-
displayName?:
|
|
876
|
+
/** Display name (supports multi-language) */
|
|
877
|
+
displayName?: LocalizedString;
|
|
871
878
|
/** Group name */
|
|
872
879
|
group?: string;
|
|
873
880
|
/** Schema kind */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ErrorCode, ErrorLocation, OmnifyErrorInfo, LoadedSchema, SchemaCollection, SchemaDefinition, PropertyDefinition, PluginLogger,
|
|
1
|
+
import { ErrorCode, ErrorLocation, OmnifyErrorInfo, LoadedSchema, SchemaCollection, SchemaDefinition, CustomTypeDefinition, LocaleConfig, PropertyDefinition, PluginLogger, GeneratorDefinition, OmnifyPlugin, GeneratorOutput, SchemaChange, OmnifyConfig, LocalizedString, AssociationDefinition } from '@famgia/omnify-types';
|
|
2
2
|
export { AssociationRelation, CustomTypeDefinition, DatabaseConfig, ErrorCode, ErrorLocation, LoadedSchema, OmnifyConfig, OmnifyErrorInfo, OmnifyPlugin, OutputConfig, PropertyDefinition, PropertyType, Result, SchemaCollection, SchemaDefinition, SchemaOptions, err, ok } from '@famgia/omnify-types';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -364,21 +364,27 @@ type DatabaseDriver = 'mysql' | 'postgres' | 'sqlite' | 'sqlserver';
|
|
|
364
364
|
interface ValidationOptions {
|
|
365
365
|
/** Whether to treat warnings as errors */
|
|
366
366
|
readonly strict?: boolean;
|
|
367
|
-
/**
|
|
367
|
+
/**
|
|
368
|
+
* Custom type names registered by plugins.
|
|
369
|
+
* @deprecated Use customTypeDefinitions for full validation support
|
|
370
|
+
*/
|
|
368
371
|
readonly customTypes?: readonly string[];
|
|
372
|
+
/**
|
|
373
|
+
* Full custom type definitions from plugins.
|
|
374
|
+
* Provides validFields for proper field validation.
|
|
375
|
+
*/
|
|
376
|
+
readonly customTypeDefinitions?: ReadonlyMap<string, CustomTypeDefinition>;
|
|
369
377
|
/** Whether to validate associations (requires all schemas) */
|
|
370
378
|
readonly validateAssociations?: boolean;
|
|
371
379
|
/** Database driver for compatibility checking */
|
|
372
380
|
readonly databaseDriver?: DatabaseDriver;
|
|
381
|
+
/**
|
|
382
|
+
* Locale configuration for validating localized strings.
|
|
383
|
+
* When provided, warns if displayName/description uses locales not in the configured list.
|
|
384
|
+
*/
|
|
385
|
+
readonly localeConfig?: LocaleConfig;
|
|
373
386
|
}
|
|
374
387
|
|
|
375
|
-
/**
|
|
376
|
-
* @famgia/omnify-core - Schema Validator
|
|
377
|
-
*
|
|
378
|
-
* Validates schema definitions for correctness and consistency.
|
|
379
|
-
* Uses class-based type system for extensible validation.
|
|
380
|
-
*/
|
|
381
|
-
|
|
382
388
|
/**
|
|
383
389
|
* Validates a property type.
|
|
384
390
|
*/
|
|
@@ -624,9 +630,10 @@ declare class PluginManager {
|
|
|
624
630
|
/**
|
|
625
631
|
* Runs all registered generators in topological order.
|
|
626
632
|
* @param schemas - The schemas to generate from
|
|
633
|
+
* @param changes - Schema changes detected from lock file comparison
|
|
627
634
|
* @returns Result with all generated outputs
|
|
628
635
|
*/
|
|
629
|
-
runGenerators(schemas: SchemaCollection): Promise<GeneratorRunResult>;
|
|
636
|
+
runGenerators(schemas: SchemaCollection, changes?: readonly SchemaChange[]): Promise<GeneratorRunResult>;
|
|
630
637
|
/**
|
|
631
638
|
* Clears all registered plugins, types, and generators.
|
|
632
639
|
*/
|
|
@@ -866,8 +873,8 @@ interface GeneratedFile {
|
|
|
866
873
|
interface SchemaMetadata {
|
|
867
874
|
/** Schema name */
|
|
868
875
|
name: string;
|
|
869
|
-
/** Display name */
|
|
870
|
-
displayName?:
|
|
876
|
+
/** Display name (supports multi-language) */
|
|
877
|
+
displayName?: LocalizedString;
|
|
871
878
|
/** Group name */
|
|
872
879
|
group?: string;
|
|
873
880
|
/** Schema kind */
|
package/dist/index.js
CHANGED
|
@@ -442,6 +442,7 @@ function notImplementedError(feature) {
|
|
|
442
442
|
import * as fs from "fs/promises";
|
|
443
443
|
import * as path from "path";
|
|
444
444
|
import yaml from "js-yaml";
|
|
445
|
+
import { isLocalizedString } from "@famgia/omnify-types";
|
|
445
446
|
function fileNameToSchemaName(fileName) {
|
|
446
447
|
const baseName = path.basename(fileName, path.extname(fileName));
|
|
447
448
|
if (!baseName.includes("-") && !baseName.includes("_")) {
|
|
@@ -528,7 +529,7 @@ function buildSchemaDefinition(data) {
|
|
|
528
529
|
if (data.kind !== void 0) {
|
|
529
530
|
schema.kind = data.kind;
|
|
530
531
|
}
|
|
531
|
-
if (data.displayName !== void 0 &&
|
|
532
|
+
if (data.displayName !== void 0 && isLocalizedString(data.displayName)) {
|
|
532
533
|
schema.displayName = data.displayName;
|
|
533
534
|
}
|
|
534
535
|
if (data.titleIndex !== void 0 && typeof data.titleIndex === "string") {
|
|
@@ -554,10 +555,13 @@ function buildSchemaDefinition(data) {
|
|
|
554
555
|
}
|
|
555
556
|
}
|
|
556
557
|
if (data.properties !== void 0 && typeof data.properties === "object") {
|
|
557
|
-
const properties = buildProperties(data.properties);
|
|
558
|
+
const { properties, invalidProperties } = buildProperties(data.properties);
|
|
558
559
|
if (Object.keys(properties).length > 0) {
|
|
559
560
|
schema.properties = properties;
|
|
560
561
|
}
|
|
562
|
+
if (invalidProperties.length > 0) {
|
|
563
|
+
schema._invalidProperties = invalidProperties;
|
|
564
|
+
}
|
|
561
565
|
}
|
|
562
566
|
if (data.values !== void 0 && Array.isArray(data.values)) {
|
|
563
567
|
schema.values = data.values;
|
|
@@ -606,12 +610,25 @@ function buildSchemaOptions(data) {
|
|
|
606
610
|
}
|
|
607
611
|
function buildProperties(data) {
|
|
608
612
|
const properties = {};
|
|
613
|
+
const invalidProperties = [];
|
|
609
614
|
for (const [name, value] of Object.entries(data)) {
|
|
610
|
-
if (value
|
|
615
|
+
if (value === void 0 || value === null) {
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (typeof value === "object") {
|
|
611
619
|
properties[name] = buildPropertyDefinition(value);
|
|
620
|
+
} else {
|
|
621
|
+
invalidProperties.push({
|
|
622
|
+
propertyName: name,
|
|
623
|
+
value,
|
|
624
|
+
expectedFormat: `Property '${name}' must be an object with 'type' field. Example:
|
|
625
|
+
${name}:
|
|
626
|
+
type: String
|
|
627
|
+
nullable: true`
|
|
628
|
+
});
|
|
612
629
|
}
|
|
613
630
|
}
|
|
614
|
-
return properties;
|
|
631
|
+
return { properties, invalidProperties };
|
|
615
632
|
}
|
|
616
633
|
var VALID_PROPERTY_FIELDS = /* @__PURE__ */ new Set([
|
|
617
634
|
"type",
|
|
@@ -660,7 +677,7 @@ function buildPropertyDefinition(data) {
|
|
|
660
677
|
if (unknownFields.length > 0) {
|
|
661
678
|
prop._unknownFields = unknownFields;
|
|
662
679
|
}
|
|
663
|
-
if (data.displayName !== void 0 &&
|
|
680
|
+
if (data.displayName !== void 0 && isLocalizedString(data.displayName)) {
|
|
664
681
|
prop.displayName = data.displayName;
|
|
665
682
|
}
|
|
666
683
|
if (data.nullable !== void 0 && typeof data.nullable === "boolean") {
|
|
@@ -672,7 +689,7 @@ function buildPropertyDefinition(data) {
|
|
|
672
689
|
if (data.unique !== void 0 && typeof data.unique === "boolean") {
|
|
673
690
|
prop.unique = data.unique;
|
|
674
691
|
}
|
|
675
|
-
if (data.description !== void 0 &&
|
|
692
|
+
if (data.description !== void 0 && isLocalizedString(data.description)) {
|
|
676
693
|
prop.description = data.description;
|
|
677
694
|
}
|
|
678
695
|
if (data.renamedFrom !== void 0 && typeof data.renamedFrom === "string") {
|
|
@@ -949,6 +966,9 @@ async function ensureFileSchema(schemas, schemasDir, autoCreate = false) {
|
|
|
949
966
|
};
|
|
950
967
|
}
|
|
951
968
|
|
|
969
|
+
// src/validation/validator.ts
|
|
970
|
+
import { isLocaleMap } from "@famgia/omnify-types";
|
|
971
|
+
|
|
952
972
|
// src/validation/types/base.ts
|
|
953
973
|
var BASE_PROPERTY_FIELDS = [
|
|
954
974
|
"type",
|
|
@@ -1042,6 +1062,30 @@ var TypeRegistry = class {
|
|
|
1042
1062
|
getAllTypeNames() {
|
|
1043
1063
|
return [...this.types.keys()];
|
|
1044
1064
|
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Get all valid fields across ALL types.
|
|
1067
|
+
* Used to determine if a field is valid for any type.
|
|
1068
|
+
*/
|
|
1069
|
+
getAllValidFields() {
|
|
1070
|
+
const allFields = /* @__PURE__ */ new Set();
|
|
1071
|
+
for (const type of this.types.values()) {
|
|
1072
|
+
for (const field of type.validFields) {
|
|
1073
|
+
allFields.add(field);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
return allFields;
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Check if a field is valid for any registered type.
|
|
1080
|
+
*/
|
|
1081
|
+
isFieldValidForAnyType(field) {
|
|
1082
|
+
for (const type of this.types.values()) {
|
|
1083
|
+
if (type.validFields.includes(field)) {
|
|
1084
|
+
return true;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
return false;
|
|
1088
|
+
}
|
|
1045
1089
|
/**
|
|
1046
1090
|
* Get count of registered types.
|
|
1047
1091
|
*/
|
|
@@ -2095,6 +2139,25 @@ function validateUnknownOptionsFields(schema, filePath) {
|
|
|
2095
2139
|
}
|
|
2096
2140
|
return errors;
|
|
2097
2141
|
}
|
|
2142
|
+
function validatePropertyFormat(schema, filePath) {
|
|
2143
|
+
const errors = [];
|
|
2144
|
+
const invalidProperties = schema._invalidProperties;
|
|
2145
|
+
if (!invalidProperties || invalidProperties.length === 0) {
|
|
2146
|
+
return errors;
|
|
2147
|
+
}
|
|
2148
|
+
for (const invalid of invalidProperties) {
|
|
2149
|
+
const valueType = typeof invalid.value;
|
|
2150
|
+
const valuePreview = valueType === "string" ? `"${invalid.value}"` : String(invalid.value);
|
|
2151
|
+
errors.push(
|
|
2152
|
+
validationError(
|
|
2153
|
+
`Property '${invalid.propertyName}' has invalid format: got ${valueType} (${valuePreview})`,
|
|
2154
|
+
buildLocation7(filePath),
|
|
2155
|
+
invalid.expectedFormat
|
|
2156
|
+
)
|
|
2157
|
+
);
|
|
2158
|
+
}
|
|
2159
|
+
return errors;
|
|
2160
|
+
}
|
|
2098
2161
|
function validateDbCompatibility(propertyName, property, filePath, databaseDriver) {
|
|
2099
2162
|
const errors = [];
|
|
2100
2163
|
const warnings = [];
|
|
@@ -2121,16 +2184,52 @@ function validateDbCompatibility(propertyName, property, filePath, databaseDrive
|
|
|
2121
2184
|
}
|
|
2122
2185
|
return { errors, warnings };
|
|
2123
2186
|
}
|
|
2124
|
-
function
|
|
2187
|
+
function validateUnknownFieldsDetailed(propertyName, property, filePath, customTypeDefinitions) {
|
|
2125
2188
|
const errors = [];
|
|
2126
|
-
const
|
|
2127
|
-
if (!
|
|
2128
|
-
return errors;
|
|
2189
|
+
const warnings = [];
|
|
2190
|
+
if (!property.type) {
|
|
2191
|
+
return { errors, warnings };
|
|
2129
2192
|
}
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2193
|
+
let validFields;
|
|
2194
|
+
const isBuiltIn = typeRegistry.has(property.type);
|
|
2195
|
+
if (isBuiltIn) {
|
|
2196
|
+
validFields = typeRegistry.getValidFields(property.type);
|
|
2197
|
+
} else {
|
|
2198
|
+
const customTypeDef = customTypeDefinitions?.get(property.type);
|
|
2199
|
+
if (customTypeDef?.validFields) {
|
|
2200
|
+
validFields = [...BASE_PROPERTY_FIELDS, ...customTypeDef.validFields];
|
|
2201
|
+
} else {
|
|
2202
|
+
validFields = [...BASE_PROPERTY_FIELDS];
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
const validFieldsSet = new Set(validFields);
|
|
2206
|
+
for (const field of Object.keys(property)) {
|
|
2207
|
+
if (field.startsWith("_")) continue;
|
|
2208
|
+
if (validFieldsSet.has(field)) continue;
|
|
2209
|
+
const isValidForOtherType = typeRegistry.isFieldValidForAnyType(field);
|
|
2210
|
+
if (isValidForOtherType) {
|
|
2211
|
+
errors.push(
|
|
2212
|
+
validationError(
|
|
2213
|
+
`Property '${propertyName}' of type '${property.type}' has invalid field '${field}'`,
|
|
2214
|
+
buildLocation7(filePath),
|
|
2215
|
+
`'${field}' is not valid for type '${property.type}'. Valid fields: ${validFields.join(", ")}`
|
|
2216
|
+
)
|
|
2217
|
+
);
|
|
2218
|
+
} else {
|
|
2219
|
+
warnings.push(
|
|
2220
|
+
validationError(
|
|
2221
|
+
`Property '${propertyName}' has unknown field '${field}'`,
|
|
2222
|
+
buildLocation7(filePath),
|
|
2223
|
+
getSuggestionForUnknownField(field)
|
|
2224
|
+
)
|
|
2225
|
+
);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
return { errors, warnings };
|
|
2229
|
+
}
|
|
2230
|
+
function getSuggestionForUnknownField(field) {
|
|
2231
|
+
if (field === "required") {
|
|
2232
|
+
return `'required' is not a valid field. Properties are required by default.
|
|
2134
2233
|
Use 'nullable: true' to make a field optional.
|
|
2135
2234
|
Example:
|
|
2136
2235
|
email:
|
|
@@ -2140,10 +2239,12 @@ Example:
|
|
|
2140
2239
|
phone:
|
|
2141
2240
|
type: String
|
|
2142
2241
|
nullable: true # optional field`;
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2242
|
+
}
|
|
2243
|
+
if (field === "hidden") {
|
|
2244
|
+
return `'hidden' is not a standard field. For Laravel, hidden fields are configured in the Model class.`;
|
|
2245
|
+
}
|
|
2246
|
+
if (field === "foreignKey") {
|
|
2247
|
+
return `'foreignKey' is not needed. Omnify auto-generates foreign keys from Association properties.
|
|
2147
2248
|
The foreign key name is derived from the property name + '_id'.
|
|
2148
2249
|
Example:
|
|
2149
2250
|
author:
|
|
@@ -2151,16 +2252,8 @@ Example:
|
|
|
2151
2252
|
relation: ManyToOne
|
|
2152
2253
|
target: User
|
|
2153
2254
|
# Creates author_id column automatically`;
|
|
2154
|
-
}
|
|
2155
|
-
errors.push(
|
|
2156
|
-
validationError(
|
|
2157
|
-
`Property '${propertyName}' has unknown field '${field}'`,
|
|
2158
|
-
buildLocation7(filePath),
|
|
2159
|
-
suggestion
|
|
2160
|
-
)
|
|
2161
|
-
);
|
|
2162
2255
|
}
|
|
2163
|
-
return
|
|
2256
|
+
return `Valid property fields: type, displayName, nullable, default, unique, description, length, unsigned, precision, scale, enum, relation, target, onDelete, onUpdate, joinTable`;
|
|
2164
2257
|
}
|
|
2165
2258
|
function validatePropertyType(propertyName, property, filePath, customTypes = []) {
|
|
2166
2259
|
const errors = [];
|
|
@@ -2416,6 +2509,62 @@ function validateEnumSchema(schema, filePath) {
|
|
|
2416
2509
|
}
|
|
2417
2510
|
return errors;
|
|
2418
2511
|
}
|
|
2512
|
+
function validateLocalizedString(fieldName, value, filePath, localeConfig, context) {
|
|
2513
|
+
const warnings = [];
|
|
2514
|
+
if (value === void 0 || !isLocaleMap(value)) {
|
|
2515
|
+
return { warnings };
|
|
2516
|
+
}
|
|
2517
|
+
if (!localeConfig) {
|
|
2518
|
+
return { warnings };
|
|
2519
|
+
}
|
|
2520
|
+
const configuredLocales = new Set(localeConfig.locales);
|
|
2521
|
+
const usedLocales = Object.keys(value);
|
|
2522
|
+
for (const locale of usedLocales) {
|
|
2523
|
+
if (!configuredLocales.has(locale)) {
|
|
2524
|
+
const contextStr = context ? ` (property '${context}')` : "";
|
|
2525
|
+
warnings.push(
|
|
2526
|
+
validationError(
|
|
2527
|
+
`${fieldName}${contextStr} uses locale '${locale}' which is not in configured locales`,
|
|
2528
|
+
buildLocation7(filePath),
|
|
2529
|
+
`Configured locales: ${localeConfig.locales.join(", ")}. Add '${locale}' to your locale configuration or remove it from the schema.`
|
|
2530
|
+
)
|
|
2531
|
+
);
|
|
2532
|
+
}
|
|
2533
|
+
}
|
|
2534
|
+
return { warnings };
|
|
2535
|
+
}
|
|
2536
|
+
function validateLocalizedStrings(schema, localeConfig) {
|
|
2537
|
+
const warnings = [];
|
|
2538
|
+
const schemaDisplayNameResult = validateLocalizedString(
|
|
2539
|
+
"displayName",
|
|
2540
|
+
schema.displayName,
|
|
2541
|
+
schema.filePath,
|
|
2542
|
+
localeConfig
|
|
2543
|
+
);
|
|
2544
|
+
warnings.push(...schemaDisplayNameResult.warnings);
|
|
2545
|
+
if (schema.properties) {
|
|
2546
|
+
for (const [propName, property] of Object.entries(schema.properties)) {
|
|
2547
|
+
const propDisplayNameResult = validateLocalizedString(
|
|
2548
|
+
"displayName",
|
|
2549
|
+
property.displayName,
|
|
2550
|
+
schema.filePath,
|
|
2551
|
+
localeConfig,
|
|
2552
|
+
propName
|
|
2553
|
+
);
|
|
2554
|
+
warnings.push(...propDisplayNameResult.warnings);
|
|
2555
|
+
const propDescription = property.description;
|
|
2556
|
+
const propDescriptionResult = validateLocalizedString(
|
|
2557
|
+
"description",
|
|
2558
|
+
propDescription,
|
|
2559
|
+
schema.filePath,
|
|
2560
|
+
localeConfig,
|
|
2561
|
+
propName
|
|
2562
|
+
);
|
|
2563
|
+
warnings.push(...propDescriptionResult.warnings);
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
return warnings;
|
|
2567
|
+
}
|
|
2419
2568
|
function validateSchema(schema, options = {}) {
|
|
2420
2569
|
const errors = [];
|
|
2421
2570
|
const warnings = [];
|
|
@@ -2424,6 +2573,8 @@ function validateSchema(schema, options = {}) {
|
|
|
2424
2573
|
errors.push(...unknownSchemaFieldErrors);
|
|
2425
2574
|
const unknownOptionsErrors = validateUnknownOptionsFields(schema, schema.filePath);
|
|
2426
2575
|
errors.push(...unknownOptionsErrors);
|
|
2576
|
+
const propertyFormatErrors = validatePropertyFormat(schema, schema.filePath);
|
|
2577
|
+
errors.push(...propertyFormatErrors);
|
|
2427
2578
|
const propErrors = validateProperties(schema, schema.filePath, customTypes);
|
|
2428
2579
|
errors.push(...propErrors);
|
|
2429
2580
|
const optErrors = validateOptions(schema, schema.filePath);
|
|
@@ -2445,13 +2596,21 @@ function validateSchema(schema, options = {}) {
|
|
|
2445
2596
|
}
|
|
2446
2597
|
if (schema.properties) {
|
|
2447
2598
|
for (const [name, property] of Object.entries(schema.properties)) {
|
|
2448
|
-
const
|
|
2449
|
-
|
|
2599
|
+
const unknownFieldResult = validateUnknownFieldsDetailed(
|
|
2600
|
+
name,
|
|
2601
|
+
property,
|
|
2602
|
+
schema.filePath,
|
|
2603
|
+
options.customTypeDefinitions
|
|
2604
|
+
);
|
|
2605
|
+
errors.push(...unknownFieldResult.errors);
|
|
2606
|
+
warnings.push(...unknownFieldResult.warnings);
|
|
2450
2607
|
const dbCompat = validateDbCompatibility(name, property, schema.filePath, options.databaseDriver);
|
|
2451
2608
|
errors.push(...dbCompat.errors);
|
|
2452
2609
|
warnings.push(...dbCompat.warnings);
|
|
2453
2610
|
}
|
|
2454
2611
|
}
|
|
2612
|
+
const localizedStringWarnings = validateLocalizedStrings(schema, options.localeConfig);
|
|
2613
|
+
warnings.push(...localizedStringWarnings);
|
|
2455
2614
|
return {
|
|
2456
2615
|
schemaName: schema.name,
|
|
2457
2616
|
valid: errors.length === 0,
|
|
@@ -2541,8 +2700,10 @@ var GeneratorRunner = class {
|
|
|
2541
2700
|
}
|
|
2542
2701
|
/**
|
|
2543
2702
|
* Run all generators in topological order.
|
|
2703
|
+
* @param schemas - The schemas to generate from
|
|
2704
|
+
* @param changes - Schema changes detected from lock file comparison
|
|
2544
2705
|
*/
|
|
2545
|
-
async runAll(schemas) {
|
|
2706
|
+
async runAll(schemas, changes) {
|
|
2546
2707
|
const errors = [];
|
|
2547
2708
|
const outputs = [];
|
|
2548
2709
|
const outputsByGenerator = /* @__PURE__ */ new Map();
|
|
@@ -2570,10 +2731,12 @@ var GeneratorRunner = class {
|
|
|
2570
2731
|
this.options.logger.debug(`Running generator: ${name}`);
|
|
2571
2732
|
const ctx = {
|
|
2572
2733
|
schemas,
|
|
2734
|
+
changes,
|
|
2573
2735
|
pluginConfig,
|
|
2574
2736
|
cwd: this.options.cwd,
|
|
2575
2737
|
logger: this.options.logger,
|
|
2576
|
-
previousOutputs
|
|
2738
|
+
previousOutputs,
|
|
2739
|
+
customTypes: this.options.customTypes ?? /* @__PURE__ */ new Map()
|
|
2577
2740
|
};
|
|
2578
2741
|
const result = await definition.generate(ctx);
|
|
2579
2742
|
const generatorOutputs = Array.isArray(result) ? result : [result];
|
|
@@ -2925,17 +3088,24 @@ var PluginManager = class {
|
|
|
2925
3088
|
/**
|
|
2926
3089
|
* Runs all registered generators in topological order.
|
|
2927
3090
|
* @param schemas - The schemas to generate from
|
|
3091
|
+
* @param changes - Schema changes detected from lock file comparison
|
|
2928
3092
|
* @returns Result with all generated outputs
|
|
2929
3093
|
*/
|
|
2930
|
-
async runGenerators(schemas) {
|
|
3094
|
+
async runGenerators(schemas, changes) {
|
|
3095
|
+
const customTypes = /* @__PURE__ */ new Map();
|
|
3096
|
+
for (const [name, registeredType] of this._types) {
|
|
3097
|
+
const { pluginName, pluginVersion, ...typeDefinition } = registeredType;
|
|
3098
|
+
customTypes.set(name, typeDefinition);
|
|
3099
|
+
}
|
|
2931
3100
|
const runner = new GeneratorRunner({
|
|
2932
3101
|
cwd: this._cwd,
|
|
2933
|
-
logger: this._logger
|
|
3102
|
+
logger: this._logger,
|
|
3103
|
+
customTypes
|
|
2934
3104
|
});
|
|
2935
3105
|
for (const gen of this._generators.values()) {
|
|
2936
3106
|
runner.register(gen);
|
|
2937
3107
|
}
|
|
2938
|
-
return runner.runAll(schemas);
|
|
3108
|
+
return runner.runAll(schemas, changes);
|
|
2939
3109
|
}
|
|
2940
3110
|
/**
|
|
2941
3111
|
* Clears all registered plugins, types, and generators.
|