@true-sight/model-schema 1.0.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.
Files changed (68) hide show
  1. package/dist/constants.d.ts +1 -0
  2. package/dist/constants.js +4 -0
  3. package/dist/dsl/compile/compile-explore.d.ts +4 -0
  4. package/dist/dsl/compile/compile-explore.js +60 -0
  5. package/dist/dsl/compile/compile-model.d.ts +4 -0
  6. package/dist/dsl/compile/compile-model.js +39 -0
  7. package/dist/dsl/compile/compile-view.d.ts +2 -0
  8. package/dist/dsl/compile/compile-view.js +56 -0
  9. package/dist/dsl/compile/index.d.ts +3 -0
  10. package/dist/dsl/compile/index.js +10 -0
  11. package/dist/dsl/compile/join-helpers.d.ts +5 -0
  12. package/dist/dsl/compile/join-helpers.js +88 -0
  13. package/dist/dsl/decorators/dimension.decorator.d.ts +2 -0
  14. package/dist/dsl/decorators/dimension.decorator.js +12 -0
  15. package/dist/dsl/decorators/explore.decorator.d.ts +2 -0
  16. package/dist/dsl/decorators/explore.decorator.js +9 -0
  17. package/dist/dsl/decorators/index.d.ts +7 -0
  18. package/dist/dsl/decorators/index.js +18 -0
  19. package/dist/dsl/decorators/join.decorator.d.ts +2 -0
  20. package/dist/dsl/decorators/join.decorator.js +12 -0
  21. package/dist/dsl/decorators/measure.decorator.d.ts +2 -0
  22. package/dist/dsl/decorators/measure.decorator.js +12 -0
  23. package/dist/dsl/decorators/model.decorator.d.ts +2 -0
  24. package/dist/dsl/decorators/model.decorator.js +9 -0
  25. package/dist/dsl/decorators/view.decorator.d.ts +4 -0
  26. package/dist/dsl/decorators/view.decorator.js +20 -0
  27. package/dist/dsl/errors/compile-errors.d.ts +12 -0
  28. package/dist/dsl/errors/compile-errors.js +33 -0
  29. package/dist/dsl/expr/aggregates.d.ts +6 -0
  30. package/dist/dsl/expr/aggregates.js +21 -0
  31. package/dist/dsl/expr/field.d.ts +15 -0
  32. package/dist/dsl/expr/field.js +44 -0
  33. package/dist/dsl/expr/index.d.ts +4 -0
  34. package/dist/dsl/expr/index.js +16 -0
  35. package/dist/dsl/expr/join-scope.d.ts +5 -0
  36. package/dist/dsl/expr/join-scope.js +23 -0
  37. package/dist/dsl/expr/raw.d.ts +2 -0
  38. package/dist/dsl/expr/raw.js +6 -0
  39. package/dist/dsl/registry/explore-registry.d.ts +22 -0
  40. package/dist/dsl/registry/explore-registry.js +22 -0
  41. package/dist/dsl/registry/model-registry.d.ts +9 -0
  42. package/dist/dsl/registry/model-registry.js +11 -0
  43. package/dist/dsl/registry/view-registry.d.ts +32 -0
  44. package/dist/dsl/registry/view-registry.js +42 -0
  45. package/dist/dsl/types/join-scope.types.d.ts +9 -0
  46. package/dist/dsl/types/join-scope.types.js +8 -0
  47. package/dist/dsl/types/view-name-map.types.d.ts +13 -0
  48. package/dist/dsl/types/view-name-map.types.js +2 -0
  49. package/dist/dsl/types/view-proxy.types.d.ts +13 -0
  50. package/dist/dsl/types/view-proxy.types.js +2 -0
  51. package/dist/index.d.ts +13 -0
  52. package/dist/index.js +39 -0
  53. package/dist/types/manifest-expr.types.d.ts +37 -0
  54. package/dist/types/manifest-expr.types.js +26 -0
  55. package/dist/types/manifest.types.d.ts +54 -0
  56. package/dist/types/manifest.types.js +2 -0
  57. package/dist/validate/expr-semantic.d.ts +6 -0
  58. package/dist/validate/expr-semantic.js +117 -0
  59. package/dist/validate/semantic-rules.d.ts +3 -0
  60. package/dist/validate/semantic-rules.js +68 -0
  61. package/dist/validate/structural.d.ts +2 -0
  62. package/dist/validate/structural.js +27 -0
  63. package/dist/validate/validate-manifest.d.ts +2 -0
  64. package/dist/validate/validate-manifest.js +16 -0
  65. package/dist/validate/validation-result.d.ts +10 -0
  66. package/dist/validate/validation-result.js +2 -0
  67. package/manifest.schema.json +207 -0
  68. package/package.json +47 -0
