@api-client/core 0.18.3 → 0.18.5

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@api-client/core",
3
3
  "description": "The API Client's core client library. Works in NodeJS and in a ES enabled browser.",
4
- "version": "0.18.3",
4
+ "version": "0.18.5",
5
5
  "license": "Apache-2.0",
6
6
  "exports": {
7
7
  "./browser.js": {
@@ -87,12 +87,14 @@
87
87
  "@api-client/json": "^0.2.0",
88
88
  "@esm-bundle/chai": "^4.3.4-fix.0",
89
89
  "@metrichor/jmespath": "^0.3.1",
90
+ "@pawel-up/csv": "^0.2.0",
90
91
  "@pawel-up/data-mock": "^0.4.0",
91
92
  "@pawel-up/jexl": "^4.0.1",
92
93
  "@xmldom/xmldom": "^0.9.7",
93
94
  "amf-json-ld-lib": "^0.0.15",
94
95
  "chalk": "^5.4.1",
95
96
  "console-table-printer": "^2.11.2",
97
+ "isomorphic-dompurify": "^2.26.0",
96
98
  "nanoid": "^5.1.5",
97
99
  "ws": "^8.12.0",
98
100
  "xpath": "^0.0.34"
@@ -111,6 +113,7 @@
111
113
  "@types/cors": "^2.8.12",
112
114
  "@types/express-ntlm": "^2.3.3",
113
115
  "@types/jsdom": "^21.1.7",
116
+ "@types/json-schema": "^7.0.15",
114
117
  "@types/mocha": "^10.0.10",
115
118
  "@types/node": "^24.0.1",
116
119
  "@types/sinon": "^17.0.1",
@@ -131,11 +134,11 @@
131
134
  "get-port": "^7.0.0",
132
135
  "globals": "^16.0.0",
133
136
  "husky": "^9.0.11",
134
- "jsdom": "^26.0.0",
135
137
  "lint-staged": "^16.0.0",
136
138
  "nock": "^14.0.1",
137
139
  "oauth2-mock-server": "^8.0.0",
138
140
  "prettier": "^3.5.1",
141
+ "schema-org-json-schemas": "^2.1.4",
139
142
  "sinon": "^21.0.0",
140
143
  "ts-lit-plugin": "^2.0.2",
141
144
  "ts-node-maintained": "^10.9.5",
@@ -0,0 +1,48 @@
1
+ import DOMPurify from 'isomorphic-dompurify'
2
+ import { snakeCase } from '@pawel-up/jexl/string.js'
3
+
4
+ export function sanitizeInput(input: string): string {
5
+ return DOMPurify.isSupported ? DOMPurify.sanitize(input) : input
6
+ }
7
+
8
+ /**
9
+ * Converts a string into a sanitized, database column friendly name.
10
+ * - Sanitizes the input using DOMPurify.
11
+ * - Converts to lowercase.
12
+ * - Replaces spaces and multiple underscores with a single underscore.
13
+ * - Removes any characters that are not alphanumeric or underscore.
14
+ *
15
+ * @param inputName The string to format.
16
+ * @returns A database column friendly name.
17
+ */
18
+ export function toDatabaseColumnName(inputName: string, defaultName = 'untitled_column'): string {
19
+ // 1. Sanitize
20
+ let name = sanitizeInput(inputName)
21
+
22
+ // 2. Convert to lowercase
23
+ name = snakeCase(name)
24
+
25
+ // 3. Replace spaces and multiple hyphens/underscores with a single underscore
26
+ name = name.replace(/[\s-]+/g, '_')
27
+
28
+ // 4. Remove any characters that are not alphanumeric or underscore
29
+ name = name.replace(/[^a-z0-9_]/g, '')
30
+
31
+ // 5. Ensure it doesn't start or end with an underscore (optional, but good practice)
32
+ name = name.replace(/^_+|_+$/g, '')
33
+
34
+ return name || defaultName
35
+ }
36
+ /**
37
+ * Converts a string into a sanitized, database table friendly name.
38
+ * - Sanitizes the input using DOMPurify.
39
+ * - Converts to lowercase.
40
+ * - Replaces spaces and multiple underscores with a single underscore.
41
+ * - Removes any characters that are not alphanumeric or underscore.
42
+ *
43
+ * @param inputName The string to format.
44
+ * @returns A database table friendly name.
45
+ */
46
+ export function toDatabaseTableName(inputName: string, defaultName = 'untitled_table'): string {
47
+ return toDatabaseColumnName(inputName, defaultName)
48
+ }
@@ -0,0 +1,91 @@
1
+ import { type CSVOptions, CSVParser, type ParseResult } from '@pawel-up/csv'
2
+ import type { DataDomain } from '../DataDomain.js'
3
+ import { sanitizeInput, toDatabaseColumnName, toDatabaseTableName } from '../helpers/database.js'
4
+ import type { DomainPropertySchema } from '../DomainProperty.js'
5
+ import type { DomainEntity } from '../DomainEntity.js'
6
+ import type { DomainModel } from '../DomainModel.js'
7
+
8
+ export type { CSVOptions, ParseResult }
9
+
10
+ /**
11
+ * Imports CSV data into a DataDomain.
12
+ *
13
+ * This class parses CSV files and translates the column definitions into DomainProperty instances
14
+ * within a specified DomainModel and DomainEntity.
15
+ */
16
+ export class CsvImporter {
17
+ private parser: CSVParser
18
+ private domain: DataDomain
19
+
20
+ /**
21
+ * Creates an instance of CsvImporter.
22
+ * @param domain The DataDomain to which the imported data will be added.
23
+ * @param options Optional CSV parsing options.
24
+ */
25
+ constructor(domain: DataDomain, options?: CSVOptions) {
26
+ this.parser = new CSVParser(options)
27
+ this.domain = domain
28
+ }
29
+
30
+ /**
31
+ * Parses a CSV file or string to extract its structure and data.
32
+ * This is a wrapper around the underlying CSV parser.
33
+ * @param csv The CSV content to parse, as a File object or a string.
34
+ * @returns A promise that resolves with the parsed result.
35
+ */
36
+ public parse(csv: File | string): Promise<ParseResult> {
37
+ return this.parser.parse(csv)
38
+ }
39
+
40
+ /**
41
+ * Imports the parsed CSV data structure into the domain as a new model and entity.
42
+ * It creates a `DomainEntity` where each column from the CSV is represented as a `DomainProperty`.
43
+ * The first row of data is used to provide an example value for each property.
44
+ * @param data The result from the `parse` method, containing the CSV structure and values.
45
+ * @param modelName The name to be used for the created `DomainModel` and `DomainEntity`.
46
+ * @returns A promise that resolves when the import is complete.
47
+ */
48
+ public async import(data: ParseResult, modelName: string): Promise<{ entity: DomainEntity; model: DomainModel }> {
49
+ const name = toDatabaseTableName(modelName, 'imported_cvs_data')
50
+ const model = this.domain.addModel({ info: { name } })
51
+ const entity = model.addEntity({ info: { name } })
52
+ const sanitizedInputName = sanitizeInput(modelName)
53
+ if (name !== sanitizedInputName) {
54
+ model.info.displayName = sanitizedInputName
55
+ entity.info.displayName = sanitizedInputName
56
+ }
57
+ for (const row of data.format) {
58
+ const { index, name, type, format } = row
59
+ const columnName = toDatabaseColumnName(name, `column_${index}`)
60
+ const schema: Partial<DomainPropertySchema> = {
61
+ info: { name: columnName },
62
+ type,
63
+ }
64
+ if (format) {
65
+ schema.bindings = [
66
+ {
67
+ type: 'web',
68
+ schema: {
69
+ format: format === 'integer' ? 'int64' : 'double',
70
+ },
71
+ },
72
+ ]
73
+ }
74
+ const exampleRow = data.values[0]
75
+ if (Array.isArray(exampleRow) && exampleRow[index]) {
76
+ const value = exampleRow[index]
77
+ if (value !== undefined && value !== null) {
78
+ schema.schema = {
79
+ examples: [sanitizeInput(String(value))],
80
+ }
81
+ }
82
+ }
83
+ const prop = entity.addProperty(schema)
84
+ const sn = sanitizeInput(name)
85
+ if (sn !== columnName) {
86
+ prop.info.displayName = sn
87
+ }
88
+ }
89
+ return { entity, model }
90
+ }
91
+ }
@@ -0,0 +1,10 @@
1
+ import { Exception } from '../../exceptions/exception.js'
2
+
3
+ /**
4
+ * An exception thrown during the JSON Schema import process when an
5
+ * unrecoverable error occurs.
6
+ */
7
+ export class ImporterException extends Exception {
8
+ static override code = 'E_IMPORTER_FAILURE'
9
+ static override status = 400 // Bad Request, as it's likely due to invalid input schemas
10
+ }