@api-client/core 0.18.14 → 0.18.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.
@@ -0,0 +1,84 @@
1
+ import type { JSONSchema7 } from 'json-schema';
2
+ import type { JsonImportReport, InMemorySchema } from './JsonSchemaImporter.js';
3
+ import { JsonSchemaImporter } from './JsonSchemaImporter.js';
4
+ import { SchemaFilteringStrategy, type SchemaFilteringOptions, FILTERING_STRATEGIES } from './SchemaFilteringStrategy.js';
5
+ import type { DataDomain } from '../DataDomain.js';
6
+ /**
7
+ * Extended JsonSchemaImporter that supports filtering out non-structural schemas.
8
+ * This version can eliminate schemas that don't contribute meaningful structure
9
+ * to the data model, such as empty objects or conceptual marker types.
10
+ */
11
+ export declare class FilteringJsonSchemaImporter extends JsonSchemaImporter {
12
+ private filteringStrategy;
13
+ constructor(domain: DataDomain, filteringOptions?: SchemaFilteringOptions);
14
+ /**
15
+ * Creates an importer with a predefined filtering strategy.
16
+ */
17
+ static withStrategy(domain: DataDomain, strategyName: keyof typeof FILTERING_STRATEGIES): FilteringJsonSchemaImporter;
18
+ /**
19
+ * Creates an importer optimized for API development.
20
+ * Excludes schemas that don't contribute to API structure.
21
+ */
22
+ static forApiModeling(domain: DataDomain): FilteringJsonSchemaImporter;
23
+ /**
24
+ * Creates an importer optimized for database schema generation.
25
+ * Very strict filtering - only includes schemas with concrete properties.
26
+ */
27
+ static forDatabaseModeling(domain: DataDomain): FilteringJsonSchemaImporter;
28
+ /**
29
+ * Override the base import method to apply filtering.
30
+ */
31
+ import(schemas: InMemorySchema[], modelName: string): Promise<JsonImportReport>;
32
+ /**
33
+ * Pre-filters schemas before they are processed by the base importer.
34
+ */
35
+ private preFilterSchemas;
36
+ /**
37
+ * Post-processes the import report to clean up any remaining filtered entities.
38
+ */
39
+ private postFilterReport;
40
+ /**
41
+ * Determines if an entity should be filtered out based on its characteristics.
42
+ */
43
+ private shouldFilterEntity;
44
+ /**
45
+ * Gets a human-readable reason for filtering an entity.
46
+ */
47
+ private getEntityFilterReason;
48
+ /**
49
+ * Removes associations that reference entities that were filtered out.
50
+ */
51
+ private cleanupOrphanedAssociations;
52
+ }
53
+ /**
54
+ * Utility functions for working with filtered imports.
55
+ */
56
+ export declare const SchemaFilteringUtils: {
57
+ /**
58
+ * Analyzes a JSON schema to determine if it would be filtered by the given strategy.
59
+ */
60
+ wouldBeFiltered(schema: JSONSchema7, strategy: SchemaFilteringStrategy): boolean;
61
+ /**
62
+ * Gets statistics about what would be filtered from a set of schemas.
63
+ */
64
+ getFilteringStats(schemas: {
65
+ id: string;
66
+ schema: JSONSchema7;
67
+ }[], strategy: SchemaFilteringStrategy): {
68
+ total: number;
69
+ filtered: number;
70
+ remaining: number;
71
+ filteredSchemas: {
72
+ id: string;
73
+ reason: string;
74
+ }[];
75
+ };
76
+ /**
77
+ * Creates a report showing what would be filtered from a schema collection.
78
+ */
79
+ createFilteringReport(schemas: {
80
+ id: string;
81
+ schema: JSONSchema7;
82
+ }[], strategy: SchemaFilteringStrategy): string;
83
+ };
84
+ //# sourceMappingURL=FilteringJsonSchemaImporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilteringJsonSchemaImporter.d.ts","sourceRoot":"","sources":["../../../../src/modeling/importers/FilteringJsonSchemaImporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EACL,uBAAuB,EACvB,KAAK,sBAAsB,EAC3B,oBAAoB,EACrB,MAAM,8BAA8B,CAAA;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAIlD;;;;GAIG;AACH,qBAAa,2BAA4B,SAAQ,kBAAkB;IACjE,OAAO,CAAC,iBAAiB,CAAyB;gBAEtC,MAAM,EAAE,UAAU,EAAE,gBAAgB,GAAE,sBAA2B;IAK7E;;OAEG;IACH,MAAM,CAAC,YAAY,CACjB,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,MAAM,OAAO,oBAAoB,GAC9C,2BAA2B;IAO9B;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,2BAA2B;IAWtE;;;OAGG;IACH,MAAM,CAAC,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,2BAA2B;IAkB3E;;OAEG;IACY,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAa9F;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAgCxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAsDxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAW7B;;OAEG;IACH,OAAO,CAAC,2BAA2B;CAkCpC;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB;IAC/B;;OAEG;4BACqB,WAAW,YAAY,uBAAuB,GAAG,OAAO;IAIhF;;OAEG;+BAEQ;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,EAAE,YACpC,uBAAuB,GAChC;QACD,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE,MAAM,CAAA;QACjB,eAAe,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAClD;IAoBD;;OAEG;mCAC4B;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE,EAAE,YAAY,uBAAuB,GAAG,MAAM;CAmBjH,CAAA"}
@@ -0,0 +1,254 @@
1
+ import { JsonSchemaImporter } from './JsonSchemaImporter.js';
2
+ import { SchemaFilteringStrategy, FILTERING_STRATEGIES, } from './SchemaFilteringStrategy.js';
3
+ /**
4
+ * Extended JsonSchemaImporter that supports filtering out non-structural schemas.
5
+ * This version can eliminate schemas that don't contribute meaningful structure
6
+ * to the data model, such as empty objects or conceptual marker types.
7
+ */
8
+ export class FilteringJsonSchemaImporter extends JsonSchemaImporter {
9
+ filteringStrategy;
10
+ constructor(domain, filteringOptions = {}) {
11
+ super(domain);
12
+ this.filteringStrategy = new SchemaFilteringStrategy(filteringOptions);
13
+ }
14
+ /**
15
+ * Creates an importer with a predefined filtering strategy.
16
+ */
17
+ static withStrategy(domain, strategyName) {
18
+ const strategy = FILTERING_STRATEGIES[strategyName];
19
+ // Access private options through a public method (would need to be added to SchemaFilteringStrategy)
20
+ const options = strategy['options'];
21
+ return new FilteringJsonSchemaImporter(domain, options);
22
+ }
23
+ /**
24
+ * Creates an importer optimized for API development.
25
+ * Excludes schemas that don't contribute to API structure.
26
+ */
27
+ static forApiModeling(domain) {
28
+ return new FilteringJsonSchemaImporter(domain, {
29
+ excludeEmptyObjects: true,
30
+ excludeConceptualMarkers: true,
31
+ excludePatterns: [
32
+ /.*Enumeration$/, // Exclude *Enumeration schemas
33
+ /.*Type$/, // Exclude conceptual *Type schemas that are just markers
34
+ ],
35
+ });
36
+ }
37
+ /**
38
+ * Creates an importer optimized for database schema generation.
39
+ * Very strict filtering - only includes schemas with concrete properties.
40
+ */
41
+ static forDatabaseModeling(domain) {
42
+ return new FilteringJsonSchemaImporter(domain, {
43
+ excludeEmptyObjects: true,
44
+ excludeConceptualMarkers: true,
45
+ customExclusionFilter: (schema) => {
46
+ // For database modeling, exclude anything that doesn't have properties or clear structure
47
+ return (schema.type === 'object' &&
48
+ !schema.properties &&
49
+ !schema.additionalProperties &&
50
+ !schema.allOf?.some((subSchema) => typeof subSchema === 'object' && 'properties' in subSchema && subSchema.properties));
51
+ },
52
+ });
53
+ }
54
+ /**
55
+ * Override the base import method to apply filtering.
56
+ */
57
+ async import(schemas, modelName) {
58
+ // Apply pre-filtering to the schemas before import
59
+ const filteredSchemas = this.preFilterSchemas(schemas);
60
+ // Get the raw import result with filtered schemas
61
+ const rawResult = await super.import(filteredSchemas.schemas, modelName);
62
+ // Apply post-filtering to clean up any remaining issues
63
+ const finalReport = this.postFilterReport(rawResult, filteredSchemas.messages);
64
+ return finalReport;
65
+ }
66
+ /**
67
+ * Pre-filters schemas before they are processed by the base importer.
68
+ */
69
+ preFilterSchemas(schemas) {
70
+ const filteredSchemas = [];
71
+ const messages = [];
72
+ for (const schema of schemas) {
73
+ const schemaId = schema.contents.$id || schema.path;
74
+ if (this.filteringStrategy.shouldExcludeSchema(schema.contents, schemaId)) {
75
+ const reason = this.filteringStrategy.getExclusionReason(schema.contents, schemaId);
76
+ messages.push({
77
+ level: 'info',
78
+ message: `Pre-filtered schema '${schemaId}': ${reason}`,
79
+ location: schema.path,
80
+ });
81
+ }
82
+ else {
83
+ filteredSchemas.push(schema);
84
+ }
85
+ }
86
+ if (messages.length > 0) {
87
+ messages.push({
88
+ level: 'info',
89
+ message: `Pre-filtering removed ${messages.length} non-structural schema(s)`,
90
+ });
91
+ }
92
+ return { schemas: filteredSchemas, messages };
93
+ }
94
+ /**
95
+ * Post-processes the import report to clean up any remaining filtered entities.
96
+ */
97
+ postFilterReport(report, preFilterMessages) {
98
+ const { model, messages } = report;
99
+ const allMessages = [...preFilterMessages, ...messages];
100
+ let removedCount = 0;
101
+ // Get entities as array for easier processing
102
+ const entities = Array.from(model.listEntities());
103
+ const entitiesToRemove = [];
104
+ // Check each entity to see if it should be filtered out
105
+ for (const entity of entities) {
106
+ const shouldFilter = this.shouldFilterEntity(entity);
107
+ if (shouldFilter) {
108
+ entitiesToRemove.push(entity.key);
109
+ const reason = this.getEntityFilterReason(entity);
110
+ allMessages.push({
111
+ level: 'info',
112
+ message: `Post-filtered entity '${entity.info.name}': ${reason}`,
113
+ location: entity.key,
114
+ });
115
+ removedCount++;
116
+ }
117
+ }
118
+ // Remove the filtered entities
119
+ for (const entityKey of entitiesToRemove) {
120
+ try {
121
+ model.removeEntity(entityKey);
122
+ }
123
+ catch (error) {
124
+ allMessages.push({
125
+ level: 'warning',
126
+ message: `Failed to remove entity '${entityKey}': ${error}`,
127
+ location: entityKey,
128
+ });
129
+ }
130
+ }
131
+ // Clean up orphaned associations
132
+ this.cleanupOrphanedAssociations(entities, entitiesToRemove, allMessages);
133
+ if (removedCount > 0) {
134
+ allMessages.push({
135
+ level: 'info',
136
+ message: `Post-filtering removed ${removedCount} additional non-structural entity/entities`,
137
+ });
138
+ }
139
+ return {
140
+ model,
141
+ messages: allMessages,
142
+ };
143
+ }
144
+ /**
145
+ * Determines if an entity should be filtered out based on its characteristics.
146
+ */
147
+ shouldFilterEntity(entity) {
148
+ // Check if entity has no properties and no meaningful associations
149
+ const hasProperties = Array.from(entity.listProperties()).length > 0;
150
+ const hasAssociations = Array.from(entity.listAssociations()).length > 0;
151
+ // If it has neither properties nor associations, it's likely a conceptual marker
152
+ if (!hasProperties && !hasAssociations) {
153
+ return this.filteringStrategy.shouldExcludeSchema({
154
+ type: 'object',
155
+ title: entity.info.name,
156
+ description: entity.info.description,
157
+ }, entity.info.name);
158
+ }
159
+ return false;
160
+ }
161
+ /**
162
+ * Gets a human-readable reason for filtering an entity.
163
+ */
164
+ getEntityFilterReason(entity) {
165
+ const hasProperties = Array.from(entity.listProperties()).length > 0;
166
+ const hasAssociations = Array.from(entity.listAssociations()).length > 0;
167
+ if (!hasProperties && !hasAssociations) {
168
+ return 'Entity has no properties or associations (likely a conceptual marker)';
169
+ }
170
+ return 'Entity matches exclusion pattern';
171
+ }
172
+ /**
173
+ * Removes associations that reference entities that were filtered out.
174
+ */
175
+ cleanupOrphanedAssociations(entities, removedEntityKeys, messages) {
176
+ for (const entity of entities) {
177
+ const associationsToRemove = [];
178
+ for (const association of entity.listAssociations()) {
179
+ const hasOrphanedTargets = association.targets?.some((target) => removedEntityKeys.includes(target.key));
180
+ if (hasOrphanedTargets) {
181
+ associationsToRemove.push(association.key);
182
+ messages.push({
183
+ level: 'info',
184
+ message: `Removed association '${association.info.name}' from '${entity.info.name}' due to filtered target entity`,
185
+ location: `${entity.key}.${association.key}`,
186
+ });
187
+ }
188
+ }
189
+ for (const associationKey of associationsToRemove) {
190
+ try {
191
+ entity.removeAssociation(associationKey);
192
+ }
193
+ catch (error) {
194
+ messages.push({
195
+ level: 'warning',
196
+ message: `Failed to remove association '${associationKey}' from '${entity.info.name}': ${error}`,
197
+ location: `${entity.key}.${associationKey}`,
198
+ });
199
+ }
200
+ }
201
+ }
202
+ }
203
+ }
204
+ /**
205
+ * Utility functions for working with filtered imports.
206
+ */
207
+ export const SchemaFilteringUtils = {
208
+ /**
209
+ * Analyzes a JSON schema to determine if it would be filtered by the given strategy.
210
+ */
211
+ wouldBeFiltered(schema, strategy) {
212
+ return strategy.shouldExcludeSchema(schema);
213
+ },
214
+ /**
215
+ * Gets statistics about what would be filtered from a set of schemas.
216
+ */
217
+ getFilteringStats(schemas, strategy) {
218
+ const filteredSchemas = [];
219
+ for (const { id, schema } of schemas) {
220
+ if (strategy.shouldExcludeSchema(schema, id)) {
221
+ filteredSchemas.push({
222
+ id,
223
+ reason: strategy.getExclusionReason(schema, id),
224
+ });
225
+ }
226
+ }
227
+ return {
228
+ total: schemas.length,
229
+ filtered: filteredSchemas.length,
230
+ remaining: schemas.length - filteredSchemas.length,
231
+ filteredSchemas,
232
+ };
233
+ },
234
+ /**
235
+ * Creates a report showing what would be filtered from a schema collection.
236
+ */
237
+ createFilteringReport(schemas, strategy) {
238
+ const stats = this.getFilteringStats(schemas, strategy);
239
+ let report = `Schema Filtering Report\n`;
240
+ report += `======================\n\n`;
241
+ report += `Total schemas: ${stats.total}\n`;
242
+ report += `Would be filtered: ${stats.filtered}\n`;
243
+ report += `Would remain: ${stats.remaining}\n\n`;
244
+ if (stats.filteredSchemas.length > 0) {
245
+ report += `Schemas that would be filtered:\n`;
246
+ report += `-------------------------------\n`;
247
+ for (const { id, reason } of stats.filteredSchemas) {
248
+ report += `• ${id}: ${reason}\n`;
249
+ }
250
+ }
251
+ return report;
252
+ },
253
+ };
254
+ //# sourceMappingURL=FilteringJsonSchemaImporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FilteringJsonSchemaImporter.js","sourceRoot":"","sources":["../../../../src/modeling/importers/FilteringJsonSchemaImporter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JSONSchema7 } from 'json-schema'\nimport type { JsonImportReport, InMemorySchema } from './JsonSchemaImporter.js'\nimport { JsonSchemaImporter } from './JsonSchemaImporter.js'\nimport {\n SchemaFilteringStrategy,\n type SchemaFilteringOptions,\n FILTERING_STRATEGIES,\n} from './SchemaFilteringStrategy.js'\nimport type { DataDomain } from '../DataDomain.js'\nimport type { DomainEntity } from '../DomainEntity.js'\nimport type { ImportMessage } from './JsonSchemaImporter.js'\n\n/**\n * Extended JsonSchemaImporter that supports filtering out non-structural schemas.\n * This version can eliminate schemas that don't contribute meaningful structure\n * to the data model, such as empty objects or conceptual marker types.\n */\nexport class FilteringJsonSchemaImporter extends JsonSchemaImporter {\n private filteringStrategy: SchemaFilteringStrategy\n\n constructor(domain: DataDomain, filteringOptions: SchemaFilteringOptions = {}) {\n super(domain)\n this.filteringStrategy = new SchemaFilteringStrategy(filteringOptions)\n }\n\n /**\n * Creates an importer with a predefined filtering strategy.\n */\n static withStrategy(\n domain: DataDomain,\n strategyName: keyof typeof FILTERING_STRATEGIES\n ): FilteringJsonSchemaImporter {\n const strategy = FILTERING_STRATEGIES[strategyName]\n // Access private options through a public method (would need to be added to SchemaFilteringStrategy)\n const options = strategy['options'] as SchemaFilteringOptions\n return new FilteringJsonSchemaImporter(domain, options)\n }\n\n /**\n * Creates an importer optimized for API development.\n * Excludes schemas that don't contribute to API structure.\n */\n static forApiModeling(domain: DataDomain): FilteringJsonSchemaImporter {\n return new FilteringJsonSchemaImporter(domain, {\n excludeEmptyObjects: true,\n excludeConceptualMarkers: true,\n excludePatterns: [\n /.*Enumeration$/, // Exclude *Enumeration schemas\n /.*Type$/, // Exclude conceptual *Type schemas that are just markers\n ],\n })\n }\n\n /**\n * Creates an importer optimized for database schema generation.\n * Very strict filtering - only includes schemas with concrete properties.\n */\n static forDatabaseModeling(domain: DataDomain): FilteringJsonSchemaImporter {\n return new FilteringJsonSchemaImporter(domain, {\n excludeEmptyObjects: true,\n excludeConceptualMarkers: true,\n customExclusionFilter: (schema: JSONSchema7) => {\n // For database modeling, exclude anything that doesn't have properties or clear structure\n return (\n schema.type === 'object' &&\n !schema.properties &&\n !schema.additionalProperties &&\n !schema.allOf?.some(\n (subSchema) => typeof subSchema === 'object' && 'properties' in subSchema && subSchema.properties\n )\n )\n },\n })\n }\n\n /**\n * Override the base import method to apply filtering.\n */\n override async import(schemas: InMemorySchema[], modelName: string): Promise<JsonImportReport> {\n // Apply pre-filtering to the schemas before import\n const filteredSchemas = this.preFilterSchemas(schemas)\n\n // Get the raw import result with filtered schemas\n const rawResult = await super.import(filteredSchemas.schemas, modelName)\n\n // Apply post-filtering to clean up any remaining issues\n const finalReport = this.postFilterReport(rawResult, filteredSchemas.messages)\n\n return finalReport\n }\n\n /**\n * Pre-filters schemas before they are processed by the base importer.\n */\n private preFilterSchemas(schemas: InMemorySchema[]): {\n schemas: InMemorySchema[]\n messages: ImportMessage[]\n } {\n const filteredSchemas: InMemorySchema[] = []\n const messages: ImportMessage[] = []\n\n for (const schema of schemas) {\n const schemaId = schema.contents.$id || schema.path\n\n if (this.filteringStrategy.shouldExcludeSchema(schema.contents, schemaId)) {\n const reason = this.filteringStrategy.getExclusionReason(schema.contents, schemaId)\n messages.push({\n level: 'info',\n message: `Pre-filtered schema '${schemaId}': ${reason}`,\n location: schema.path,\n })\n } else {\n filteredSchemas.push(schema)\n }\n }\n\n if (messages.length > 0) {\n messages.push({\n level: 'info',\n message: `Pre-filtering removed ${messages.length} non-structural schema(s)`,\n })\n }\n\n return { schemas: filteredSchemas, messages }\n }\n\n /**\n * Post-processes the import report to clean up any remaining filtered entities.\n */\n private postFilterReport(report: JsonImportReport, preFilterMessages: ImportMessage[]): JsonImportReport {\n const { model, messages } = report\n const allMessages = [...preFilterMessages, ...messages]\n let removedCount = 0\n\n // Get entities as array for easier processing\n const entities = Array.from(model.listEntities())\n const entitiesToRemove: string[] = []\n\n // Check each entity to see if it should be filtered out\n for (const entity of entities) {\n const shouldFilter = this.shouldFilterEntity(entity)\n\n if (shouldFilter) {\n entitiesToRemove.push(entity.key)\n const reason = this.getEntityFilterReason(entity)\n allMessages.push({\n level: 'info',\n message: `Post-filtered entity '${entity.info.name}': ${reason}`,\n location: entity.key,\n })\n removedCount++\n }\n }\n\n // Remove the filtered entities\n for (const entityKey of entitiesToRemove) {\n try {\n model.removeEntity(entityKey)\n } catch (error) {\n allMessages.push({\n level: 'warning',\n message: `Failed to remove entity '${entityKey}': ${error}`,\n location: entityKey,\n })\n }\n }\n\n // Clean up orphaned associations\n this.cleanupOrphanedAssociations(entities, entitiesToRemove, allMessages)\n\n if (removedCount > 0) {\n allMessages.push({\n level: 'info',\n message: `Post-filtering removed ${removedCount} additional non-structural entity/entities`,\n })\n }\n\n return {\n model,\n messages: allMessages,\n }\n }\n\n /**\n * Determines if an entity should be filtered out based on its characteristics.\n */\n private shouldFilterEntity(entity: DomainEntity): boolean {\n // Check if entity has no properties and no meaningful associations\n const hasProperties = Array.from(entity.listProperties()).length > 0\n const hasAssociations = Array.from(entity.listAssociations()).length > 0\n\n // If it has neither properties nor associations, it's likely a conceptual marker\n if (!hasProperties && !hasAssociations) {\n return this.filteringStrategy.shouldExcludeSchema(\n {\n type: 'object',\n title: entity.info.name,\n description: entity.info.description,\n } as JSONSchema7,\n entity.info.name\n )\n }\n\n return false\n }\n\n /**\n * Gets a human-readable reason for filtering an entity.\n */\n private getEntityFilterReason(entity: DomainEntity): string {\n const hasProperties = Array.from(entity.listProperties()).length > 0\n const hasAssociations = Array.from(entity.listAssociations()).length > 0\n\n if (!hasProperties && !hasAssociations) {\n return 'Entity has no properties or associations (likely a conceptual marker)'\n }\n\n return 'Entity matches exclusion pattern'\n }\n\n /**\n * Removes associations that reference entities that were filtered out.\n */\n private cleanupOrphanedAssociations(\n entities: DomainEntity[],\n removedEntityKeys: string[],\n messages: ImportMessage[]\n ): void {\n for (const entity of entities) {\n const associationsToRemove: string[] = []\n\n for (const association of entity.listAssociations()) {\n const hasOrphanedTargets = association.targets?.some((target) => removedEntityKeys.includes(target.key))\n\n if (hasOrphanedTargets) {\n associationsToRemove.push(association.key)\n messages.push({\n level: 'info',\n message: `Removed association '${association.info.name}' from '${entity.info.name}' due to filtered target entity`,\n location: `${entity.key}.${association.key}`,\n })\n }\n }\n\n for (const associationKey of associationsToRemove) {\n try {\n entity.removeAssociation(associationKey)\n } catch (error) {\n messages.push({\n level: 'warning',\n message: `Failed to remove association '${associationKey}' from '${entity.info.name}': ${error}`,\n location: `${entity.key}.${associationKey}`,\n })\n }\n }\n }\n }\n}\n\n/**\n * Utility functions for working with filtered imports.\n */\nexport const SchemaFilteringUtils = {\n /**\n * Analyzes a JSON schema to determine if it would be filtered by the given strategy.\n */\n wouldBeFiltered(schema: JSONSchema7, strategy: SchemaFilteringStrategy): boolean {\n return strategy.shouldExcludeSchema(schema)\n },\n\n /**\n * Gets statistics about what would be filtered from a set of schemas.\n */\n getFilteringStats(\n schemas: { id: string; schema: JSONSchema7 }[],\n strategy: SchemaFilteringStrategy\n ): {\n total: number\n filtered: number\n remaining: number\n filteredSchemas: { id: string; reason: string }[]\n } {\n const filteredSchemas: { id: string; reason: string }[] = []\n\n for (const { id, schema } of schemas) {\n if (strategy.shouldExcludeSchema(schema, id)) {\n filteredSchemas.push({\n id,\n reason: strategy.getExclusionReason(schema, id),\n })\n }\n }\n\n return {\n total: schemas.length,\n filtered: filteredSchemas.length,\n remaining: schemas.length - filteredSchemas.length,\n filteredSchemas,\n }\n },\n\n /**\n * Creates a report showing what would be filtered from a schema collection.\n */\n createFilteringReport(schemas: { id: string; schema: JSONSchema7 }[], strategy: SchemaFilteringStrategy): string {\n const stats = this.getFilteringStats(schemas, strategy)\n\n let report = `Schema Filtering Report\\n`\n report += `======================\\n\\n`\n report += `Total schemas: ${stats.total}\\n`\n report += `Would be filtered: ${stats.filtered}\\n`\n report += `Would remain: ${stats.remaining}\\n\\n`\n\n if (stats.filteredSchemas.length > 0) {\n report += `Schemas that would be filtered:\\n`\n report += `-------------------------------\\n`\n for (const { id, reason } of stats.filteredSchemas) {\n report += `• ${id}: ${reason}\\n`\n }\n }\n\n return report\n },\n}\n"]}
@@ -0,0 +1,72 @@
1
+ import type { JSONSchema7 } from 'json-schema';
2
+ /**
3
+ * Configuration options for schema filtering during import.
4
+ */
5
+ export interface SchemaFilteringOptions {
6
+ /**
7
+ * Whether to exclude schemas that are empty objects with no properties.
8
+ * Default: false
9
+ */
10
+ excludeEmptyObjects?: boolean;
11
+ /**
12
+ * Whether to exclude schemas that only serve as conceptual markers.
13
+ * These are typically schemas with only type: "object" and description
14
+ * but no properties, constraints, or meaningful structure.
15
+ * Default: false
16
+ */
17
+ excludeConceptualMarkers?: boolean;
18
+ /**
19
+ * Custom predicate function to determine if a schema should be excluded.
20
+ * Return true to exclude the schema from import.
21
+ */
22
+ customExclusionFilter?: (schema: JSONSchema7, schemaId?: string) => boolean;
23
+ /**
24
+ * List of schema IDs to explicitly exclude.
25
+ */
26
+ excludeSchemaIds?: string[];
27
+ /**
28
+ * Patterns to match against schema titles or IDs for exclusion.
29
+ */
30
+ excludePatterns?: RegExp[];
31
+ }
32
+ /**
33
+ * Strategy class for determining which schemas should be filtered out during import.
34
+ */
35
+ export declare class SchemaFilteringStrategy {
36
+ private options;
37
+ constructor(options?: SchemaFilteringOptions);
38
+ /**
39
+ * Determines whether a schema should be excluded from import.
40
+ */
41
+ shouldExcludeSchema(schema: JSONSchema7, schemaId?: string): boolean;
42
+ /**
43
+ * Checks if a schema represents an empty object with no meaningful structure.
44
+ */
45
+ private isEmptyObjectSchema;
46
+ /**
47
+ * Checks if a schema is likely a conceptual marker with no structural value.
48
+ */
49
+ private isConceptualMarkerSchema;
50
+ /**
51
+ * Gets a human-readable reason why a schema was excluded.
52
+ */
53
+ getExclusionReason(schema: JSONSchema7, schemaId?: string): string;
54
+ }
55
+ /**
56
+ * Predefined filtering strategies for common use cases.
57
+ */
58
+ export declare const FILTERING_STRATEGIES: {
59
+ /**
60
+ * Strategy for API modeling - excludes schemas that don't contribute to API structure.
61
+ */
62
+ readonly API_MODELING: SchemaFilteringStrategy;
63
+ /**
64
+ * Strategy for database modeling - very strict, only includes schemas with concrete properties.
65
+ */
66
+ readonly DATABASE_MODELING: SchemaFilteringStrategy;
67
+ /**
68
+ * Conservative strategy - only excludes obviously empty schemas.
69
+ */
70
+ readonly CONSERVATIVE: SchemaFilteringStrategy;
71
+ };
72
+ //# sourceMappingURL=SchemaFilteringStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchemaFilteringStrategy.d.ts","sourceRoot":"","sources":["../../../../src/modeling/importers/SchemaFilteringStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAE7B;;;;;OAKG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAElC;;;OAGG;IACH,qBAAqB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,OAAO,CAAA;IAE3E;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAE3B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;GAEG;AACH,qBAAa,uBAAuB;IACtB,OAAO,CAAC,OAAO;gBAAP,OAAO,GAAE,sBAA2B;IAExD;;OAEG;IACH,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAiCpE;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA4BhC;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM;CAenE;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB;IAC/B;;OAEG;;IAUH;;OAEG;;IAiBH;;OAEG;;CAIK,CAAA"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Strategy class for determining which schemas should be filtered out during import.
3
+ */
4
+ export class SchemaFilteringStrategy {
5
+ options;
6
+ constructor(options = {}) {
7
+ this.options = options;
8
+ }
9
+ /**
10
+ * Determines whether a schema should be excluded from import.
11
+ */
12
+ shouldExcludeSchema(schema, schemaId) {
13
+ // Check explicit exclusion list
14
+ if (schemaId && this.options.excludeSchemaIds?.includes(schemaId)) {
15
+ return true;
16
+ }
17
+ // Check pattern exclusions
18
+ if (schemaId && this.options.excludePatterns) {
19
+ for (const pattern of this.options.excludePatterns) {
20
+ if (pattern.test(schemaId) || (schema.title && pattern.test(schema.title))) {
21
+ return true;
22
+ }
23
+ }
24
+ }
25
+ // Check for empty objects
26
+ if (this.options.excludeEmptyObjects && this.isEmptyObjectSchema(schema)) {
27
+ return true;
28
+ }
29
+ // Check for conceptual markers
30
+ if (this.options.excludeConceptualMarkers && this.isConceptualMarkerSchema(schema)) {
31
+ return true;
32
+ }
33
+ // Apply custom filter
34
+ if (this.options.customExclusionFilter?.(schema, schemaId)) {
35
+ return true;
36
+ }
37
+ return false;
38
+ }
39
+ /**
40
+ * Checks if a schema represents an empty object with no meaningful structure.
41
+ */
42
+ isEmptyObjectSchema(schema) {
43
+ return (schema.type === 'object' &&
44
+ (!schema.properties || Object.keys(schema.properties).length === 0) &&
45
+ !schema.additionalProperties &&
46
+ !schema.patternProperties &&
47
+ !schema.allOf &&
48
+ !schema.oneOf &&
49
+ !schema.anyOf &&
50
+ !schema.if &&
51
+ !schema.then &&
52
+ !schema.else &&
53
+ !schema.required?.length &&
54
+ !schema.minProperties &&
55
+ !schema.maxProperties);
56
+ }
57
+ /**
58
+ * Checks if a schema is likely a conceptual marker with no structural value.
59
+ */
60
+ isConceptualMarkerSchema(schema) {
61
+ // Check for schemas that are just empty objects or only have allOf with references
62
+ if (this.isEmptyObjectSchema(schema)) {
63
+ return true;
64
+ }
65
+ // Note: We removed the check for single allOf with $ref as this represents
66
+ // valid schema inheritance/extension patterns (e.g., BlogPosting extending SocialMediaPosting)
67
+ // Such schemas should be included as they define meaningful type hierarchies
68
+ // Check for schemas that only have description and type but no structure
69
+ if (schema.type === 'object' &&
70
+ schema.description &&
71
+ !schema.properties &&
72
+ !schema.additionalProperties &&
73
+ !schema.allOf &&
74
+ !schema.oneOf &&
75
+ !schema.anyOf &&
76
+ Object.keys(schema).filter((key) => !['$schema', '$id', 'title', 'description', 'type'].includes(key)).length ===
77
+ 0) {
78
+ return true;
79
+ }
80
+ return false;
81
+ }
82
+ /**
83
+ * Gets a human-readable reason why a schema was excluded.
84
+ */
85
+ getExclusionReason(schema, schemaId) {
86
+ if (schemaId && this.options.excludeSchemaIds?.includes(schemaId)) {
87
+ return `Schema ID '${schemaId}' is in the exclusion list`;
88
+ }
89
+ if (this.isEmptyObjectSchema(schema)) {
90
+ return 'Schema is an empty object with no structural definition';
91
+ }
92
+ if (this.isConceptualMarkerSchema(schema)) {
93
+ return 'Schema appears to be a conceptual marker with no concrete structure';
94
+ }
95
+ return 'Schema excluded by custom filter';
96
+ }
97
+ }
98
+ /**
99
+ * Predefined filtering strategies for common use cases.
100
+ */
101
+ export const FILTERING_STRATEGIES = {
102
+ /**
103
+ * Strategy for API modeling - excludes schemas that don't contribute to API structure.
104
+ */
105
+ API_MODELING: new SchemaFilteringStrategy({
106
+ excludeEmptyObjects: true,
107
+ excludeConceptualMarkers: true,
108
+ excludePatterns: [
109
+ /.*Enumeration$/, // Exclude *Enumeration schemas
110
+ /.*Type$/, // Exclude conceptual *Type schemas that are just markers
111
+ ],
112
+ }),
113
+ /**
114
+ * Strategy for database modeling - very strict, only includes schemas with concrete properties.
115
+ */
116
+ DATABASE_MODELING: new SchemaFilteringStrategy({
117
+ excludeEmptyObjects: true,
118
+ excludeConceptualMarkers: true,
119
+ customExclusionFilter: (schema) => {
120
+ // For database modeling, exclude anything that doesn't have properties or clear structure
121
+ return (schema.type === 'object' &&
122
+ !schema.properties &&
123
+ !schema.additionalProperties &&
124
+ !schema.allOf?.some((subSchema) => typeof subSchema === 'object' && 'properties' in subSchema && subSchema.properties));
125
+ },
126
+ }),
127
+ /**
128
+ * Conservative strategy - only excludes obviously empty schemas.
129
+ */
130
+ CONSERVATIVE: new SchemaFilteringStrategy({
131
+ excludeEmptyObjects: true,
132
+ }),
133
+ };
134
+ //# sourceMappingURL=SchemaFilteringStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SchemaFilteringStrategy.js","sourceRoot":"","sources":["../../../../src/modeling/importers/SchemaFilteringStrategy.ts"],"names":[],"mappings":"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","sourcesContent":["import type { JSONSchema7 } from 'json-schema'\n\n/**\n * Configuration options for schema filtering during import.\n */\nexport interface SchemaFilteringOptions {\n /**\n * Whether to exclude schemas that are empty objects with no properties.\n * Default: false\n */\n excludeEmptyObjects?: boolean\n\n /**\n * Whether to exclude schemas that only serve as conceptual markers.\n * These are typically schemas with only type: \"object\" and description\n * but no properties, constraints, or meaningful structure.\n * Default: false\n */\n excludeConceptualMarkers?: boolean\n\n /**\n * Custom predicate function to determine if a schema should be excluded.\n * Return true to exclude the schema from import.\n */\n customExclusionFilter?: (schema: JSONSchema7, schemaId?: string) => boolean\n\n /**\n * List of schema IDs to explicitly exclude.\n */\n excludeSchemaIds?: string[]\n\n /**\n * Patterns to match against schema titles or IDs for exclusion.\n */\n excludePatterns?: RegExp[]\n}\n\n/**\n * Strategy class for determining which schemas should be filtered out during import.\n */\nexport class SchemaFilteringStrategy {\n constructor(private options: SchemaFilteringOptions = {}) {}\n\n /**\n * Determines whether a schema should be excluded from import.\n */\n shouldExcludeSchema(schema: JSONSchema7, schemaId?: string): boolean {\n // Check explicit exclusion list\n if (schemaId && this.options.excludeSchemaIds?.includes(schemaId)) {\n return true\n }\n\n // Check pattern exclusions\n if (schemaId && this.options.excludePatterns) {\n for (const pattern of this.options.excludePatterns) {\n if (pattern.test(schemaId) || (schema.title && pattern.test(schema.title))) {\n return true\n }\n }\n }\n\n // Check for empty objects\n if (this.options.excludeEmptyObjects && this.isEmptyObjectSchema(schema)) {\n return true\n }\n\n // Check for conceptual markers\n if (this.options.excludeConceptualMarkers && this.isConceptualMarkerSchema(schema)) {\n return true\n }\n\n // Apply custom filter\n if (this.options.customExclusionFilter?.(schema, schemaId)) {\n return true\n }\n\n return false\n }\n\n /**\n * Checks if a schema represents an empty object with no meaningful structure.\n */\n private isEmptyObjectSchema(schema: JSONSchema7): boolean {\n return (\n schema.type === 'object' &&\n (!schema.properties || Object.keys(schema.properties).length === 0) &&\n !schema.additionalProperties &&\n !schema.patternProperties &&\n !schema.allOf &&\n !schema.oneOf &&\n !schema.anyOf &&\n !schema.if &&\n !schema.then &&\n !schema.else &&\n !schema.required?.length &&\n !schema.minProperties &&\n !schema.maxProperties\n )\n }\n\n /**\n * Checks if a schema is likely a conceptual marker with no structural value.\n */\n private isConceptualMarkerSchema(schema: JSONSchema7): boolean {\n // Check for schemas that are just empty objects or only have allOf with references\n if (this.isEmptyObjectSchema(schema)) {\n return true\n }\n\n // Note: We removed the check for single allOf with $ref as this represents\n // valid schema inheritance/extension patterns (e.g., BlogPosting extending SocialMediaPosting)\n // Such schemas should be included as they define meaningful type hierarchies\n\n // Check for schemas that only have description and type but no structure\n if (\n schema.type === 'object' &&\n schema.description &&\n !schema.properties &&\n !schema.additionalProperties &&\n !schema.allOf &&\n !schema.oneOf &&\n !schema.anyOf &&\n Object.keys(schema).filter((key) => !['$schema', '$id', 'title', 'description', 'type'].includes(key)).length ===\n 0\n ) {\n return true\n }\n\n return false\n }\n\n /**\n * Gets a human-readable reason why a schema was excluded.\n */\n getExclusionReason(schema: JSONSchema7, schemaId?: string): string {\n if (schemaId && this.options.excludeSchemaIds?.includes(schemaId)) {\n return `Schema ID '${schemaId}' is in the exclusion list`\n }\n\n if (this.isEmptyObjectSchema(schema)) {\n return 'Schema is an empty object with no structural definition'\n }\n\n if (this.isConceptualMarkerSchema(schema)) {\n return 'Schema appears to be a conceptual marker with no concrete structure'\n }\n\n return 'Schema excluded by custom filter'\n }\n}\n\n/**\n * Predefined filtering strategies for common use cases.\n */\nexport const FILTERING_STRATEGIES = {\n /**\n * Strategy for API modeling - excludes schemas that don't contribute to API structure.\n */\n API_MODELING: new SchemaFilteringStrategy({\n excludeEmptyObjects: true,\n excludeConceptualMarkers: true,\n excludePatterns: [\n /.*Enumeration$/, // Exclude *Enumeration schemas\n /.*Type$/, // Exclude conceptual *Type schemas that are just markers\n ],\n }),\n\n /**\n * Strategy for database modeling - very strict, only includes schemas with concrete properties.\n */\n DATABASE_MODELING: new SchemaFilteringStrategy({\n excludeEmptyObjects: true,\n excludeConceptualMarkers: true,\n customExclusionFilter: (schema: JSONSchema7) => {\n // For database modeling, exclude anything that doesn't have properties or clear structure\n return (\n schema.type === 'object' &&\n !schema.properties &&\n !schema.additionalProperties &&\n !schema.allOf?.some(\n (subSchema) => typeof subSchema === 'object' && 'properties' in subSchema && subSchema.properties\n )\n )\n },\n }),\n\n /**\n * Conservative strategy - only excludes obviously empty schemas.\n */\n CONSERVATIVE: new SchemaFilteringStrategy({\n excludeEmptyObjects: true,\n }),\n} as const\n"]}