@xeplr/schema-handler 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Xeplr
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/index.js ADDED
@@ -0,0 +1,33 @@
1
+ var types = require('./lib/types');
2
+ var errors = require('./lib/errors');
3
+ var validate = require('./lib/validate');
4
+ var inference = require('./lib/inference');
5
+ var mapping = require('./lib/mapping');
6
+ var templating = require('./lib/templating');
7
+
8
+ module.exports = {
9
+ // Types
10
+ TYPES: types.TYPES,
11
+ CHECKERS: types.CHECKERS,
12
+ check: types.check,
13
+
14
+ // Errors
15
+ ValidationError: errors.ValidationError,
16
+
17
+ // Validation
18
+ applySchema: validate.applySchema,
19
+
20
+ // Inference (learn / dynamic schema updates)
21
+ inferType: inference.inferType,
22
+ schemaFromObject: inference.schemaFromObject,
23
+ mergeSchemas: inference.mergeSchemas,
24
+ schemasEqual: inference.schemasEqual,
25
+
26
+ // Mapping (dotted paths + resolve)
27
+ getPath: mapping.getPath,
28
+ resolveMapping: mapping.resolveMapping,
29
+
30
+ // Templating ({name} interpolation)
31
+ interpolate: templating.interpolate,
32
+ interpolateAll: templating.interpolateAll
33
+ };
package/lib/errors.js ADDED
@@ -0,0 +1,11 @@
1
+ // Structured validation failure. `details` is an array of per-field messages
2
+ // so the caller can render field-level UI errors, not just one blob.
3
+ class ValidationError extends Error {
4
+ constructor(message, details) {
5
+ super(message);
6
+ this.name = 'ValidationError';
7
+ this.details = details || [];
8
+ }
9
+ }
10
+
11
+ module.exports = { ValidationError: ValidationError };
@@ -0,0 +1,41 @@
1
+ // Derive a schema (or schema fragment) from an actual value at runtime.
2
+ // Powers "learn missing fields" and "dynamic" modes for output schemas.
3
+
4
+ function inferType(v) {
5
+ if (v === null || v === undefined) return 'null';
6
+ if (Array.isArray(v)) return 'array';
7
+ if (v instanceof Date) return 'date';
8
+ return typeof v;
9
+ }
10
+
11
+ // Given an object, return { key: {type} } for each own key.
12
+ function schemaFromObject(obj) {
13
+ var out = {};
14
+ if (!obj || typeof obj !== 'object') return out;
15
+ var keys = Object.keys(obj);
16
+ for (var i = 0; i < keys.length; i++) out[keys[i]] = { type: inferType(obj[keys[i]]) };
17
+ return out;
18
+ }
19
+
20
+ // Merge fresh into current keeping every key already in current (learn mode).
21
+ function mergeSchemas(current, fresh) {
22
+ current = current || {};
23
+ fresh = fresh || {};
24
+ var next = Object.assign({}, current);
25
+ var keys = Object.keys(fresh);
26
+ for (var i = 0; i < keys.length; i++) {
27
+ if (!next[keys[i]]) next[keys[i]] = fresh[keys[i]];
28
+ }
29
+ return next;
30
+ }
31
+
32
+ function schemasEqual(a, b) {
33
+ return JSON.stringify(a || {}) === JSON.stringify(b || {});
34
+ }
35
+
36
+ module.exports = {
37
+ inferType: inferType,
38
+ schemaFromObject: schemaFromObject,
39
+ mergeSchemas: mergeSchemas,
40
+ schemasEqual: schemasEqual
41
+ };
package/lib/mapping.js ADDED
@@ -0,0 +1,23 @@
1
+ // Resolve a mapping — { targetName: 'source.dotted.path' } — against a source
2
+ // object. Returns { targetName: value }. Missing paths yield `undefined`.
3
+
4
+ function getPath(obj, path) {
5
+ if (obj == null || !path) return undefined;
6
+ var parts = String(path).split('.');
7
+ var cur = obj;
8
+ for (var i = 0; i < parts.length; i++) {
9
+ if (cur == null) return undefined;
10
+ cur = cur[parts[i]];
11
+ }
12
+ return cur;
13
+ }
14
+
15
+ function resolveMapping(mapping, source) {
16
+ var out = {};
17
+ if (!mapping) return out;
18
+ var keys = Object.keys(mapping);
19
+ for (var i = 0; i < keys.length; i++) out[keys[i]] = getPath(source, mapping[keys[i]]);
20
+ return out;
21
+ }
22
+
23
+ module.exports = { resolveMapping: resolveMapping, getPath: getPath };
@@ -0,0 +1,38 @@
1
+ // Simple placeholder interpolation. `{name}` and `{a.b.c}` are resolved
2
+ // against `context` via dotted paths. Unknown paths render as empty string.
3
+ // Use `{{` and `}}` for literal braces.
4
+
5
+ var { getPath } = require('./mapping');
6
+
7
+ var OPEN_SENTINEL = '';
8
+ var CLOSE_SENTINEL = '';
9
+
10
+ function interpolate(template, context) {
11
+ if (template == null) return '';
12
+ var str = String(template)
13
+ .split('{{').join(OPEN_SENTINEL)
14
+ .split('}}').join(CLOSE_SENTINEL);
15
+ str = str.replace(/\{([^{}]+)\}/g, function(_, path) {
16
+ var v = getPath(context, path.trim());
17
+ if (v === undefined || v === null) return '';
18
+ return typeof v === 'object' ? JSON.stringify(v) : String(v);
19
+ });
20
+ return str.split(OPEN_SENTINEL).join('{').split(CLOSE_SENTINEL).join('}');
21
+ }
22
+
23
+ // Recursively interpolate all string values in a structure. Objects and
24
+ // arrays are walked; primitives other than strings are returned as-is.
25
+ function interpolateAll(value, context) {
26
+ if (value == null) return value;
27
+ if (typeof value === 'string') return interpolate(value, context);
28
+ if (Array.isArray(value)) return value.map(function(v) { return interpolateAll(v, context); });
29
+ if (typeof value === 'object') {
30
+ var out = {};
31
+ var keys = Object.keys(value);
32
+ for (var i = 0; i < keys.length; i++) out[keys[i]] = interpolateAll(value[keys[i]], context);
33
+ return out;
34
+ }
35
+ return value;
36
+ }
37
+
38
+ module.exports = { interpolate: interpolate, interpolateAll: interpolateAll };
package/lib/types.js ADDED
@@ -0,0 +1,20 @@
1
+ // The one canonical set of supported types + runtime type predicates.
2
+ // Used by validate.js (input checking) and inference.js (typeof-based inference).
3
+
4
+ var TYPES = ['string', 'number', 'boolean', 'date', 'object', 'array'];
5
+
6
+ var CHECKERS = {
7
+ string: function(v) { return typeof v === 'string'; },
8
+ number: function(v) { return typeof v === 'number' && !isNaN(v); },
9
+ boolean: function(v) { return typeof v === 'boolean'; },
10
+ date: function(v) { return v instanceof Date || (typeof v === 'string' && !isNaN(Date.parse(v))); },
11
+ object: function(v) { return v !== null && typeof v === 'object' && !Array.isArray(v) && !(v instanceof Date); },
12
+ array: function(v) { return Array.isArray(v); }
13
+ };
14
+
15
+ function check(type, value) {
16
+ var fn = CHECKERS[type];
17
+ return fn ? fn(value) : true; // unknown type → don't reject
18
+ }
19
+
20
+ module.exports = { TYPES: TYPES, CHECKERS: CHECKERS, check: check };
@@ -0,0 +1,44 @@
1
+ var { check } = require('./types');
2
+ var { ValidationError } = require('./errors');
3
+
4
+ /**
5
+ * Apply a schema (array of field definitions) to a values object.
6
+ * Returns a copy of `values` with defaults filled in.
7
+ * Throws ValidationError listing every problem.
8
+ *
9
+ * Field: { name, type, required, default, description, order }
10
+ * Values: { [name]: value }
11
+ * Label: free-form string used in error messages, e.g. 'config' | 'input' | 'params'
12
+ */
13
+ function applySchema(schema, values, label) {
14
+ values = values || {};
15
+ label = label || 'field';
16
+ var out = {};
17
+ var errors = [];
18
+
19
+ if (!Array.isArray(schema)) return Object.assign({}, values);
20
+
21
+ for (var i = 0; i < schema.length; i++) {
22
+ var field = schema[i];
23
+ if (!field || !field.name) continue;
24
+
25
+ var val = values[field.name];
26
+ var missing = val === undefined || val === null;
27
+
28
+ if (missing && field.default !== undefined) { out[field.name] = field.default; continue; }
29
+ if (missing) {
30
+ if (field.required) errors.push('Missing required ' + label + ' field: ' + field.name);
31
+ continue;
32
+ }
33
+ if (field.type && !check(field.type, val)) {
34
+ errors.push(label + ' field "' + field.name + '" expected type ' + field.type + ', got ' + typeof val);
35
+ continue;
36
+ }
37
+ out[field.name] = val;
38
+ }
39
+
40
+ if (errors.length) throw new ValidationError(errors.join('; '), errors);
41
+ return out;
42
+ }
43
+
44
+ module.exports = { applySchema: applySchema };
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@xeplr/schema-handler",
3
+ "version": "1.0.1",
4
+ "description": "Field-schema primitive: define, validate, infer, map, and template values across schemas",
5
+ "main": "index.js",
6
+ "files": [
7
+ "index.js",
8
+ "lib/"
9
+ ],
10
+ "keywords": [
11
+ "schema",
12
+ "validation",
13
+ "mapping",
14
+ "templating",
15
+ "form"
16
+ ],
17
+ "author": "xeplr",
18
+ "license": "MIT",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/Xeplr/xeplr-schema-handler"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "dependencies": {}
27
+ }