@api-client/core 0.18.6 → 0.18.8

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.
@@ -1,8 +1,35 @@
1
- import { type CSVOptions, type ParseResult } from '@pawel-up/csv';
1
+ import { type CSVOptions, type ParseResult as ParseResult_ } from '@pawel-up/csv';
2
2
  import type { DataDomain } from '../DataDomain.js';
3
3
  import type { DomainEntity } from '../DomainEntity.js';
4
4
  import type { DomainModel } from '../DomainModel.js';
5
- export type { CSVOptions, ParseResult };
5
+ interface ParseResult extends ParseResult_ {
6
+ /**
7
+ * The file name of the CSV that was parsed.
8
+ * If the CSV is provided as a string, it will be named `inline_csv_0`, `inline_csv_1`, etc.
9
+ */
10
+ file: string;
11
+ }
12
+ interface ImportResult {
13
+ /**
14
+ * The DomainEntity created from the CSV data.
15
+ */
16
+ entity: DomainEntity;
17
+ /**
18
+ * The DomainModel that contains the imported entity.
19
+ */
20
+ model: DomainModel;
21
+ }
22
+ interface ImportManyResult {
23
+ /**
24
+ * An array of DomainEntity instances created from the CSV data.
25
+ */
26
+ entities: DomainEntity[];
27
+ /**
28
+ * The DomainModel that contains all imported entities.
29
+ */
30
+ model: DomainModel;
31
+ }
32
+ export type { CSVOptions, ParseResult, ImportResult, ImportManyResult };
6
33
  /**
7
34
  * Imports CSV data into a DataDomain.
8
35
  *
@@ -25,6 +52,7 @@ export declare class CsvImporter {
25
52
  * @returns A promise that resolves with the parsed result.
26
53
  */
27
54
  parse(csv: File | string): Promise<ParseResult>;
55
+ private removeExtension;
28
56
  /**
29
57
  * Imports the parsed CSV data structure into the domain as a new model and entity.
30
58
  * It creates a `DomainEntity` where each column from the CSV is represented as a `DomainProperty`.
@@ -33,9 +61,15 @@ export declare class CsvImporter {
33
61
  * @param modelName The name to be used for the created `DomainModel` and `DomainEntity`.
34
62
  * @returns A promise that resolves when the import is complete.
35
63
  */
36
- import(data: ParseResult, modelName: string): Promise<{
37
- entity: DomainEntity;
38
- model: DomainModel;
39
- }>;
64
+ import(data: ParseResult, modelName: string): Promise<ImportResult>;
65
+ /**
66
+ * Imports multiple parsed CSV data structures into the same data model.
67
+ * Creates a single `DomainModel` with multiple `DomainEntity` instances, one for each CSV data structure.
68
+ * Each entity represents the structure of its corresponding CSV file.
69
+ * @param data Array of objects containing parsed CSV data and entity names.
70
+ * @param modelName The name to be used for the created `DomainModel`.
71
+ * @returns A promise that resolves with the created model and all entities.
72
+ */
73
+ importMany(data: ParseResult[], modelName: string): Promise<ImportManyResult>;
40
74
  }
41
75
  //# sourceMappingURL=CsvImporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CsvImporter.d.ts","sourceRoot":"","sources":["../../../../src/modeling/importers/CsvImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAa,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AAC5E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,CAAA;AAEvC;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAAY;IAE1B;;;;OAIG;gBACS,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,UAAU;IAKpD;;;;;OAKG;IACI,KAAK,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAItD;;;;;;;OAOG;IACU,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,CAAC;CA2CjH"}