@@ -0,0 +1,22 @@
1
+ import type { ManifestExpr } from '../../types/manifest-expr.types.js';
2
+ import type { JoinRelationship, JoinType } from '../../types/manifest.types.js';
3
+ export type ViewConstructor = new (...args: unknown[]) => object;
4
+ export type ExploreOptions = {
5
+ name: string;
6
+ label: string;
7
+ from: ViewConstructor;
8
+ };
9
+ export type JoinScope = Record<string, unknown>;
10
+ export type JoinOptions = {
11
+ relationship: JoinRelationship;
12
+ type: JoinType;
13
+ sqlOn: (scope: JoinScope) => ManifestExpr;
14
+ };
15
+ export type JoinEntry = {
16
+ propertyKey: string;
17
+ options: JoinOptions;
18
+ };
19
+ export declare function registerExplore(ctor: object, options: ExploreOptions): void;
20
+ export declare function getExploreMeta(ctor: object): ExploreOptions | undefined;
21
+ export declare function addJoin(prototype: object, entry: JoinEntry): void;
22
+ export declare function getJoins(prototype: object): JoinEntry[];
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerExplore = registerExplore;
4
+ exports.getExploreMeta = getExploreMeta;
5
+ exports.addJoin = addJoin;
6
+ exports.getJoins = getJoins;
7
+ const exploreMeta = new WeakMap();
8
+ const joinMeta = new WeakMap();
9
+ function registerExplore(ctor, options) {
10
+ exploreMeta.set(ctor, options);
11
+ }
12
+ function getExploreMeta(ctor) {
13
+ return exploreMeta.get(ctor);
14
+ }
15
+ function addJoin(prototype, entry) {
16
+ const existing = joinMeta.get(prototype) ?? [];
17
+ existing.push(entry);
18
+ joinMeta.set(prototype, existing);
19
+ }
20
+ function getJoins(prototype) {
21
+ return joinMeta.get(prototype) ?? [];
22
+ }
@@ -0,0 +1,9 @@
1
+ import type { ViewConstructor } from './explore-registry.js';
2
+ export type ModelOptions = {
3
+ name: string;
4
+ label: string;
5
+ connection: string;
6
+ explores: ViewConstructor[];
7
+ };
8
+ export declare function registerModel(ctor: object, options: ModelOptions): void;
9
+ export declare function getModelMeta(ctor: object): ModelOptions | undefined;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerModel = registerModel;
4
+ exports.getModelMeta = getModelMeta;
5
+ const modelMeta = new WeakMap();
6
+ function registerModel(ctor, options) {
7
+ modelMeta.set(ctor, options);
8
+ }
9
+ function getModelMeta(ctor) {
10
+ return modelMeta.get(ctor);
11
+ }
@@ -0,0 +1,32 @@
1
+ import type { AggregateType, DimensionType } from '../../types/manifest.types.js';
2
+ export type ViewOptions = {
3
+ name: string;
4
+ label: string;
5
+ table: string;
6
+ };
7
+ export type DimensionOptions = {
8
+ groupLabel: string;
9
+ label: string;
10
+ type: DimensionType;
11
+ };
12
+ export type MeasureOptions = {
13
+ groupLabel: string;
14
+ label: string;
15
+ type: AggregateType;
16
+ };
17
+ export type DimensionEntry = {
18
+ propertyKey: string;
19
+ options: DimensionOptions;
20
+ };
21
+ export type MeasureEntry = {
22
+ propertyKey: string;
23
+ options: MeasureOptions;
24
+ };
25
+ export declare function registerView(ctor: object, options: ViewOptions): void;
26
+ export declare function getViewMeta(ctor: object): ViewOptions | undefined;
27
+ export declare function getViewName(ctor: object): string | undefined;
28
+ export declare function setViewNameBrand(ctor: object, name: string): void;
29
+ export declare function addDimension(prototype: object, entry: DimensionEntry): void;
30
+ export declare function getDimensions(prototype: object): DimensionEntry[];
31
+ export declare function addMeasure(prototype: object, entry: MeasureEntry): void;
32
+ export declare function getMeasures(prototype: object): MeasureEntry[];
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerView = registerView;
4
+ exports.getViewMeta = getViewMeta;
5
+ exports.getViewName = getViewName;
6
+ exports.setViewNameBrand = setViewNameBrand;
7
+ exports.addDimension = addDimension;
8
+ exports.getDimensions = getDimensions;
9
+ exports.addMeasure = addMeasure;
10
+ exports.getMeasures = getMeasures;
11
+ const viewMeta = new WeakMap();
12
+ const dimensionMeta = new WeakMap();
13
+ const measureMeta = new WeakMap();
14
+ function registerView(ctor, options) {
15
+ viewMeta.set(ctor, options);
16
+ }
17
+ function getViewMeta(ctor) {
18
+ return viewMeta.get(ctor);
19
+ }
20
+ function getViewName(ctor) {
21
+ return getViewMeta(ctor)?.name;
22
+ }
23
+ function setViewNameBrand(ctor, name) {
24
+ ctor.__viewName = name;
25
+ }
26
+ function appendEntry(map, target, entry) {
27
+ const existing = map.get(target) ?? [];
28
+ existing.push(entry);
29
+ map.set(target, existing);
30
+ }
31
+ function addDimension(prototype, entry) {
32
+ appendEntry(dimensionMeta, prototype, entry);
33
+ }
34
+ function getDimensions(prototype) {
35
+ return dimensionMeta.get(prototype) ?? [];
36
+ }
37
+ function addMeasure(prototype, entry) {
38
+ appendEntry(measureMeta, prototype, entry);
39
+ }
40
+ function getMeasures(prototype) {
41
+ return measureMeta.get(prototype) ?? [];
42
+ }
@@ -0,0 +1,9 @@
1
+ import type { ManifestExpr } from '../../types/manifest-expr.types.js';
2
+ import type { JoinScopeProxy } from './view-name-map.types.js';
3
+ export type JoinScopeCallback = (...proxies: JoinScopeProxy[]) => ManifestExpr;
4
+ export type JoinScopeSqlOn = (scope: Record<string, unknown>) => ManifestExpr;
5
+ export interface JoinScopeTagged {
6
+ readonly __joinScopeBrand: symbol;
7
+ readonly fn: JoinScopeCallback;
8
+ }
9
+ export declare function isJoinScopeTagged(value: unknown): value is JoinScopeTagged;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isJoinScopeTagged = isJoinScopeTagged;
4
+ function isJoinScopeTagged(value) {
5
+ return ((typeof value === 'object' || typeof value === 'function') &&
6
+ value !== null &&
7
+ '__joinScopeBrand' in value);
8
+ }
@@ -0,0 +1,13 @@
1
+ import type { Field } from '../expr/field.js';
2
+ import type { ViewConstructor, ViewProxy } from './view-proxy.types.js';
3
+ /** Augment in consumer repos to map @View({ name }) → view class. */
4
+ export interface ViewNameMap {
5
+ }
6
+ export type ViewProxyByName<N extends string> = N extends keyof ViewNameMap & string ? ViewProxy<ViewNameMap[N]> : ViewProxy<ViewConstructor>;
7
+ /** Positional join callback proxy — index allows join-only columns. */
8
+ export type JoinScopeProxy = {
9
+ [key: string]: Field<unknown>;
10
+ };
11
+ export type JoinScopeProxies<Names extends readonly string[]> = {
12
+ [I in keyof Names]: I extends `${number}` ? ViewProxyByName<Names[I] & string> : never;
13
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ import type { Field } from '../expr/field.js';
2
+ export type ViewConstructor = new (...args: unknown[]) => object;
3
+ export type DimensionKeys<V extends ViewConstructor> = {
4
+ [K in keyof InstanceType<V>]: InstanceType<V>[K] extends Field<infer _> ? K : never;
5
+ }[keyof InstanceType<V>];
6
+ export type ViewProxy<V extends ViewConstructor> = {
7
+ [K in DimensionKeys<V>]: InstanceType<V>[K];
8
+ } & {
9
+ [key: string]: Field<unknown>;
10
+ };
11
+ export interface ViewBrand {
12
+ readonly __viewName?: string;
13
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,13 @@
1
+ export { SCHEMA_VERSION } from './constants.js';
2
+ export type { AggregateKind, AggregateExpr, ComparisonExpr, ComparisonKind, JoinOn, JoinPair, LogicExpr, LogicKind, ManifestExpr, ManifestExprObject, NotExpr, RawExpr, RefString, } from './types/manifest-expr.types.js';
3
+ export { isJoinPair, isManifestExprObject, isRefString, REF_STRING_PATTERN, } from './types/manifest-expr.types.js';
4
+ export type { AggregateType, DimensionDefinition, DimensionType, Explore as ManifestExplore, ExploreJoin, JoinRelationship, JoinType, MeasurementDefinition, Model as ManifestModel, ModelManifest, ViewDefinition, } from './types/manifest.types.js';
5
+ export type { ManifestValidationError, ValidationResult, } from './validate/validation-result.js';
6
+ export { validateManifest } from './validate/validate-manifest.js';
7
+ export { Field, field, count, sum, min, max, raw, joinScope, isJoinScopeTagged } from './dsl/expr/index.js';
8
+ export type { JoinScopeCallback, JoinScopeSqlOn, JoinScopeTagged } from './dsl/types/join-scope.types.js';
9
+ export { View, Dimension, Measure, Explore, Join, Model } from './dsl/decorators/index.js';
10
+ export type { ViewProxy, ViewConstructor } from './dsl/types/view-proxy.types.js';
11
+ export type { ViewNameMap, ViewProxyByName, } from './dsl/types/view-name-map.types.js';
12
+ export { compileView, compileExplore, compileModel, compileModels } from './dsl/compile/index.js';
13
+ export { MissingMetadataError, InvalidMeasureError, JoinScopeError, DuplicateNameError, } from './dsl/errors/compile-errors.js';
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DuplicateNameError = exports.JoinScopeError = exports.InvalidMeasureError = exports.MissingMetadataError = exports.compileModels = exports.compileModel = exports.compileExplore = exports.compileView = exports.Model = exports.Join = exports.Explore = exports.Measure = exports.Dimension = exports.View = exports.isJoinScopeTagged = exports.joinScope = exports.raw = exports.max = exports.min = exports.sum = exports.count = exports.field = exports.Field = exports.validateManifest = exports.REF_STRING_PATTERN = exports.isRefString = exports.isManifestExprObject = exports.isJoinPair = exports.SCHEMA_VERSION = void 0;
4
+ var constants_js_1 = require("./constants.js");
5
+ Object.defineProperty(exports, "SCHEMA_VERSION", { enumerable: true, get: function () { return constants_js_1.SCHEMA_VERSION; } });
6
+ var manifest_expr_types_js_1 = require("./types/manifest-expr.types.js");
7
+ Object.defineProperty(exports, "isJoinPair", { enumerable: true, get: function () { return manifest_expr_types_js_1.isJoinPair; } });
8
+ Object.defineProperty(exports, "isManifestExprObject", { enumerable: true, get: function () { return manifest_expr_types_js_1.isManifestExprObject; } });
9
+ Object.defineProperty(exports, "isRefString", { enumerable: true, get: function () { return manifest_expr_types_js_1.isRefString; } });
10
+ Object.defineProperty(exports, "REF_STRING_PATTERN", { enumerable: true, get: function () { return manifest_expr_types_js_1.REF_STRING_PATTERN; } });
11
+ var validate_manifest_js_1 = require("./validate/validate-manifest.js");
12
+ Object.defineProperty(exports, "validateManifest", { enumerable: true, get: function () { return validate_manifest_js_1.validateManifest; } });
13
+ var index_js_1 = require("./dsl/expr/index.js");
14
+ Object.defineProperty(exports, "Field", { enumerable: true, get: function () { return index_js_1.Field; } });
15
+ Object.defineProperty(exports, "field", { enumerable: true, get: function () { return index_js_1.field; } });
16
+ Object.defineProperty(exports, "count", { enumerable: true, get: function () { return index_js_1.count; } });
17
+ Object.defineProperty(exports, "sum", { enumerable: true, get: function () { return index_js_1.sum; } });
18
+ Object.defineProperty(exports, "min", { enumerable: true, get: function () { return index_js_1.min; } });
19
+ Object.defineProperty(exports, "max", { enumerable: true, get: function () { return index_js_1.max; } });
20
+ Object.defineProperty(exports, "raw", { enumerable: true, get: function () { return index_js_1.raw; } });
21
+ Object.defineProperty(exports, "joinScope", { enumerable: true, get: function () { return index_js_1.joinScope; } });
22
+ Object.defineProperty(exports, "isJoinScopeTagged", { enumerable: true, get: function () { return index_js_1.isJoinScopeTagged; } });
23
+ var index_js_2 = require("./dsl/decorators/index.js");
24
+ Object.defineProperty(exports, "View", { enumerable: true, get: function () { return index_js_2.View; } });
25
+ Object.defineProperty(exports, "Dimension", { enumerable: true, get: function () { return index_js_2.Dimension; } });
26
+ Object.defineProperty(exports, "Measure", { enumerable: true, get: function () { return index_js_2.Measure; } });
27
+ Object.defineProperty(exports, "Explore", { enumerable: true, get: function () { return index_js_2.Explore; } });
28
+ Object.defineProperty(exports, "Join", { enumerable: true, get: function () { return index_js_2.Join; } });
29
+ Object.defineProperty(exports, "Model", { enumerable: true, get: function () { return index_js_2.Model; } });
30
+ var index_js_3 = require("./dsl/compile/index.js");
31
+ Object.defineProperty(exports, "compileView", { enumerable: true, get: function () { return index_js_3.compileView; } });
32
+ Object.defineProperty(exports, "compileExplore", { enumerable: true, get: function () { return index_js_3.compileExplore; } });
33
+ Object.defineProperty(exports, "compileModel", { enumerable: true, get: function () { return index_js_3.compileModel; } });
34
+ Object.defineProperty(exports, "compileModels", { enumerable: true, get: function () { return index_js_3.compileModels; } });
35
+ var compile_errors_js_1 = require("./dsl/errors/compile-errors.js");
36
+ Object.defineProperty(exports, "MissingMetadataError", { enumerable: true, get: function () { return compile_errors_js_1.MissingMetadataError; } });
37
+ Object.defineProperty(exports, "InvalidMeasureError", { enumerable: true, get: function () { return compile_errors_js_1.InvalidMeasureError; } });
38
+ Object.defineProperty(exports, "JoinScopeError", { enumerable: true, get: function () { return compile_errors_js_1.JoinScopeError; } });
39
+ Object.defineProperty(exports, "DuplicateNameError", { enumerable: true, get: function () { return compile_errors_js_1.DuplicateNameError; } });
@@ -0,0 +1,37 @@
1
+ export declare const REF_STRING_PATTERN: RegExp;
2
+ export type RefString = `${string}.${string}`;
3
+ export type ComparisonKind = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte';
4
+ export type LogicKind = 'and' | 'or';
5
+ export type AggregateKind = 'count' | 'sum' | 'min' | 'max';
6
+ export type RawExpr = {
7
+ kind: 'raw';
8
+ sql: string;
9
+ };
10
+ export type ComparisonExpr = {
11
+ kind: ComparisonKind;
12
+ left: ManifestExpr;
13
+ right: ManifestExpr;
14
+ };
15
+ export type LogicExpr = {
16
+ kind: LogicKind;
17
+ left: ManifestExpr;
18
+ right: ManifestExpr;
19
+ };
20
+ export type NotExpr = {
21
+ kind: 'not';
22
+ operand: ManifestExpr;
23
+ };
24
+ export type AggregateExpr = {
25
+ kind: 'aggregate';
26
+ fn: AggregateKind;
27
+ operand: ManifestExpr;
28
+ };
29
+ export type ManifestExprObject = RawExpr | ComparisonExpr | LogicExpr | NotExpr | AggregateExpr;
30
+ export type ManifestExpr = RefString | ManifestExprObject;
31
+ export type JoinPair = {
32
+ pair: [string, string];
33
+ };
34
+ export type JoinOn = JoinPair | ManifestExpr;
35
+ export declare function isRefString(value: unknown): value is RefString;
36
+ export declare function isManifestExprObject(value: unknown): value is ManifestExprObject;
37
+ export declare function isJoinPair(value: unknown): value is JoinPair;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.REF_STRING_PATTERN = void 0;
4
+ exports.isRefString = isRefString;
5
+ exports.isManifestExprObject = isManifestExprObject;
6
+ exports.isJoinPair = isJoinPair;
7
+ exports.REF_STRING_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*\.[a-zA-Z_][a-zA-Z0-9_]*$/;
8
+ function isRefString(value) {
9
+ return typeof value === 'string' && exports.REF_STRING_PATTERN.test(value);
10
+ }
11
+ function isManifestExprObject(value) {
12
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
13
+ return false;
14
+ }
15
+ return 'kind' in value && typeof value.kind === 'string';
16
+ }
17
+ function isJoinPair(value) {
18
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
19
+ return false;
20
+ }
21
+ const pair = value.pair;
22
+ return (Array.isArray(pair) &&
23
+ pair.length === 2 &&
24
+ typeof pair[0] === 'string' &&
25
+ typeof pair[1] === 'string');
26
+ }
@@ -0,0 +1,54 @@
1
+ import type { JoinOn, ManifestExpr } from './manifest-expr.types.js';
2
+ export type DimensionType = 'integer' | 'string' | 'date' | 'datetime' | 'boolean';
3
+ export type AggregateType = 'sum' | 'count' | 'min' | 'max';
4
+ export type JoinType = 'inner' | 'left' | 'right' | 'full';
5
+ export type JoinRelationship = 'one_to_one' | 'one_to_many' | 'many_to_one' | 'many_to_many';
6
+ export interface ExploreJoin {
7
+ name: string;
8
+ fromView: string;
9
+ on: JoinOn;
10
+ type: JoinType;
11
+ relationship: JoinRelationship;
12
+ }
13
+ export interface DimensionDefinition {
14
+ groupLabel: string;
15
+ name: string;
16
+ label: string;
17
+ type: DimensionType;
18
+ expression: ManifestExpr;
19
+ }
20
+ export interface MeasurementDefinition {
21
+ groupLabel: string;
22
+ name: string;
23
+ label: string;
24
+ type: AggregateType;
25
+ expression: ManifestExpr;
26
+ }
27
+ export interface ViewDefinition {
28
+ name: string;
29
+ label: string;
30
+ sql: {
31
+ tableName: string;
32
+ };
33
+ dimensions: DimensionDefinition[];
34
+ measurements: MeasurementDefinition[];
35
+ }
36
+ export interface Explore {
37
+ name: string;
38
+ label: string;
39
+ from: string;
40
+ joins: ExploreJoin[];
41
+ views: ViewDefinition[];
42
+ }
43
+ export interface Model {
44
+ name: string;
45
+ label: string;
46
+ connectionName: string;
47
+ explores: Explore[];
48
+ }
49
+ export interface ModelManifest {
50
+ schemaVersion: '1.1';
51
+ generatedAt: string;
52
+ sourceCommit?: string;
53
+ models: Model[];
54
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import type { AggregateType } from '../types/manifest.types.js';
2
+ import type { JoinOn, ManifestExpr } from '../types/manifest-expr.types.js';
3
+ import type { ManifestValidationError } from './validation-result.js';
4
+ export declare function validateDimensionExpression(expression: ManifestExpr, viewNames: Set<string>, path: string): ManifestValidationError[];
5
+ export declare function validateMeasurementExpression(expression: ManifestExpr, expectedType: AggregateType, viewNames: Set<string>, path: string): ManifestValidationError[];
6
+ export declare function validateJoinOn(on: JoinOn, viewNames: Set<string>, fromView: string, joinFromView: string, path: string): ManifestValidationError[];
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateDimensionExpression = validateDimensionExpression;
4
+ exports.validateMeasurementExpression = validateMeasurementExpression;
5
+ exports.validateJoinOn = validateJoinOn;
6
+ const manifest_expr_types_js_1 = require("../types/manifest-expr.types.js");
7
+ function refViewName(ref) {
8
+ return ref.split('.')[0] ?? '';
9
+ }
10
+ function validateRefInViews(ref, viewNames, path, errors) {
11
+ const viewName = refViewName(ref);
12
+ if (!viewNames.has(viewName)) {
13
+ errors.push({
14
+ path,
15
+ message: `expression references unknown view "${viewName}"`,
16
+ });
17
+ }
18
+ }
19
+ function collectExprSemanticErrors(expr, viewNames, path, errors, allowRaw) {
20
+ if ((0, manifest_expr_types_js_1.isRefString)(expr)) {
21
+ validateRefInViews(expr, viewNames, path, errors);
22
+ return;
23
+ }
24
+ if (!(0, manifest_expr_types_js_1.isManifestExprObject)(expr)) {
25
+ errors.push({ path, message: 'invalid expression' });
26
+ return;
27
+ }
28
+ switch (expr.kind) {
29
+ case 'raw':
30
+ if (!allowRaw) {
31
+ errors.push({ path, message: 'raw expressions are not allowed here' });
32
+ }
33
+ return;
34
+ case 'not':
35
+ collectExprSemanticErrors(expr.operand, viewNames, `${path}.operand`, errors, allowRaw);
36
+ return;
37
+ case 'aggregate':
38
+ collectExprSemanticErrors(expr.operand, viewNames, `${path}.operand`, errors, false);
39
+ return;
40
+ case 'eq':
41
+ case 'neq':
42
+ case 'gt':
43
+ case 'gte':
44
+ case 'lt':
45
+ case 'lte':
46
+ case 'and':
47
+ case 'or':
48
+ collectExprSemanticErrors(expr.left, viewNames, `${path}.left`, errors, allowRaw);
49
+ collectExprSemanticErrors(expr.right, viewNames, `${path}.right`, errors, allowRaw);
50
+ return;
51
+ default: {
52
+ const _exhaustive = expr;
53
+ errors.push({ path, message: `unknown expression kind: ${_exhaustive.kind}` });
54
+ }
55
+ }
56
+ }
57
+ function validateDimensionExpression(expression, viewNames, path) {
58
+ const errors = [];
59
+ if (!(0, manifest_expr_types_js_1.isRefString)(expression)) {
60
+ errors.push({
61
+ path,
62
+ message: 'dimension expression must be a view.field ref string',
63
+ });
64
+ return errors;
65
+ }
66
+ validateRefInViews(expression, viewNames, path, errors);
67
+ return errors;
68
+ }
69
+ function validateMeasurementExpression(expression, expectedType, viewNames, path) {
70
+ const errors = [];
71
+ if (!(0, manifest_expr_types_js_1.isManifestExprObject)(expression) || expression.kind !== 'aggregate') {
72
+ errors.push({
73
+ path,
74
+ message: 'measurement expression must be an aggregate node',
75
+ });
76
+ return errors;
77
+ }
78
+ if (expression.fn !== expectedType) {
79
+ errors.push({
80
+ path: `${path}.fn`,
81
+ message: `aggregate fn "${expression.fn}" does not match measurement type "${expectedType}"`,
82
+ });
83
+ }
84
+ if (!(0, manifest_expr_types_js_1.isRefString)(expression.operand)) {
85
+ errors.push({
86
+ path: `${path}.operand`,
87
+ message: 'measurement aggregate operand must be a view.field ref string',
88
+ });
89
+ }
90
+ else {
91
+ validateRefInViews(expression.operand, viewNames, `${path}.operand`, errors);
92
+ }
93
+ return errors;
94
+ }
95
+ function validateJoinOn(on, viewNames, fromView, joinFromView, path) {
96
+ const errors = [];
97
+ if ((0, manifest_expr_types_js_1.isJoinPair)(on)) {
98
+ if (on.pair[0].trim().length === 0 || on.pair[1].trim().length === 0) {
99
+ errors.push({ path: `${path}.pair`, message: 'pair fields must not be empty' });
100
+ }
101
+ if (!viewNames.has(fromView)) {
102
+ errors.push({
103
+ path,
104
+ message: `pair join references unknown from view "${fromView}"`,
105
+ });
106
+ }
107
+ if (!viewNames.has(joinFromView)) {
108
+ errors.push({
109
+ path,
110
+ message: `pair join references unknown joined view "${joinFromView}"`,
111
+ });
112
+ }
113
+ return errors;
114
+ }
115
+ collectExprSemanticErrors(on, viewNames, path, errors, true);
116
+ return errors;
117
+ }
@@ -0,0 +1,3 @@
1
+ import type { ModelManifest } from '../types/manifest.types.js';
2
+ import type { ManifestValidationError } from './validation-result.js';
3
+ export declare function collectSemanticErrors(manifest: ModelManifest): ManifestValidationError[];
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.collectSemanticErrors = collectSemanticErrors;
4
+ const expr_semantic_js_1 = require("./expr-semantic.js");
5
+ function duplicateNameErrors(names, pathPrefix, entityLabel) {
6
+ const seen = new Map();
7
+ const errors = [];
8
+ names.forEach((name, index) => {
9
+ if (seen.has(name)) {
10
+ errors.push({
11
+ path: `${pathPrefix}[${index}].name`,
12
+ message: `duplicate ${entityLabel} name: ${name}`,
13
+ });
14
+ }
15
+ else {
16
+ seen.set(name, index);
17
+ }
18
+ });
19
+ return errors;
20
+ }
21
+ function collectSemanticErrors(manifest) {
22
+ const errors = [];
23
+ if (manifest.models.length === 0) {
24
+ errors.push({ path: 'models', message: 'models must not be empty' });
25
+ return errors;
26
+ }
27
+ errors.push(...duplicateNameErrors(manifest.models.map((model) => model.name), 'models', 'model'));
28
+ manifest.models.forEach((model, modelIndex) => {
29
+ const modelPath = `models[${modelIndex}]`;
30
+ if (model.connectionName.trim().length === 0) {
31
+ errors.push({
32
+ path: `${modelPath}.connectionName`,
33
+ message: 'connectionName must not be empty',
34
+ });
35
+ }
36
+ errors.push(...duplicateNameErrors(model.explores.map((explore) => explore.name), `${modelPath}.explores`, 'explore'));
37
+ model.explores.forEach((explore, exploreIndex) => {
38
+ const explorePath = `${modelPath}.explores[${exploreIndex}]`;
39
+ const viewNames = new Set(explore.views.map((view) => view.name));
40
+ if (!viewNames.has(explore.from)) {
41
+ errors.push({
42
+ path: `${explorePath}.from`,
43
+ message: `from view "${explore.from}" is not in explore views`,
44
+ });
45
+ }
46
+ explore.joins.forEach((join, joinIndex) => {
47
+ if (!viewNames.has(join.fromView)) {
48
+ errors.push({
49
+ path: `${explorePath}.joins[${joinIndex}].fromView`,
50
+ message: `join fromView "${join.fromView}" is not in explore views`,
51
+ });
52
+ }
53
+ errors.push(...(0, expr_semantic_js_1.validateJoinOn)(join.on, viewNames, explore.from, join.fromView, `${explorePath}.joins[${joinIndex}].on`));
54
+ });
55
+ explore.views.forEach((view, viewIndex) => {
56
+ const viewPath = `${explorePath}.views[${viewIndex}]`;
57
+ errors.push(...duplicateNameErrors(view.dimensions.map((dimension) => dimension.name), `${viewPath}.dimensions`, 'dimension'), ...duplicateNameErrors(view.measurements.map((measurement) => measurement.name), `${viewPath}.measurements`, 'measurement'));
58
+ view.dimensions.forEach((dimension, dimensionIndex) => {
59
+ errors.push(...(0, expr_semantic_js_1.validateDimensionExpression)(dimension.expression, viewNames, `${viewPath}.dimensions[${dimensionIndex}].expression`));
60
+ });
61
+ view.measurements.forEach((measurement, measurementIndex) => {
62
+ errors.push(...(0, expr_semantic_js_1.validateMeasurementExpression)(measurement.expression, measurement.type, viewNames, `${viewPath}.measurements[${measurementIndex}].expression`));
63
+ });
64
+ });
65
+ });
66
+ });
67
+ return errors;
68
+ }
@@ -0,0 +1,2 @@
1
+ import type { ValidationResult } from './validation-result.js';
2
+ export declare function validateStructure(input: unknown): ValidationResult;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.validateStructure = validateStructure;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const ajv_1 = __importDefault(require("ajv"));
10
+ const manifestSchema = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)((0, node_path_1.dirname)(__filename), '../../manifest.schema.json'), 'utf-8'));
11
+ const ajv = new ajv_1.default({ allErrors: true, strict: false });
12
+ const validateJson = ajv.compile(manifestSchema);
13
+ function mapAjvError(error) {
14
+ const path = error.instancePath.replace(/^\//, '').replace(/\//g, '.');
15
+ const prefix = path.length > 0 ? `${path}: ` : '';
16
+ return { path, message: `${prefix}${error.message ?? 'invalid value'}`.trim() };
17
+ }
18
+ function validateStructure(input) {
19
+ if (input === null || typeof input !== 'object' || Array.isArray(input)) {
20
+ return { ok: false, errors: [{ path: '', message: 'expected object' }] };
21
+ }
22
+ if (!validateJson(input)) {
23
+ const errors = (validateJson.errors ?? []).map(mapAjvError);
24
+ return { ok: false, errors: errors.length > 0 ? errors : [{ path: '', message: 'invalid manifest' }] };
25
+ }
26
+ return { ok: true };
27
+ }
@@ -0,0 +1,2 @@
1
+ import type { ValidationResult } from './validation-result.js';
2
+ export declare function validateManifest(input: unknown): ValidationResult;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateManifest = validateManifest;
4
+ const semantic_rules_js_1 = require("./semantic-rules.js");
5
+ const structural_js_1 = require("./structural.js");
6
+ function validateManifest(input) {
7
+ const structural = (0, structural_js_1.validateStructure)(input);
8
+ if (!structural.ok) {
9
+ return structural;
10
+ }
11
+ const semanticErrors = (0, semantic_rules_js_1.collectSemanticErrors)(input);
12
+ if (semanticErrors.length > 0) {
13
+ return { ok: false, errors: semanticErrors };
14
+ }
15
+ return { ok: true };
16
+ }
@@ -0,0 +1,10 @@
1
+ export type ManifestValidationError = {
2
+ path: string;
3
+ message: string;
4
+ };
5
+ export type ValidationResult = {
6
+ ok: true;
7
+ } | {
8
+ ok: false;
9
+ errors: ManifestValidationError[];
10
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });