@hestia-earth/schema-convert 7.2.0 → 7.4.0

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/json.d.ts CHANGED
@@ -1,2 +1,37 @@
1
- import { definitions } from '@hestia-earth/json-schema';
1
+ import { SchemaType } from '@hestia-earth/schema';
2
+ import { definitions } from '@hestia-earth/json-schema/types';
3
+ export interface INode {
4
+ type: SchemaType;
5
+ id?: string;
6
+ name?: string;
7
+ }
8
+ export interface ICSVContent {
9
+ [key: string]: string | ICSVContent;
10
+ }
11
+ interface ICSVHeader {
12
+ name: string;
13
+ index: number;
14
+ }
15
+ export interface ICSVError {
16
+ message: string;
17
+ schema?: SchemaType;
18
+ schemaKey?: string;
19
+ key?: string;
20
+ property?: string;
21
+ value?: any;
22
+ error?: string;
23
+ headers?: ICSVHeader[];
24
+ }
25
+ export declare const throwCSVError: <T extends ICSVError>(error: T) => never;
26
+ export declare const cleanStringValue: (value: string) => string;
27
+ export declare const formatNode: (schemas: definitions, type: SchemaType, data: ICSVContent, ignoreInternal: boolean, top?: boolean) => any;
28
+ export declare const filterEmptyNode: (schemas: definitions, { schemaVersion, ...node }: any) => boolean;
29
+ /**
30
+ * Convert CSV to Hestia JSON-LD format.
31
+ *
32
+ * @param schemas The definitions of the Hestia Schema (`import { loadSchemas } from "@hestia-earth/json-schema"`)
33
+ * @param content The content of the CSV as a string
34
+ * @returns A list of JSON-LD content.
35
+ */
2
36
  export declare const toJson: (schemas: definitions, content: string) => Promise<any[]>;
37
+ export {};
package/json.js CHANGED
@@ -46,51 +46,251 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
46
46
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
47
  }
48
48
  };
49
+ var __rest = (this && this.__rest) || function (s, e) {
50
+ var t = {};
51
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
52
+ t[p] = s[p];
53
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
54
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
55
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
56
+ t[p[i]] = s[p[i]];
57
+ }
58
+ return t;
59
+ };
49
60
  Object.defineProperty(exports, "__esModule", { value: true });
50
- exports.toJson = void 0;
61
+ exports.toJson = exports.filterEmptyNode = exports.formatNode = exports.cleanStringValue = exports.throwCSVError = void 0;
51
62
  var csvtojson = require("csvtojson");
52
63
  var schema_1 = require("@hestia-earth/schema");
64
+ var types_1 = require("@hestia-earth/json-schema/types");
53
65
  var utils_1 = require("./utils");