1
+ {"version":3,"file":"CsvImporter.d.ts","sourceRoot":"","sources":["../../../../src/modeling/importers/CsvImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,UAAU,EAAa,KAAK,WAAW,IAAI,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAGlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAEpD,UAAU,WAAY,SAAQ,YAAY;IACxC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;CACb;AAID,UAAU,YAAY;IACpB;;OAEG;IACH,MAAM,EAAE,YAAY,CAAA;IACpB;;OAEG;IACH,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,UAAU,gBAAgB;IACxB;;OAEG;IACH,QAAQ,EAAE,YAAY,EAAE,CAAA;IACxB;;OAEG;IACH,KAAK,EAAE,WAAW,CAAA;CACnB;AAED,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,CAAA;AAEvE;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,MAAM,CAAY;IAE1B;;;;OAIG;gBACS,MAAM,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,UAAU;IAKpD;;;;;OAKG;IACU,KAAK,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ5D,OAAO,CAAC,eAAe;IAOvB;;;;;;;OAOG;IACU,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA6ChF;;;;;;;OAOG;IACU,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAyD3F"}
@@ -1,5 +1,6 @@
1
1
  import { CSVParser } from '@pawel-up/csv';
2
2
  import { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js';
3
+ let increment = 0;
3
4
  /**
4
5
  * Imports CSV data into a DataDomain.
5
6
  *
@@ -24,8 +25,18 @@ export class CsvImporter {
24
25
  * @param csv The CSV content to parse, as a File object or a string.
25
26
  * @returns A promise that resolves with the parsed result.
26
27
  */
27
- parse(csv) {
28
- return this.parser.parse(csv);
28
+ async parse(csv) {
29
+ const result = await this.parser.parse(csv);
30
+ return {
31
+ ...result,
32
+ file: typeof csv === 'string' ? 'inline_csv_' + increment++ : csv.name,
33
+ };
34
+ }
35
+ removeExtension(name) {
36
+ if (name.endsWith('.csv')) {
37
+ name = name.slice(0, -4); // Remove .csv extension if present
38
+ }
39
+ return name;
29
40
  }
30
41
  /**
31
42
  * Imports the parsed CSV data structure into the domain as a new model and entity.
@@ -36,6 +47,7 @@ export class CsvImporter {
36
47
  * @returns A promise that resolves when the import is complete.
37
48
  */
38
49
  async import(data, modelName) {
50
+ modelName = this.removeExtension(modelName);
39
51
  const name = toDatabaseTableName(modelName, 'imported_cvs_data');
40
52
  const model = this.domain.addModel({ info: { name } });
41
53
  const entity = model.addEntity({ info: { name } });
@@ -78,5 +90,66 @@ export class CsvImporter {
78
90
  }
79
91
  return { entity, model };
80
92
  }
93
+ /**
94
+ * Imports multiple parsed CSV data structures into the same data model.
95
+ * Creates a single `DomainModel` with multiple `DomainEntity` instances, one for each CSV data structure.
96
+ * Each entity represents the structure of its corresponding CSV file.
97
+ * @param data Array of objects containing parsed CSV data and entity names.
98
+ * @param modelName The name to be used for the created `DomainModel`.
99
+ * @returns A promise that resolves with the created model and all entities.
100
+ */
101
+ async importMany(data, modelName) {
102
+ modelName = this.removeExtension(modelName);
103
+ const name = toDatabaseTableName(modelName, 'imported_cvs_data');
104
+ const model = this.domain.addModel({ info: { name } });
105
+ const sanitizedModelName = sanitizeInput(modelName);
106
+ if (name !== sanitizedModelName) {
107
+ model.info.displayName = sanitizedModelName;
108
+ }
109
+ const entities = [];
110
+ for (const { format, values, file } of data) {
111
+ const cleanFile = this.removeExtension(file);
112
+ const entityDbName = toDatabaseTableName(cleanFile, `entity_${entities.length}`);
113
+ const entity = model.addEntity({ info: { name: entityDbName } });
114
+ const sanitizedEntityName = sanitizeInput(cleanFile);
115
+ if (entityDbName !== sanitizedEntityName) {
116
+ entity.info.displayName = sanitizedEntityName;
117
+ }
118
+ const exampleRow = values[0];
119
+ for (const row of format) {
120
+ const { index, name, type, format } = row;
121
+ const columnName = toDatabaseColumnName(name, `column_${index}`);
122
+ const schema = {
123
+ info: { name: columnName },
124
+ type,
125
+ };
126
+ if (format) {
127
+ schema.bindings = [
128
+ {
129
+ type: 'web',
130
+ schema: {
131
+ format: format === 'integer' ? 'int64' : 'double',
132
+ },
133
+ },
134
+ ];
135
+ }
136
+ if (Array.isArray(exampleRow) && exampleRow[index]) {
137
+ const value = exampleRow[index];
138
+ if (value !== undefined && value !== null) {
139
+ schema.schema = {
140
+ examples: [sanitizeInput(String(value))],
141
+ };
142
+ }
143
+ }
144
+ const prop = entity.addProperty(schema);
145
+ const sn = sanitizeInput(name);
146
+ if (sn !== columnName) {
147
+ prop.info.displayName = sn;
148
+ }
149
+ }
150
+ entities.push(entity);
151
+ }
152
+ return { entities, model };
153
+ }
81
154
  }
82
155
  //# sourceMappingURL=CsvImporter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CsvImporter.js","sourceRoot":"","sources":["../../../../src/modeling/importers/CsvImporter.ts"],"names":[],"mappings":"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","sourcesContent":["import { type CSVOptions, CSVParser, type ParseResult } from '@pawel-up/csv'\nimport type { DataDomain } from '../DataDomain.js'\nimport { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js'\nimport type { DomainPropertySchema } from '../DomainProperty.js'\nimport type { DomainEntity } from '../DomainEntity.js'\nimport type { DomainModel } from '../DomainModel.js'\n\nexport type { CSVOptions, ParseResult }\n\n/**\n * Imports CSV data into a DataDomain.\n *\n * This class parses CSV files and translates the column definitions into DomainProperty instances\n * within a specified DomainModel and DomainEntity.\n */\nexport class CsvImporter {\n private parser: CSVParser\n private domain: DataDomain\n\n /**\n * Creates an instance of CsvImporter.\n * @param domain The DataDomain to which the imported data will be added.\n * @param options Optional CSV parsing options.\n */\n constructor(domain: DataDomain, options?: CSVOptions) {\n this.parser = new CSVParser(options)\n this.domain = domain\n }\n\n /**\n * Parses a CSV file or string to extract its structure and data.\n * This is a wrapper around the underlying CSV parser.\n * @param csv The CSV content to parse, as a File object or a string.\n * @returns A promise that resolves with the parsed result.\n */\n public parse(csv: File | string): Promise<ParseResult> {\n return this.parser.parse(csv)\n }\n\n /**\n * Imports the parsed CSV data structure into the domain as a new model and entity.\n * It creates a `DomainEntity` where each column from the CSV is represented as a `DomainProperty`.\n * The first row of data is used to provide an example value for each property.\n * @param data The result from the `parse` method, containing the CSV structure and values.\n * @param modelName The name to be used for the created `DomainModel` and `DomainEntity`.\n * @returns A promise that resolves when the import is complete.\n */\n public async import(data: ParseResult, modelName: string): Promise<{ entity: DomainEntity; model: DomainModel }> {\n const name = toDatabaseTableName(modelName, 'imported_cvs_data')\n const model = this.domain.addModel({ info: { name } })\n const entity = model.addEntity({ info: { name } })\n const sanitizedInputName = sanitizeInput(modelName)\n if (name !== sanitizedInputName) {\n model.info.displayName = sanitizedInputName\n entity.info.displayName = sanitizedInputName\n }\n for (const row of data.format) {\n const { index, name, type, format } = row\n const columnName = toDatabaseColumnName(name, `column_${index}`)\n const schema: Partial<DomainPropertySchema> = {\n info: { name: columnName },\n type,\n }\n if (format) {\n schema.bindings = [\n {\n type: 'web',\n schema: {\n format: format === 'integer' ? 'int64' : 'double',\n },\n },\n ]\n }\n const exampleRow = data.values[0]\n if (Array.isArray(exampleRow) && exampleRow[index]) {\n const value = exampleRow[index]\n if (value !== undefined && value !== null) {\n schema.schema = {\n examples: [sanitizeInput(String(value))],\n }\n }\n }\n const prop = entity.addProperty(schema)\n const sn = sanitizeInput(name)\n if (sn !== columnName) {\n prop.info.displayName = sn\n }\n }\n return { entity, model }\n }\n}\n"]}
1
+ {"version":3,"file":"CsvImporter.js","sourceRoot":"","sources":["../../../../src/modeling/importers/CsvImporter.ts"],"names":[],"mappings":"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","sourcesContent":["import { type CSVOptions, CSVParser, type ParseResult as ParseResult_ } from '@pawel-up/csv'\nimport type { DataDomain } from '../DataDomain.js'\nimport { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js'\nimport type { DomainPropertySchema } from '../DomainProperty.js'\nimport type { DomainEntity } from '../DomainEntity.js'\nimport type { DomainModel } from '../DomainModel.js'\n\ninterface ParseResult extends ParseResult_ {\n /**\n * The file name of the CSV that was parsed.\n * If the CSV is provided as a string, it will be named `inline_csv_0`, `inline_csv_1`, etc.\n */\n file: string\n}\n\nlet increment = 0\n\ninterface ImportResult {\n /**\n * The DomainEntity created from the CSV data.\n */\n entity: DomainEntity\n /**\n * The DomainModel that contains the imported entity.\n */\n model: DomainModel\n}\n\ninterface ImportManyResult {\n /**\n * An array of DomainEntity instances created from the CSV data.\n */\n entities: DomainEntity[]\n /**\n * The DomainModel that contains all imported entities.\n */\n model: DomainModel\n}\n\nexport type { CSVOptions, ParseResult, ImportResult, ImportManyResult }\n\n/**\n * Imports CSV data into a DataDomain.\n *\n * This class parses CSV files and translates the column definitions into DomainProperty instances\n * within a specified DomainModel and DomainEntity.\n */\nexport class CsvImporter {\n private parser: CSVParser\n private domain: DataDomain\n\n /**\n * Creates an instance of CsvImporter.\n * @param domain The DataDomain to which the imported data will be added.\n * @param options Optional CSV parsing options.\n */\n constructor(domain: DataDomain, options?: CSVOptions) {\n this.parser = new CSVParser(options)\n this.domain = domain\n }\n\n /**\n * Parses a CSV file or string to extract its structure and data.\n * This is a wrapper around the underlying CSV parser.\n * @param csv The CSV content to parse, as a File object or a string.\n * @returns A promise that resolves with the parsed result.\n */\n public async parse(csv: File | string): Promise<ParseResult> {\n const result = await this.parser.parse(csv)\n return {\n ...result,\n file: typeof csv === 'string' ? 'inline_csv_' + increment++ : csv.name,\n }\n }\n\n private removeExtension(name: string): string {\n if (name.endsWith('.csv')) {\n name = name.slice(0, -4) // Remove .csv extension if present\n }\n return name\n }\n\n /**\n * Imports the parsed CSV data structure into the domain as a new model and entity.\n * It creates a `DomainEntity` where each column from the CSV is represented as a `DomainProperty`.\n * The first row of data is used to provide an example value for each property.\n * @param data The result from the `parse` method, containing the CSV structure and values.\n * @param modelName The name to be used for the created `DomainModel` and `DomainEntity`.\n * @returns A promise that resolves when the import is complete.\n */\n public async import(data: ParseResult, modelName: string): Promise<ImportResult> {\n modelName = this.removeExtension(modelName)\n const name = toDatabaseTableName(modelName, 'imported_cvs_data')\n const model = this.domain.addModel({ info: { name } })\n const entity = model.addEntity({ info: { name } })\n const sanitizedInputName = sanitizeInput(modelName)\n if (name !== sanitizedInputName) {\n model.info.displayName = sanitizedInputName\n entity.info.displayName = sanitizedInputName\n }\n for (const row of data.format) {\n const { index, name, type, format } = row\n const columnName = toDatabaseColumnName(name, `column_${index}`)\n const schema: Partial<DomainPropertySchema> = {\n info: { name: columnName },\n type,\n }\n if (format) {\n schema.bindings = [\n {\n type: 'web',\n schema: {\n format: format === 'integer' ? 'int64' : 'double',\n },\n },\n ]\n }\n const exampleRow = data.values[0]\n if (Array.isArray(exampleRow) && exampleRow[index]) {\n const value = exampleRow[index]\n if (value !== undefined && value !== null) {\n schema.schema = {\n examples: [sanitizeInput(String(value))],\n }\n }\n }\n const prop = entity.addProperty(schema)\n const sn = sanitizeInput(name)\n if (sn !== columnName) {\n prop.info.displayName = sn\n }\n }\n return { entity, model }\n }\n\n /**\n * Imports multiple parsed CSV data structures into the same data model.\n * Creates a single `DomainModel` with multiple `DomainEntity` instances, one for each CSV data structure.\n * Each entity represents the structure of its corresponding CSV file.\n * @param data Array of objects containing parsed CSV data and entity names.\n * @param modelName The name to be used for the created `DomainModel`.\n * @returns A promise that resolves with the created model and all entities.\n */\n public async importMany(data: ParseResult[], modelName: string): Promise<ImportManyResult> {\n modelName = this.removeExtension(modelName)\n const name = toDatabaseTableName(modelName, 'imported_cvs_data')\n const model = this.domain.addModel({ info: { name } })\n const sanitizedModelName = sanitizeInput(modelName)\n if (name !== sanitizedModelName) {\n model.info.displayName = sanitizedModelName\n }\n\n const entities: DomainEntity[] = []\n\n for (const { format, values, file } of data) {\n const cleanFile = this.removeExtension(file)\n const entityDbName = toDatabaseTableName(cleanFile, `entity_${entities.length}`)\n const entity = model.addEntity({ info: { name: entityDbName } })\n const sanitizedEntityName = sanitizeInput(cleanFile)\n if (entityDbName !== sanitizedEntityName) {\n entity.info.displayName = sanitizedEntityName\n }\n\n const exampleRow = values[0]\n for (const row of format) {\n const { index, name, type, format } = row\n const columnName = toDatabaseColumnName(name, `column_${index}`)\n const schema: Partial<DomainPropertySchema> = {\n info: { name: columnName },\n type,\n }\n if (format) {\n schema.bindings = [\n {\n type: 'web',\n schema: {\n format: format === 'integer' ? 'int64' : 'double',\n },\n },\n ]\n }\n if (Array.isArray(exampleRow) && exampleRow[index]) {\n const value = exampleRow[index]\n if (value !== undefined && value !== null) {\n schema.schema = {\n examples: [sanitizeInput(String(value))],\n }\n }\n }\n const prop = entity.addProperty(schema)\n const sn = sanitizeInput(name)\n if (sn !== columnName) {\n prop.info.displayName = sn\n }\n }\n entities.push(entity)\n }\n\n return { entities, model }\n }\n}\n"]}
@@ -68,6 +68,10 @@ export declare class JsonSchemaImporter {
68
68
  * Helper for entity creation, can be extended for custom logic.
69
69
  */
70
70
  private createEntity;
71
+ /**
72
+ * Generates a meaningful name for inline entities based on their parent context.
73
+ */
74
+ private generateInlineEntityName;
71
75
  /**
72
76
  * Populates a DomainEntity with its properties, associations, and parent relationships.
73
77
  */
@@ -1 +1 @@
1
- {"version":3,"file":"JsonSchemaImporter.d.ts","sourceRoot":"","sources":["../../../../src/modeling/importers/JsonSchemaImporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA8C,MAAM,aAAa,CAAA;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAQ/C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,GAAG,MAAM,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB;;OAEG;IACH,KAAK,EAAE,WAAW,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,QAAQ,EAAE,WAAW,CAAA;CACtB;AAED;;;;;GAKG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,KAAK,CAAiC;gBAElC,MAAM,EAAE,UAAU;IAI9B;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACH,OAAO,CAAC,MAAM;IAId;;OAEG;IACU,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAqE5F,OAAO,CAAC,MAAM;IAYd;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAuBxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAgDpB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAiD3B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAwEnC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA0D5B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAuE/B,OAAO,CAAC,kBAAkB;CA+F3B"}
1
+ {"version":3,"file":"JsonSchemaImporter.d.ts","sourceRoot":"","sources":["../../../../src/modeling/importers/JsonSchemaImporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAA8C,MAAM,aAAa,CAAA;AAC1F,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAS/C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,GAAG,MAAM,CAAA;IACzB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB;;OAEG;IACH,KAAK,EAAE,WAAW,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAA;IACZ,kDAAkD;IAClD,QAAQ,EAAE,WAAW,CAAA;CACtB;AAED;;;;;GAKG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,KAAK,CAAiC;gBAElC,MAAM,EAAE,UAAU;IAI9B;;OAEG;IACH,OAAO,CAAC,UAAU;IAOlB;;OAEG;IACH,OAAO,CAAC,MAAM;IAId;;OAEG;IACU,MAAM,CAAC,OAAO,EAAE,cAAc,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4F5F,OAAO,CAAC,MAAM;IAYd;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAuBxB;;OAEG;IACH,OAAO,CAAC,YAAY;IA6BpB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAehC;;OAEG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAgDpB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAsF3B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAyEnC;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA0D5B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAuE/B,OAAO,CAAC,kBAAkB;CAgG3B"}
@@ -1,5 +1,6 @@
1
1
  import { DomainProperty } from '../DomainProperty.js';
2
2
  import { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js';
3
+ import { nanoid } from '../../nanoid.js';
3
4
  /**
4
5
  * Imports JSON Schema definitions into a DataDomain.
5
6
  *
@@ -38,31 +39,47 @@ export class JsonSchemaImporter {
38
39
  // Build a flat map of all definitions and $id-indexed schemas
39
40
  const definitionMap = new Map();
40
41
  const idMap = new Map();
42
+ const processedSchemas = new Set(); // Track processed schema objects to avoid duplicates
41
43
  for (const schema of schemas) {
42
44
  // Add $id mapping if present
43
45
  if (schema.contents.$id) {
44
46
  idMap.set(schema.contents.$id, schema.contents);
47
+ // Add the entire schema to the definitions maps as well as they can be referenced by other schemas.
48
+ definitionMap.set(schema.contents.$id, schema.contents);
45
49
  }
46
50
  // Add the schema itself by its path
47
51
  definitionMap.set(schema.path, schema.contents);
48
52
  // Add all definitions inside this schema
49
- const defs = (schema.contents.definitions ||
50
- schema.contents.$defs);
51
- if (defs) {
52
- for (const [defName, defSchema] of Object.entries(defs)) {
53
+ const definitions = schema.contents.definitions;
54
+ const defs = schema.contents.$defs;
55
+ if (definitions) {
56
+ for (const [defName, defSchema] of Object.entries(definitions)) {
53
57
  if (typeof defSchema === 'object') {
54
- // Use a JSON pointer for the key
58
+ // Use a JSON pointer for the key - include both full path and short form
55
59
  definitionMap.set(`${schema.path}#/definitions/${defName}`, defSchema);
56
- // Also allow lookup by just #/definitions/defName for single-file schemas
57
60
  definitionMap.set(`#/definitions/${defName}`, defSchema);
58
61
  }
59
62
  }
60
63
  }
64
+ if (defs) {
65
+ for (const [defName, defSchema] of Object.entries(defs)) {
66
+ if (typeof defSchema === 'object') {
67
+ // Use a JSON pointer for the key - include both full path and short form
68
+ definitionMap.set(`${schema.path}#/$defs/${defName}`, defSchema);
69
+ definitionMap.set(`#/$defs/${defName}`, defSchema);
70
+ }
71
+ }
72
+ }
61
73
  }
62
74
  // == Pass 1: Create all entities ==
63
75
  for (const [key, schema] of definitionMap.entries()) {
76
+ // Skip if this schema object has already been processed
77
+ if (processedSchemas.has(schema)) {
78
+ continue;
79
+ }
64
80
  if (typeof schema === 'object' && schema.type === 'object') {
65
81
  this.createEntity(key, schema, key);
82
+ processedSchemas.add(schema);
66
83
  }
67
84
  else if (this.isEnum(schema)) {
68
85
  this.enums.set(key, schema);
@@ -73,10 +90,15 @@ export class JsonSchemaImporter {
73
90
  }
74
91
  // Also create entities for all $id-indexed schemas if not already present
75
92
  for (const [id, schema] of idMap.entries()) {
93
+ // Skip if this schema object has already been processed
94
+ if (processedSchemas.has(schema)) {
95
+ continue;
96
+ }
76
97
  if (!this.refMap.has(id) && typeof schema === 'object' && schema.type === 'object') {
77
98
  this.createEntity(id, schema, id);
99
+ processedSchemas.add(schema);
78
100
  }
79
- else if (this.isEnum(schema)) {
101
+ else if (this.isEnum(schema) && !this.enums.has(id)) {
80
102
  this.enums.set(id, schema);
81
103
  }
82
104
  else {
@@ -120,10 +142,10 @@ export class JsonSchemaImporter {
120
142
  return definitionMap.get(refPath);
121
143
  if (idMap.has(refPath))
122
144
  return idMap.get(refPath);
123
- // Try to resolve #/definitions/Name from any schema
124
- if (refPath.startsWith('#/definitions/')) {
145
+ // Try to resolve #/definitions/Name or #/$defs/Name from any schema
146
+ if (refPath.startsWith('#/definitions/') || refPath.startsWith('#/$defs/')) {
125
147
  for (const [key, schema] of definitionMap.entries()) {
126
- if (key.endsWith(refPath))
148
+ if (key === refPath)
127
149
  return schema;
128
150
  }
129
151
  }
@@ -140,7 +162,16 @@ export class JsonSchemaImporter {
140
162
  * Helper for entity creation, can be extended for custom logic.
141
163
  */
142
164
  createEntity(name, schema, refPath) {
143
- const fixedName = schema.title || name;
165
+ let fixedName = schema.title || name;
166
+ // Extract just the definition name from JSON pointers (both short and full paths)
167
+ if (name.includes('#/definitions/')) {
168
+ const parts = name.split('#/definitions/');
169
+ fixedName = schema.title || parts[parts.length - 1];
170
+ }
171
+ else if (name.includes('#/$defs/')) {
172
+ const parts = name.split('#/$defs/');
173
+ fixedName = schema.title || parts[parts.length - 1];
174
+ }
144
175
  const cleanName = toDatabaseTableName(fixedName, 'untitled_entity');
145
176
  const entity = this.model.addEntity({
146
177
  info: {
@@ -157,6 +188,21 @@ export class JsonSchemaImporter {
157
188
  this.refMap.set(refPath, entity.key);
158
189
  return entity;
159
190
  }
191
+ /**
192
+ * Generates a meaningful name for inline entities based on their parent context.
193
+ */
194
+ generateInlineEntityName(parentEntityKey, propName, schema) {
195
+ // Try to use the schema title first
196
+ if (schema.title) {
197
+ return toDatabaseTableName(schema.title, 'untitled_entity');
198
+ }
199
+ // Find the parent entity to create a meaningful name
200
+ const parentEntity = this.domain.findEntity(parentEntityKey);
201
+ const parentName = parentEntity?.info.name || 'unknown';
202
+ // Create a name like "User_Address" or "Order_ShippingInfo"
203
+ const combinedName = `${parentName}_${propName}`;
204
+ return toDatabaseTableName(combinedName, 'untitled_entity');
205
+ }
160
206
  /**
161
207
  * Populates a DomainEntity with its properties, associations, and parent relationships.
162
208
  */
@@ -223,7 +269,7 @@ export class JsonSchemaImporter {
223
269
  * Recursively analyzes a schema definition to find all contained primitive types and `$ref`s.
224
270
  * It's used to understand the nature of a property (is it a primitive, an association, or a mix).
225
271
  */
226
- collectTypesAndRefs(schema) {
272
+ collectTypesAndRefs(schema, parentEntityKey, propName) {
227
273
  const collected = { refs: new Set(), types: new Set(), isArray: false };
228
274
  if (typeof schema !== 'object') {
229
275
  return collected;
@@ -239,11 +285,22 @@ export class JsonSchemaImporter {
239
285
  collected.types.add(t);
240
286
  }
241
287
  }
288
+ // Handle inline object types by creating entities immediately
289
+ if (schema.type === 'object' && schema.properties && parentEntityKey && propName) {
290
+ // Create an entity for this inline object immediately
291
+ const inlineEntityName = this.generateInlineEntityName(parentEntityKey, propName, schema);
292
+ const inlineEntity = this.createEntity(inlineEntityName, schema, inlineEntityName);
293
+ // Populate it immediately since we have the schema
294
+ this.populateEntity(inlineEntity, schema);
295
+ // Add a reference to it so it gets treated as an association
296
+ collected.refs.add(inlineEntityName);
297
+ return collected;
298
+ }
242
299
  if (schema.type === 'array') {
243
300
  collected.isArray = true;
244
301
  if (typeof schema.items === 'object') {
245
- // Recurse into items
246
- const itemInfo = this.collectTypesAndRefs(Array.isArray(schema.items) ? schema.items[0] : schema.items);
302
+ // Recurse into items - pass along parent context for inline objects in arrays
303
+ const itemInfo = this.collectTypesAndRefs(Array.isArray(schema.items) ? schema.items[0] : schema.items, parentEntityKey, propName ? `${propName}_item` : undefined);
247
304
  itemInfo.refs.forEach((r) => collected.refs.add(r));
248
305
  itemInfo.types.forEach((t) => collected.types.add(t));
249
306
  }
@@ -252,7 +309,7 @@ export class JsonSchemaImporter {
252
309
  const choices = schema.anyOf || schema.oneOf;
253
310
  if (choices) {
254
311
  for (const choice of choices) {
255
- const choiceInfo = this.collectTypesAndRefs(choice);
312
+ const choiceInfo = this.collectTypesAndRefs(choice, parentEntityKey);
256
313
  choiceInfo.refs.forEach((r) => collected.refs.add(r));
257
314
  choiceInfo.types.forEach((t) => collected.types.add(t));
258
315
  if (choiceInfo.isArray) {
@@ -260,6 +317,19 @@ export class JsonSchemaImporter {
260
317
  }
261
318
  }
262
319
  }
320
+ if (schema.enum) {
321
+ // If the schema has an enum, we treat it as a string type with specific values.
322
+ collected.types.add('string');
323
+ // consider the following schema: `"enum": ["one", "two", "three"]`
324
+ const id = nanoid(8);
325
+ this.enums.set(id, {
326
+ type: 'string',
327
+ oneOf: schema.enum.map((value) => ({
328
+ const: String(value), // Ensure enum values are strings
329
+ })),
330
+ });
331
+ collected.refs.add(id); // Add the enum reference
332
+ }
263
333
  return collected;
264
334
  }
265
335
  /**
@@ -267,7 +337,9 @@ export class JsonSchemaImporter {
267
337
  */
268
338
  createPropertyOrAssociation(entity, propName, propSchema, isRequired) {
269
339
  // Analyze the property schema to understand its composition (primitives, refs, arrays).
270
- const analysis = this.collectTypesAndRefs(propSchema);
340
+ // Pass entity context to collectTypesAndRefs for inline object handling
341
+ const analysis = this.collectTypesAndRefs(propSchema, entity.key, propName);
342
+ // console.log(`Analyzing property '${propName}' in entity '${entity.info.name}':`, analysis, propSchema)
271
343
  // Case 1: If the property has `$ref` to an enum, we treat it as a DomainProperty.
272
344
  if (analysis.refs.size === 1 && this.enums.has([...analysis.refs][0])) {
273
345
  const prop = this.createEnumProperty(propName, propSchema, this.enums.get([...analysis.refs][0]), entity.info.name);
@@ -517,6 +589,7 @@ export class JsonSchemaImporter {
517
589
  }
518
590
  }
519
591
  if (Object.keys(schema).length > 0) {
592
+ // console.log(`Creating enum property '${propName}' with schema:`, schema)
520
593
  prop.schema = schema;
521
594
  }
522
595
  return prop;