@malloydata/motly-ts-parser 0.2.0 → 0.2.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/build/interface/src/types.d.ts +69 -0
- package/build/interface/src/types.js +12 -0
- package/build/{clone.d.ts → parser/src/clone.d.ts} +1 -1
- package/build/{clone.js → parser/src/clone.js} +3 -3
- package/build/{index.d.ts → parser/src/index.d.ts} +2 -2
- package/build/{index.js → parser/src/index.js} +3 -3
- package/build/{interpreter.d.ts → parser/src/interpreter.d.ts} +1 -1
- package/build/{interpreter.js → parser/src/interpreter.js} +2 -2
- package/build/{session.d.ts → parser/src/session.d.ts} +1 -1
- package/build/{validate.d.ts → parser/src/validate.d.ts} +1 -1
- package/build/{validate.js → parser/src/validate.js} +22 -22
- package/package.json +3 -4
- /package/build/{ast.d.ts → parser/src/ast.d.ts} +0 -0
- /package/build/{ast.js → parser/src/ast.js} +0 -0
- /package/build/{parser.d.ts → parser/src/parser.d.ts} +0 -0
- /package/build/{parser.js → parser/src/parser.js} +0 -0
- /package/build/{session.js → parser/src/session.js} +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** A MOTLY scalar: string, number, boolean, or Date. */
|
|
2
|
+
export type MOTLYScalar = string | number | boolean | Date;
|
|
3
|
+
/** A reference to another node in the MOTLY tree (e.g. `$^parent.name`). */
|
|
4
|
+
export interface MOTLYRef {
|
|
5
|
+
linkTo: string;
|
|
6
|
+
}
|
|
7
|
+
/** An environment variable reference (e.g. `@env.API_KEY`). */
|
|
8
|
+
export interface MOTLYEnvRef {
|
|
9
|
+
env: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* A value node in the MOTLY tree.
|
|
13
|
+
*
|
|
14
|
+
* - `eq` — the node's assigned value: a scalar, a reference ({@link MOTLYRef}),
|
|
15
|
+
* or an array of child nodes
|
|
16
|
+
* - `properties` — named child nodes (the node's "tags")
|
|
17
|
+
* - `deleted` — true if this node was explicitly deleted with `-name`
|
|
18
|
+
*/
|
|
19
|
+
export interface MOTLYValue {
|
|
20
|
+
eq?: MOTLYScalar | MOTLYRef | MOTLYEnvRef | MOTLYNode[];
|
|
21
|
+
properties?: Record<string, MOTLYNode>;
|
|
22
|
+
deleted?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A node in the MOTLY tree. Every node is a {@link MOTLYValue}.
|
|
26
|
+
* References are represented as `eq: { linkTo: "..." }` inside a value node.
|
|
27
|
+
*/
|
|
28
|
+
export type MOTLYNode = MOTLYValue;
|
|
29
|
+
/** A parse error with source location span. */
|
|
30
|
+
export interface MOTLYError {
|
|
31
|
+
/** Machine-readable error code (e.g. `"tag-parse-syntax-error"`). */
|
|
32
|
+
code: string;
|
|
33
|
+
/** Human-readable error message. */
|
|
34
|
+
message: string;
|
|
35
|
+
/** Start of the offending region (0-based line, column, and byte offset). */
|
|
36
|
+
begin: {
|
|
37
|
+
line: number;
|
|
38
|
+
column: number;
|
|
39
|
+
offset: number;
|
|
40
|
+
};
|
|
41
|
+
/** End of the offending region (0-based, exclusive). */
|
|
42
|
+
end: {
|
|
43
|
+
line: number;
|
|
44
|
+
column: number;
|
|
45
|
+
offset: number;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/** An error from schema validation. */
|
|
49
|
+
export interface MOTLYSchemaError {
|
|
50
|
+
/** Machine-readable error code (e.g. `"missing-required"`, `"wrong-type"`). */
|
|
51
|
+
code: string;
|
|
52
|
+
/** Human-readable error message. */
|
|
53
|
+
message: string;
|
|
54
|
+
/** Path to the offending node (e.g. `["metadata", "name"]`). */
|
|
55
|
+
path: string[];
|
|
56
|
+
}
|
|
57
|
+
/** Type guard: is this eq value a link reference? */
|
|
58
|
+
export declare function isRef(eq: MOTLYValue["eq"]): eq is MOTLYRef;
|
|
59
|
+
/** Type guard: is this eq value an env reference? */
|
|
60
|
+
export declare function isEnvRef(eq: MOTLYValue["eq"]): eq is MOTLYEnvRef;
|
|
61
|
+
/** An error from reference validation. */
|
|
62
|
+
export interface MOTLYValidationError {
|
|
63
|
+
/** Machine-readable error code (e.g. `"unresolved-reference"`). */
|
|
64
|
+
code: string;
|
|
65
|
+
/** Human-readable error message. */
|
|
66
|
+
message: string;
|
|
67
|
+
/** Path to the offending reference (e.g. `["spec", "ref"]`). */
|
|
68
|
+
path: string[];
|
|
69
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isRef = isRef;
|
|
4
|
+
exports.isEnvRef = isEnvRef;
|
|
5
|
+
/** Type guard: is this eq value a link reference? */
|
|
6
|
+
function isRef(eq) {
|
|
7
|
+
return typeof eq === "object" && eq !== null && "linkTo" in eq && !Array.isArray(eq) && !(eq instanceof Date);
|
|
8
|
+
}
|
|
9
|
+
/** Type guard: is this eq value an env reference? */
|
|
10
|
+
function isEnvRef(eq) {
|
|
11
|
+
return typeof eq === "object" && eq !== null && "env" in eq && !Array.isArray(eq) && !(eq instanceof Date);
|
|
12
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.cloneValue = cloneValue;
|
|
4
|
-
const
|
|
4
|
+
const types_1 = require("../../interface/src/types");
|
|
5
5
|
/** Deep clone a MOTLYValue. */
|
|
6
6
|
function cloneValue(value) {
|
|
7
7
|
const result = {};
|
|
@@ -14,10 +14,10 @@ function cloneValue(value) {
|
|
|
14
14
|
else if (Array.isArray(value.eq)) {
|
|
15
15
|
result.eq = value.eq.map(cloneValue);
|
|
16
16
|
}
|
|
17
|
-
else if ((0,
|
|
17
|
+
else if ((0, types_1.isRef)(value.eq)) {
|
|
18
18
|
result.eq = { linkTo: value.eq.linkTo };
|
|
19
19
|
}
|
|
20
|
-
else if ((0,
|
|
20
|
+
else if ((0, types_1.isEnvRef)(value.eq)) {
|
|
21
21
|
result.eq = { env: value.eq.env };
|
|
22
22
|
}
|
|
23
23
|
else {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { MOTLYScalar, MOTLYRef, MOTLYEnvRef, MOTLYValue, MOTLYNode, MOTLYError, MOTLYSchemaError, MOTLYValidationError, } from "
|
|
2
|
-
export { isRef, isEnvRef } from "
|
|
1
|
+
export type { MOTLYScalar, MOTLYRef, MOTLYEnvRef, MOTLYValue, MOTLYNode, MOTLYError, MOTLYSchemaError, MOTLYValidationError, } from "../../interface/src/types";
|
|
2
|
+
export { isRef, isEnvRef } from "../../interface/src/types";
|
|
3
3
|
export { MOTLYSession } from "./session";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MOTLYSession = exports.isEnvRef = exports.isRef = void 0;
|
|
4
|
-
var
|
|
5
|
-
Object.defineProperty(exports, "isRef", { enumerable: true, get: function () { return
|
|
6
|
-
Object.defineProperty(exports, "isEnvRef", { enumerable: true, get: function () { return
|
|
4
|
+
var types_1 = require("../../interface/src/types");
|
|
5
|
+
Object.defineProperty(exports, "isRef", { enumerable: true, get: function () { return types_1.isRef; } });
|
|
6
|
+
Object.defineProperty(exports, "isEnvRef", { enumerable: true, get: function () { return types_1.isEnvRef; } });
|
|
7
7
|
var session_1 = require("./session");
|
|
8
8
|
Object.defineProperty(exports, "MOTLYSession", { enumerable: true, get: function () { return session_1.MOTLYSession; } });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Statement } from "./ast";
|
|
2
|
-
import { MOTLYValue, MOTLYError } from "
|
|
2
|
+
import { MOTLYValue, MOTLYError } from "../../interface/src/types";
|
|
3
3
|
/** Execute a list of parsed statements against an existing MOTLYValue. */
|
|
4
4
|
export declare function execute(statements: Statement[], root: MOTLYValue): MOTLYError[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.execute = execute;
|
|
4
|
-
const
|
|
4
|
+
const types_1 = require("../../interface/src/types");
|
|
5
5
|
const clone_1 = require("./clone");
|
|
6
6
|
/** Execute a list of parsed statements against an existing MOTLYValue. */
|
|
7
7
|
function execute(statements, root) {
|
|
@@ -280,7 +280,7 @@ function cloneError(message) {
|
|
|
280
280
|
* if N > D. Absolute references (ups=0) are left alone.
|
|
281
281
|
*/
|
|
282
282
|
function sanitizeClonedRefs(node, depth, errors) {
|
|
283
|
-
if ((0,
|
|
283
|
+
if ((0, types_1.isRef)(node.eq)) {
|
|
284
284
|
const parsed = parseRefUps(node.eq.linkTo);
|
|
285
285
|
if (parsed.ups > 0 && parsed.ups > depth) {
|
|
286
286
|
const zero = { line: 0, column: 0, offset: 0 };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { MOTLYValue, MOTLYSchemaError, MOTLYValidationError } from "
|
|
1
|
+
import { MOTLYValue, MOTLYSchemaError, MOTLYValidationError } from "../../interface/src/types";
|
|
2
2
|
export declare function validateReferences(root: MOTLYValue): MOTLYValidationError[];
|
|
3
3
|
export declare function validateSchema(tag: MOTLYValue, schema: MOTLYValue): MOTLYSchemaError[];
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validateReferences = validateReferences;
|
|
4
4
|
exports.validateSchema = validateSchema;
|
|
5
|
-
const
|
|
5
|
+
const types_1 = require("../../interface/src/types");
|
|
6
6
|
function getEqString(node) {
|
|
7
7
|
return typeof node.eq === "string" ? node.eq : undefined;
|
|
8
8
|
}
|
|
9
9
|
function valueEqString(node) {
|
|
10
|
-
if ((0,
|
|
10
|
+
if ((0, types_1.isRef)(node.eq) || (0, types_1.isEnvRef)(node.eq))
|
|
11
11
|
return undefined;
|
|
12
12
|
return getEqString(node);
|
|
13
13
|
}
|
|
@@ -15,7 +15,7 @@ function extractSection(node, name) {
|
|
|
15
15
|
if (!node.properties)
|
|
16
16
|
return undefined;
|
|
17
17
|
const section = node.properties[name];
|
|
18
|
-
if (section === undefined || (0,
|
|
18
|
+
if (section === undefined || (0, types_1.isRef)(section.eq) || (0, types_1.isEnvRef)(section.eq))
|
|
19
19
|
return undefined;
|
|
20
20
|
return section.properties;
|
|
21
21
|
}
|
|
@@ -38,7 +38,7 @@ function walkRefs(node, path, ancestors, root, errors) {
|
|
|
38
38
|
path.push(key);
|
|
39
39
|
// Check if child's eq is a reference (checked at property level
|
|
40
40
|
// to maintain correct ancestor depth for reference resolution)
|
|
41
|
-
if ((0,
|
|
41
|
+
if ((0, types_1.isRef)(child.eq)) {
|
|
42
42
|
const errMsg = checkLink(child.eq, ancestors, root);
|
|
43
43
|
if (errMsg !== null) {
|
|
44
44
|
errors.push({
|
|
@@ -62,7 +62,7 @@ function walkArrayRefs(arr, path, ancestors, parentNode, root, errors) {
|
|
|
62
62
|
const idxKey = `[${i}]`;
|
|
63
63
|
path.push(idxKey);
|
|
64
64
|
// Check if element's eq is a reference
|
|
65
|
-
if ((0,
|
|
65
|
+
if ((0, types_1.isRef)(elem.eq)) {
|
|
66
66
|
const errMsg = checkLink(elem.eq, ancestors, root);
|
|
67
67
|
if (errMsg !== null) {
|
|
68
68
|
errors.push({
|
|
@@ -183,7 +183,7 @@ function getAdditionalPolicy(schema) {
|
|
|
183
183
|
const additional = schema.properties["Additional"];
|
|
184
184
|
if (additional === undefined)
|
|
185
185
|
return { kind: "reject" };
|
|
186
|
-
if ((0,
|
|
186
|
+
if ((0, types_1.isRef)(additional.eq))
|
|
187
187
|
return { kind: "reject" };
|
|
188
188
|
const eqStr = getEqString(additional);
|
|
189
189
|
if (eqStr !== undefined) {
|
|
@@ -262,12 +262,12 @@ function makeTypeSpecNode(typeName) {
|
|
|
262
262
|
return { eq: typeName };
|
|
263
263
|
}
|
|
264
264
|
function validateValueType(value, typeSpec, types, path, errors) {
|
|
265
|
-
if ((0,
|
|
265
|
+
if ((0, types_1.isRef)(typeSpec.eq))
|
|
266
266
|
return;
|
|
267
267
|
// Check for union type (oneOf)
|
|
268
268
|
if (typeSpec.properties) {
|
|
269
269
|
const oneOf = typeSpec.properties["oneOf"];
|
|
270
|
-
if (oneOf !== undefined && !(0,
|
|
270
|
+
if (oneOf !== undefined && !(0, types_1.isRef)(oneOf.eq)) {
|
|
271
271
|
validateUnion(value, oneOf, types, path, errors);
|
|
272
272
|
return;
|
|
273
273
|
}
|
|
@@ -275,14 +275,14 @@ function validateValueType(value, typeSpec, types, path, errors) {
|
|
|
275
275
|
// Check for enum (eq) or pattern (matches)
|
|
276
276
|
if (typeSpec.properties) {
|
|
277
277
|
const eqProp = typeSpec.properties["eq"];
|
|
278
|
-
if (eqProp !== undefined && !(0,
|
|
278
|
+
if (eqProp !== undefined && !(0, types_1.isRef)(eqProp.eq)) {
|
|
279
279
|
if (Array.isArray(eqProp.eq)) {
|
|
280
280
|
validateEnum(value, eqProp.eq, path, errors);
|
|
281
281
|
return;
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
const matchesProp = typeSpec.properties["matches"];
|
|
285
|
-
if (matchesProp !== undefined && !(0,
|
|
285
|
+
if (matchesProp !== undefined && !(0, types_1.isRef)(matchesProp.eq)) {
|
|
286
286
|
const baseType = getEqString(typeSpec);
|
|
287
287
|
if (baseType !== undefined) {
|
|
288
288
|
validateBaseType(value, baseType, types, path, errors);
|
|
@@ -299,7 +299,7 @@ function validateValueType(value, typeSpec, types, path, errors) {
|
|
|
299
299
|
("Required" in typeSpec.properties ||
|
|
300
300
|
"Optional" in typeSpec.properties ||
|
|
301
301
|
"Additional" in typeSpec.properties)) {
|
|
302
|
-
if ((0,
|
|
302
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
303
303
|
errors.push({
|
|
304
304
|
message: "Expected a tag but found a link",
|
|
305
305
|
path: [...path],
|
|
@@ -368,7 +368,7 @@ function validateBaseType(value, typeName, types, path, errors) {
|
|
|
368
368
|
}
|
|
369
369
|
}
|
|
370
370
|
function validateTypeString(value, path, errors) {
|
|
371
|
-
if ((0,
|
|
371
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
372
372
|
errors.push({
|
|
373
373
|
message: 'Expected type "string" but found a link',
|
|
374
374
|
path: [...path],
|
|
@@ -385,7 +385,7 @@ function validateTypeString(value, path, errors) {
|
|
|
385
385
|
}
|
|
386
386
|
}
|
|
387
387
|
function validateTypeNumber(value, path, errors) {
|
|
388
|
-
if ((0,
|
|
388
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
389
389
|
errors.push({
|
|
390
390
|
message: 'Expected type "number" but found a link',
|
|
391
391
|
path: [...path],
|
|
@@ -402,7 +402,7 @@ function validateTypeNumber(value, path, errors) {
|
|
|
402
402
|
}
|
|
403
403
|
}
|
|
404
404
|
function validateTypeBoolean(value, path, errors) {
|
|
405
|
-
if ((0,
|
|
405
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
406
406
|
errors.push({
|
|
407
407
|
message: 'Expected type "boolean" but found a link',
|
|
408
408
|
path: [...path],
|
|
@@ -419,7 +419,7 @@ function validateTypeBoolean(value, path, errors) {
|
|
|
419
419
|
}
|
|
420
420
|
}
|
|
421
421
|
function validateTypeDate(value, path, errors) {
|
|
422
|
-
if ((0,
|
|
422
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
423
423
|
errors.push({
|
|
424
424
|
message: 'Expected type "date" but found a link',
|
|
425
425
|
path: [...path],
|
|
@@ -436,7 +436,7 @@ function validateTypeDate(value, path, errors) {
|
|
|
436
436
|
}
|
|
437
437
|
}
|
|
438
438
|
function validateTypeTag(value, path, errors) {
|
|
439
|
-
if ((0,
|
|
439
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
440
440
|
errors.push({
|
|
441
441
|
message: 'Expected type "tag" but found a link',
|
|
442
442
|
path: [...path],
|
|
@@ -445,7 +445,7 @@ function validateTypeTag(value, path, errors) {
|
|
|
445
445
|
}
|
|
446
446
|
}
|
|
447
447
|
function validateTypeFlag(value, path, errors) {
|
|
448
|
-
if ((0,
|
|
448
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
449
449
|
errors.push({
|
|
450
450
|
message: 'Expected type "flag" but found a link',
|
|
451
451
|
path: [...path],
|
|
@@ -454,7 +454,7 @@ function validateTypeFlag(value, path, errors) {
|
|
|
454
454
|
}
|
|
455
455
|
}
|
|
456
456
|
function validateArrayType(value, innerType, types, path, errors) {
|
|
457
|
-
if ((0,
|
|
457
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
458
458
|
errors.push({
|
|
459
459
|
message: `Expected type "${innerType}[]" but found a link`,
|
|
460
460
|
path: [...path],
|
|
@@ -476,7 +476,7 @@ function validateArrayType(value, innerType, types, path, errors) {
|
|
|
476
476
|
}
|
|
477
477
|
}
|
|
478
478
|
function validateEnum(value, allowed, path, errors) {
|
|
479
|
-
if ((0,
|
|
479
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
480
480
|
errors.push({
|
|
481
481
|
message: "Expected an enum value but found a link",
|
|
482
482
|
path: [...path],
|
|
@@ -498,7 +498,7 @@ function validateEnum(value, allowed, path, errors) {
|
|
|
498
498
|
return;
|
|
499
499
|
}
|
|
500
500
|
const matches = allowed.some((a) => {
|
|
501
|
-
if ((0,
|
|
501
|
+
if ((0, types_1.isRef)(a.eq))
|
|
502
502
|
return false;
|
|
503
503
|
const aeq = a.eq;
|
|
504
504
|
if (aeq instanceof Date && nodeEq instanceof Date) {
|
|
@@ -508,7 +508,7 @@ function validateEnum(value, allowed, path, errors) {
|
|
|
508
508
|
});
|
|
509
509
|
if (!matches) {
|
|
510
510
|
const allowedStrs = allowed
|
|
511
|
-
.filter((a) => !(0,
|
|
511
|
+
.filter((a) => !(0, types_1.isRef)(a.eq))
|
|
512
512
|
.map((a) => {
|
|
513
513
|
const aeq = a.eq;
|
|
514
514
|
return JSON.stringify(String(aeq));
|
|
@@ -524,7 +524,7 @@ function validatePattern(value, matchesNode, path, errors) {
|
|
|
524
524
|
const pattern = getEqString(matchesNode);
|
|
525
525
|
if (pattern === undefined)
|
|
526
526
|
return;
|
|
527
|
-
if ((0,
|
|
527
|
+
if ((0, types_1.isRef)(value.eq)) {
|
|
528
528
|
errors.push({
|
|
529
529
|
message: "Expected a value matching a pattern but found a link",
|
|
530
530
|
path: [...path],
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/motly-ts-parser",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "MOTLY text to wire format parser — pure TypeScript",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"main": "build/index.js",
|
|
7
|
-
"types": "build/index.d.ts",
|
|
6
|
+
"main": "build/parser/src/index.js",
|
|
7
|
+
"types": "build/parser/src/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
9
|
"build/"
|
|
10
10
|
],
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^25.2.2",
|
|
28
|
-
"motly-ts-interface": "file:../interface",
|
|
29
28
|
"typescript": "^5.0.0"
|
|
30
29
|
}
|
|
31
30
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|