54
- var propertyRef = function (schema, key) {
55
- var property = schema && schema.properties ? schema.properties[key] : {};
56
- return property ? ('items' in property ? property.items['$ref'] : property['$ref']) : null;
57
- };
58
- var keyType = function (schema, key) {
59
- var ref = propertyRef(schema, key);
60
- return ref ? schema_1.refToSchemaType(ref) : null;
61
- };
62
- var formatNode = function (schemas, schema, node) {
63
- return typeof node === 'object' ?
64
- Object.keys(node)
65
- .map(function (key) {
66
- var isArray = Array.isArray(node[key]);
67
- var type = keyType(schema, key);
68
- var nodeSchema = type ? schemas[type] : schema;
69
- var value = (isArray ? node[key] : [node[key]])
70
- .map(function (v) { return formatNode(schemas, nodeSchema, v); })
71
- .filter(utils_1.nonEmptyNode)
72
- .map(function (v) { return typeof v === 'object' ? (__assign(__assign({}, v), (type ? { type: type } : {}))) : v; });
73
- return {
74
- key: key,
75
- isArray: isArray,
76
- value: isArray ? value : value[0]
77
- };
78
- })
79
- .filter(function (_a) {
80
- var key = _a.key, value = _a.value;
81
- return utils_1.nonEmptyValue(key) && utils_1.nonEmptyNode(value);
82
- })
83
- .reduce(function (prev, _a) {
66
+ var IGNORE_FIELD_KEY = '-';
67
+ var VALUE_TYPE_KEY = 'valueType';
68
+ var DEFAULT_ARRAY_DELIMITER = ';';
69
+ var arrayDelimiter = function () {
70
+ try {
71
+ return process.env.CSV_ARRAY_DELIMITER || DEFAULT_ARRAY_DELIMITER;
72
+ }
73
+ catch (err) {
74
+ return DEFAULT_ARRAY_DELIMITER;
75
+ }
76
+ };
77
+ var safeParseJSON = function (obj) {
78
+ // throw already handled error or throw a generic invalid-format error
79
+ var data;
80
+ try {
81
+ data = JSON.parse(obj);
82
+ }
83
+ catch (err) { }
84
+ return data;
85
+ };
86
+ var internalProperties = function (_a) {
87
+ var properties = _a.properties;
88
+ return Object.keys(properties).filter(function (property) { return properties[property].internal; });
89
+ };
90
+ var nonEmptyCell = function (value) { return value !== IGNORE_FIELD_KEY && value !== ''; };
91
+ var compileFullKey = function (key1, key2) {
92
+ // handle arrays
93
+ var joinKey = (key2 || '').startsWith('[') ? '' : '.';
94
+ return [key1, key2].filter(Boolean).join(joinKey);
95
+ };
96
+ var propertyRequiredValue = function (value, required) {
97
+ var _a;
98
+ var val = typeof value === 'object' && required[0] in value ? value[required[0]] : value;
99
+ return nonEmptyCell(val) ? (_a = {}, _a[required[0]] = val, _a) : {};
100
+ };
101
+ var parseError = function (err) { return safeParseJSON(err.message); };
102
+ exports.throwCSVError = function (error) {
103
+ throw new Error(JSON.stringify(error));
104
+ };
105
+ var schemaNotFoundError = function () { return exports.throwCSVError({
106
+ message: 'schema-not-found'
107
+ }); };
108
+ var propertyNotFoundError = function (schema, key, value) { return exports.throwCSVError({
109
+ schema: schema.title,
110
+ message: 'property-not-found',
111
+ schemaKey: key,
112
+ key: key,
113
+ value: value
114
+ }); };
115
+ var propertyInvalidFormat = function (schema, key, value, func) {
116
+ try {
117
+ return func();
118
+ }
119
+ catch (err) {
120
+ var data = parseError(err);
121
+ // throw already handled error or throw a generic invalid-format error
122
+ return exports.throwCSVError(data ? __assign(__assign({}, data), { key: compileFullKey(key, data.key) }) : {
123
+ schema: schema.title,
124
+ message: 'property-invalid-format',
125
+ schemaKey: key,
126
+ key: key,
127
+ value: value,
128
+ error: err === null || err === void 0 ? void 0 : err.message
129
+ });
130
+ }
131
+ };
132
+ var handleArrayError = function (func) { return function (value, index) {
133
+ try {
134
+ return func(value, index);
135
+ }
136
+ catch (err) {
137
+ var data = parseError(err);
138
+ // throw already handled error or throw a generic invalid-format error
139
+ return data ?
140
+ exports.throwCSVError(__assign(__assign({}, data), { key: compileFullKey("" + index, data.key) })) :
141
+ (function () {
142
+ throw err;
143
+ })();
144
+ }
145
+ }; };
146
+ /**
147
+ * If the user provided a non-object where an object was expected, assume it was meant to be the `name` property.
148
+ *
149
+ * @param value The value mapped as a Ref
150
+ */
151
+ var schemaRefValue = function (value) { return typeof value === 'object' ? value : ({ name: value }); };
152
+ exports.cleanStringValue = function (value) { return (value.match(/^[\d]+\.[\d]+\.[\d]+$/) === null ? value.replace(/\.0$/, '') : value).trim(); };
153
+ var propertyTypeToValue = {
154
+ string: function (value) { return exports.cleanStringValue(value || ''); },
155
+ number: function (value) {
156
+ return isNaN(+value) ? (function () {
157
+ throw new Error('failed to parse number');
158
+ })() : +value;
159
+ },
160
+ integer: function (value) { return +value; },
161
+ boolean: function (value) { return value.toLowerCase() === 'true'; },
162
+ object: function (value, schemas, _a, _i) {
163
+ var $ref = _a.$ref, required = _a.required;
164
+ return $ref ?
165
+ propertyTypeToValue.$ref(value, schemas, { $ref: $ref }, _i) :
166
+ propertyTypeToValue.required(value, schemas, { required: required }, _i);
167
+ },
168
+ array: function (value, schemas, _a, _i) {
169
+ var items = _a.items;
170
+ return (Array.isArray(value) ? value : value.split(arrayDelimiter()))
171
+ .map(handleArrayError(function (val) { return items ? ('$ref' in items ?
172
+ propertyTypeToValue.object(val, schemas, items, _i) :
173
+ Array.isArray(items.type) ?
174
+ propertyTypeToValue.auto(val, schemas, items, _i) :
175
+ propertyTypeToValue[items.type](val, schemas, items, _i)) : val; }))
176
+ .filter(function (val) { return !utils_1.isEmpty(val); });
177
+ },
178
+ // try to determine the type automatically
179
+ auto: function (value, schemas, _d, _i) {
180
+ // iris are mapped as {@id: val}
181
+ return utils_1.isIri(value) ? propertyTypeToValue.required(value, schemas, { required: ['@id'] }, _i) : (utils_1.isBoolean(value) ? propertyTypeToValue.boolean(value) : (utils_1.isNumber(value) ? propertyTypeToValue.number(value) :
182
+ propertyTypeToValue.string(value)));
183
+ },
184
+ required: function (value, _schemas, _a) {
185
+ var required = _a.required;
186
+ var data = propertyRequiredValue(value, required);
187
+ return utils_1.isEmpty(data) ? {} : data;
188
+ },
189
+ $ref: function (value, schemas, _a, _i) {
190
+ var $ref = _a.$ref;
191
+ var schemaType = schema_1.refToSchemaType($ref);
192
+ var schema = schemaType ? schemas[schemaType] : undefined;
193
+ var data = schema ? mapContent(schemas, schema, _i)(schemaRefValue(value)) : safeParseJSON(value);
194
+ return utils_1.isEmpty(data) ? {} : (schema ? extendDataFromSchema(data, schema, schemaType, _i) : data);
195
+ }
196
+ };
197
+ var getPropertyDefinition = function (schema, key, ignoreErrors, value) {
198
+ if (ignoreErrors === void 0) { ignoreErrors = false; }
199
+ return key in schema.properties ? schema.properties[key] : !ignoreErrors && propertyNotFoundError(schema, key, value);
200
+ };
201
+ var getValueType = function (schema, json) {
202
+ return VALUE_TYPE_KEY in schema.properties ? (
203
+ // valueType can be present but skipped
204
+ (json[VALUE_TYPE_KEY] !== IGNORE_FIELD_KEY ? json[VALUE_TYPE_KEY] : null) ||
205
+ schema.properties[VALUE_TYPE_KEY].default) : null;
206
+ };
207
+ var getPropertyType = function (def, key, valueType) {
208
+ // default type is object (like $ref)
209
+ return (key === 'value' && valueType ? valueType : (Array.isArray(def.type) ? 'auto' : def.type)) || 'object';
210
+ };
211
+ var setDefaultProperty = function (prop, def, node, ignoreInternal) {
212
+ if (ignoreInternal === void 0) { ignoreInternal = false; }
213
+ return prop !== VALUE_TYPE_KEY && (
214
+ // only get default if internal or not present
215
+ (!ignoreInternal && def.internal) || !node || !(prop in node));
216
+ };
217
+ var getDefaultProperties = function (schema, node, ignoreInternal) {
218
+ if (ignoreInternal === void 0) { ignoreInternal = false; }
219
+ return types_1.defaultProperties(schema)
220
+ .map(function (property) {
221
+ var def = schema.properties[property];
222
+ return setDefaultProperty(property, def, node, ignoreInternal) ? { property: property, defaultValue: def.default } : null;
223
+ }, {})
224
+ .filter(Boolean);
225
+ };
226
+ var filterProperties = function (data, excludedProps) {
227
+ return Object.keys(data)
228
+ .filter(function (key) { return !excludedProps.includes(key); })
229
+ .reduce(function (prev, curr) {
230
+ var _a;
231
+ return (__assign(__assign({}, prev), (_a = {}, _a[curr] = data[curr], _a)));
232
+ }, {});
233
+ };
234
+ var nodeType = function (id, type, existingNode) {
235
+ if (existingNode === void 0) { existingNode = false; }
236
+ return type ? (schema_1.isTypeNode(type) ? (existingNode ? { '@type': type } : { id: id, type: type }) : { type: type }) : {};
237
+ };
238
+ var extendDataFromSchema = function (_a, schema, type, ignoreInternal, top) {
239
+ if (ignoreInternal === void 0) { ignoreInternal = false; }
240
+ if (top === void 0) { top = false; }
241
+ var id = _a.id, _t = _a.type, data = __rest(_a, ["id", "type"]);
242
+ return utils_1.reduceUndefinedValues(__assign(__assign(__assign({}, filterProperties(data, ignoreInternal ? [] : internalProperties(schema))), (top && schema ?
243
+ getDefaultProperties(schema, data, ignoreInternal).reduce(function (prev, _a) {
84
244
  var _b;
85
- var key = _a.key, value = _a.value;
86
- return (__assign(__assign({}, prev), (_b = {}, _b[key] = value, _b)));
245
+ var property = _a.property, defaultValue = _a.defaultValue;
246
+ return (__assign(__assign({}, prev), (_b = {}, _b[property] = defaultValue, _b)));
87
247
  }, {}) :
88
- node;
248
+ {})), nodeType(id, type, '@id' in data)));
249
+ };
250
+ var isEmptyValue = function (value) {
251
+ return (value['@type'] || value.type) === schema_1.SchemaType.Term ? !(value['@id'] || value.id || value.name) : utils_1.isEmpty(value);
252
+ };
253
+ var mapContent = function (schemas, schema, ignoreInternal) { return function (json) {
254
+ return Object.keys(json)
255
+ .filter(function (key) { return nonEmptyCell(key) && nonEmptyCell(json[key]); })
256
+ .reduce(function (prev, key) {
257
+ var _a;
258
+ var value = json[key];
259
+ var propertyDefinition = getPropertyDefinition(schema, key, false, json);
260
+ var valueType = getValueType(schema, json);
261
+ var type = getPropertyType(propertyDefinition, key, valueType);
262
+ var newValue = key === VALUE_TYPE_KEY ? '' : propertyInvalidFormat(schema, key, value, function () {
263
+ return Array.isArray(type) ? value : propertyTypeToValue[type](value, schemas, propertyDefinition, ignoreInternal);
264
+ });
265
+ return __assign(__assign(__assign({}, prev), (schema.$id ? { type: schema.title } : {})), (isEmptyValue(newValue) ? {} : (_a = {}, _a[key] = newValue, _a)));
266
+ }, {});
267
+ }; };
268
+ exports.formatNode = function (schemas, type, data, ignoreInternal, top) {
269
+ if (top === void 0) { top = false; }
270
+ var schema = type in schemas ? schemas[type] : schemaNotFoundError();
271
+ var content = mapContent(schemas, schema, ignoreInternal)(data);
272
+ return utils_1.reduceUndefinedValues(__assign({ id: !nonEmptyCell(data.id) ? undefined : data.id }, extendDataFromSchema(content, schema, type, ignoreInternal, top)));
273
+ };
274
+ exports.filterEmptyNode = function (schemas, _a) {
275
+ var schemaVersion = _a.schemaVersion, node = __rest(_a, ["schemaVersion"]);
276
+ // make sure defaultProperties are not counted
277
+ var schema = node.type ? schemas[node.type] : null;
278
+ var minKeysLength = schema ? getDefaultProperties(schema).length + 1 : 1;
279
+ return !utils_1.isEmpty(node, minKeysLength) && !!schema;
89
280
  };
90
- var convetToNode = function (schemas) { return function (data) { return Object.keys(data)
91
- .filter(utils_1.nonEmptyValue)
92
- .map(function (type) { return (__assign({ type: schema_1.typeToSchemaType(type) }, formatNode(schemas, schemas[schema_1.typeToSchemaType(type)], data[type]))); })
93
- .filter(utils_1.nonEmptyNode); }; };
281
+ var convetToNode = function (schemas) { return function (data) {
282
+ return Object.keys(data)
283
+ .filter(utils_1.nonEmptyValue)
284
+ .map(function (type) { return exports.formatNode(schemas, schema_1.typeToSchemaType(type), data[type], true, true); })
285
+ .filter(function (node) { return exports.filterEmptyNode(schemas, node); });
286
+ }; };
287
+ /**
288
+ * Convert CSV to Hestia JSON-LD format.
289
+ *
290
+ * @param schemas The definitions of the Hestia Schema (`import { loadSchemas } from "@hestia-earth/json-schema"`)
291
+ * @param content The content of the CSV as a string
292
+ * @returns A list of JSON-LD content.
293
+ */
94
294
  exports.toJson = function (schemas, content) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
95
295
  switch (_a.label) {
96
296
  case 0: return [4 /*yield*/, csvtojson({ delimiter: 'auto' }).fromString(content)];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hestia-earth/schema-convert",
3
- "version": "7.2.0",
3
+ "version": "7.4.0",
4
4
  "description": "Hestia Schema Converters",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
package/utils.d.ts CHANGED
@@ -1,5 +1,9 @@
1
1
  export declare const omit: (data: any, keys: string[]) => any;
2
2
  export declare const isExpandable: (val: any) => number | boolean;
3
+ export declare const isIri: (value?: string) => boolean;
4
+ export declare const isBoolean: (value: string) => boolean;
5
+ export declare const isNumber: (n: string | number) => boolean;
6
+ export declare const isEmpty: (value: any, minKeys?: number) => boolean;
3
7
  export declare const nonEmptyValue: (value: any) => boolean;
4
8
  export declare const nonEmptyNode: (node: any) => boolean;
5
9
  export declare const reduceUndefinedValues: <T>(obj: T) => Partial<T>;
package/utils.js CHANGED
@@ -11,7 +11,7 @@ var __assign = (this && this.__assign) || function () {
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.reduceUndefinedValues = exports.nonEmptyNode = exports.nonEmptyValue = exports.isExpandable = exports.omit = void 0;
14
+ exports.reduceUndefinedValues = exports.nonEmptyNode = exports.nonEmptyValue = exports.isEmpty = exports.isNumber = exports.isBoolean = exports.isIri = exports.isExpandable = exports.omit = void 0;
15
15
  var unset = require('lodash.unset');
16
16
  exports.omit = function (data, keys) {
17
17
  var obj = __assign({}, data);
@@ -19,21 +19,25 @@ exports.omit = function (data, keys) {
19
19
  return obj;
20
20
  };
21
21
  exports.isExpandable = function (val) { return !!val && typeof val === 'object' && (Array.isArray(val) ? val.every(exports.isExpandable) : Object.keys(val).length); };
22
+ exports.isIri = function (value) { return (value || '').startsWith('http'); };
23
+ exports.isBoolean = function (value) { return value.toLowerCase() === 'true' || value.toLowerCase() === 'false'; };
24
+ exports.isNumber = function (n) { return !isNaN(parseFloat("" + n)) && isFinite(parseFloat("" + n)); };
22
25
  var ignoreKey = function (key) { return !['@type', 'type'].includes(key); };
23
- var isEmpty = function (value) {
26
+ exports.isEmpty = function (value, minKeys) {
27
+ if (minKeys === void 0) { minKeys = 1; }
24
28
  return value === null ||
25
29
  typeof value === 'undefined' ||
26
30
  (typeof value === 'object' ?
27
31
  (Array.isArray(value) ?
28
32
  !value.length :
29
- Object.keys(value).filter(ignoreKey).length < 1) :
33
+ Object.keys(value).filter(function (key) { return key !== 'type'; }).length < minKeys) :
30
34
  value === '');
31
35
  };
32
- exports.nonEmptyValue = function (value) { return !isEmpty(value) && value !== '-'; };
36
+ exports.nonEmptyValue = function (value) { return !exports.isEmpty(value) && value !== '-'; };
33
37
  exports.nonEmptyNode = function (node) {
34
38
  return typeof node === 'object' ?
35
39
  Object.keys(node)
36
- .filter(function (key) { return ignoreKey(key) && !isEmpty(node[key]); })
40
+ .filter(function (key) { return ignoreKey(key) && !exports.isEmpty(node[key]); })
37
41
  .length > 0 :
38
42
  exports.nonEmptyValue(node);
39
43
  };