@uwdata/mosaic-spec 0.10.0 → 0.11.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/dist/mosaic-schema.json +17 -0
- package/dist/mosaic-spec.js +4287 -13264
- package/dist/mosaic-spec.min.js +33 -42
- package/dist/types/ast/ParamNode.d.ts +1 -2
- package/dist/types/ast/ParamRefNode.d.ts +1 -1
- package/dist/types/ast/SelectionNode.d.ts +15 -5
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/parse-spec.d.ts +33 -8
- package/dist/types/spec/Param.d.ts +6 -0
- package/package.json +6 -6
- package/src/ast/ParamNode.js +3 -4
- package/src/ast/ParamRefNode.js +1 -1
- package/src/ast/SelectionNode.js +46 -14
- package/src/constants.js +1 -0
- package/src/parse-spec.js +53 -16
- package/src/spec/Param.ts +7 -0
- package/src/spec/Spec.ts +1 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
export function parseParam(spec: any, ctx: any): SelectionNode | ParamNode;
|
|
1
|
+
export function parseParam(spec: any, ctx: any): import("./SelectionNode.js").SelectionNode | ParamNode;
|
|
2
2
|
export class ParamNode extends ASTNode {
|
|
3
3
|
value: any;
|
|
4
4
|
date: any;
|
|
5
5
|
instantiate(ctx: any): any;
|
|
6
6
|
codegen(ctx: any): string;
|
|
7
7
|
}
|
|
8
|
-
import { SelectionNode } from './SelectionNode.js';
|
|
9
8
|
import { ASTNode } from './ASTNode.js';
|
|
@@ -1,14 +1,24 @@
|
|
|
1
|
+
export function parseSelection(spec: any, ctx: any): SelectionNode;
|
|
1
2
|
export class SelectionNode extends ASTNode {
|
|
2
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Create a Selection AST node.
|
|
5
|
+
* @param {string} select The selection type.
|
|
6
|
+
* @param {OptionsNode} options Selection options.
|
|
7
|
+
*/
|
|
8
|
+
constructor(select?: string, options?: OptionsNode);
|
|
3
9
|
select: string;
|
|
4
|
-
|
|
5
|
-
empty: any;
|
|
10
|
+
options: OptionsNode;
|
|
6
11
|
instantiate(ctx: any): any;
|
|
7
12
|
codegen(ctx: any): string;
|
|
8
13
|
toJSON(): {
|
|
9
14
|
select: string;
|
|
10
|
-
cross: any;
|
|
11
|
-
empty: any;
|
|
12
15
|
};
|
|
13
16
|
}
|
|
17
|
+
export class IncludeNode extends ASTNode {
|
|
18
|
+
constructor(refs: any);
|
|
19
|
+
refs: any;
|
|
20
|
+
instantiate(ctx: any): any;
|
|
21
|
+
codegen(ctx: any): string;
|
|
22
|
+
}
|
|
14
23
|
import { ASTNode } from './ASTNode.js';
|
|
24
|
+
import { OptionsNode } from './OptionsNode.js';
|
|
@@ -5,6 +5,7 @@ export const OPTIONS: "options";
|
|
|
5
5
|
export const SELECTION: "selection";
|
|
6
6
|
export const PARAMREF: "paramref";
|
|
7
7
|
export const PARAM: "param";
|
|
8
|
+
export const INCLUDE: "include";
|
|
8
9
|
export const SELECT: "select";
|
|
9
10
|
export const VALUE: "value";
|
|
10
11
|
export const CROSSFILTER: "crossfilter";
|
|
@@ -59,15 +59,40 @@ export class ParseContext {
|
|
|
59
59
|
plotDefaults: import("./ast/PlotAttributeNode.js").PlotAttributeNode[];
|
|
60
60
|
parseComponent(spec: any): any;
|
|
61
61
|
/**
|
|
62
|
-
* Test if a value is param reference, if so,
|
|
63
|
-
* as needed and
|
|
62
|
+
* Test if a value is a param reference, if so, generates a parameter
|
|
63
|
+
* definition as needed and returns a new ParamRefNode. Otherwise,
|
|
64
|
+
* returns a LiteralNode for the given value.
|
|
64
65
|
* @param {*} value The value to test.
|
|
65
|
-
* @param {() => ParamNode | SelectionNode} [makeNode] A Param of Selection AST
|
|
66
|
-
* node constructor.
|
|
67
66
|
* @returns {ParamRefNode|LiteralNode} An AST node for the input value.
|
|
68
67
|
*/
|
|
69
|
-
maybeParam(value: any
|
|
70
|
-
|
|
68
|
+
maybeParam(value: any): ParamRefNode | LiteralNode;
|
|
69
|
+
/**
|
|
70
|
+
* Test if a value is a param reference, if so, generates a selection
|
|
71
|
+
* definition as needed and returns a new ParamRefNode. Otherwise,
|
|
72
|
+
* returns a LiteralNode for the given value.
|
|
73
|
+
* @param {*} value The value to test.
|
|
74
|
+
* @returns {ParamRefNode|LiteralNode} An AST node for the input value.
|
|
75
|
+
*/
|
|
76
|
+
maybeSelection(value: any): ParamRefNode | LiteralNode;
|
|
77
|
+
/**
|
|
78
|
+
* Create a parameter reference. Generates a parameter definition if needed
|
|
79
|
+
* and returns a new ParamRefNode.
|
|
80
|
+
* @param {string} name The parameter name.
|
|
81
|
+
* @param {() => ParamNode | SelectionNode} [makeNode] A Param or Selection AST
|
|
82
|
+
* node constructor.
|
|
83
|
+
* @returns {ParamRefNode|null} A node referring to the param or selection.
|
|
84
|
+
*/
|
|
85
|
+
paramRef(name: string, makeNode?: () => ParamNode | SelectionNode): ParamRefNode | null;
|
|
86
|
+
/**
|
|
87
|
+
* Create a selection reference. Generates a selection definition if needed
|
|
88
|
+
* and returns a new ParamRefNode. Returns null if a non-selection parameter
|
|
89
|
+
* with the same name already exists and *strict* is true.
|
|
90
|
+
* @param {string} name The selection name.
|
|
91
|
+
* @param {boolean} [strict=false] Indicates if this method may return param
|
|
92
|
+
* references (false, default) or only selection references (true).
|
|
93
|
+
* @returns {ParamRefNode|null} A node referring to the param or selection.
|
|
94
|
+
*/
|
|
95
|
+
selectionRef(name: string, strict?: boolean): ParamRefNode | null;
|
|
71
96
|
error(message: any, data: any): void;
|
|
72
97
|
}
|
|
73
98
|
/**
|
|
@@ -80,7 +105,7 @@ export type PlotNames = {
|
|
|
80
105
|
marks: Set<string>;
|
|
81
106
|
};
|
|
82
107
|
import { SpecNode } from './ast/SpecNode.js';
|
|
83
|
-
import { ParamNode } from './ast/ParamNode.js';
|
|
84
|
-
import { SelectionNode } from './ast/SelectionNode.js';
|
|
85
108
|
import { ParamRefNode } from './ast/ParamRefNode.js';
|
|
86
109
|
import { LiteralNode } from './ast/LiteralNode.js';
|
|
110
|
+
import { ParamNode } from './ast/ParamNode.js';
|
|
111
|
+
import { SelectionNode } from './ast/SelectionNode.js';
|
|
@@ -52,6 +52,12 @@ export interface Selection {
|
|
|
52
52
|
* false, a selection with no clauses selects all values.
|
|
53
53
|
*/
|
|
54
54
|
empty?: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Upstream selections whose clauses should be included as part of this
|
|
57
|
+
* selection. Any clauses or activations published to the upstream
|
|
58
|
+
* selections will be relayed to this selection.
|
|
59
|
+
*/
|
|
60
|
+
include?: ParamRef | ParamRef[];
|
|
55
61
|
}
|
|
56
62
|
/** A Param or Selection definition. */
|
|
57
63
|
export type ParamDefinition = ParamValue | Param | ParamDate | Selection;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uwdata/mosaic-spec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Declarative specification of Mosaic-powered applications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mosaic",
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
"types": "tsc -p tsconfig.json && npm run schema",
|
|
29
29
|
"schema": "ts-json-schema-generator -f tsconfig.json -p src/spec/Spec.ts -t Spec --no-type-check --no-ref-encode --functions hide > dist/mosaic-schema.json",
|
|
30
30
|
"pretest": "npm run prebuild && npm run types",
|
|
31
|
-
"test": "
|
|
31
|
+
"test": "vitest run && tsc -p jsconfig.json",
|
|
32
32
|
"version": "cd ../.. && npm run docs:schema",
|
|
33
33
|
"prepublishOnly": "npm run test && npm run lint && npm run build"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@uwdata/mosaic-core": "^0.
|
|
37
|
-
"@uwdata/mosaic-sql": "^0.
|
|
38
|
-
"@uwdata/vgplot": "^0.
|
|
36
|
+
"@uwdata/mosaic-core": "^0.11.0",
|
|
37
|
+
"@uwdata/mosaic-sql": "^0.11.0",
|
|
38
|
+
"@uwdata/vgplot": "^0.11.0",
|
|
39
39
|
"ts-json-schema-generator": "^2.3.0"
|
|
40
40
|
},
|
|
41
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "861d616f39926a1d2aee83b59dbdd70b0b3caf12"
|
|
42
42
|
}
|
package/src/ast/ParamNode.js
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { isArray, isObject, isoparse } from '../util.js';
|
|
2
2
|
import { ASTNode } from './ASTNode.js';
|
|
3
|
+
import { parseSelection } from './SelectionNode.js';
|
|
3
4
|
import { CROSSFILTER, INTERSECT, PARAM, SINGLE, UNION, VALUE } from '../constants.js';
|
|
4
|
-
import { SelectionNode } from './SelectionNode.js';
|
|
5
5
|
|
|
6
6
|
const paramTypes = new Set([VALUE, SINGLE, CROSSFILTER, INTERSECT, UNION]);
|
|
7
7
|
|
|
8
8
|
export function parseParam(spec, ctx) {
|
|
9
9
|
const param = isObject(spec) ? spec : { value: spec };
|
|
10
|
-
const { select = VALUE,
|
|
10
|
+
const { select = VALUE, value, date } = param;
|
|
11
11
|
if (!paramTypes.has(select)) {
|
|
12
12
|
ctx.error(`Unrecognized param type: ${select}`, param);
|
|
13
13
|
}
|
|
14
|
-
|
|
15
14
|
if (select !== VALUE) {
|
|
16
|
-
return
|
|
15
|
+
return parseSelection(spec, ctx);
|
|
17
16
|
} else if (isArray(value)) {
|
|
18
17
|
return new ParamNode(value.map(v => ctx.maybeParam(v)));
|
|
19
18
|
} else {
|
package/src/ast/ParamRefNode.js
CHANGED
package/src/ast/SelectionNode.js
CHANGED
|
@@ -1,30 +1,62 @@
|
|
|
1
1
|
import { ASTNode } from './ASTNode.js';
|
|
2
|
-
import {
|
|
2
|
+
import { OptionsNode, parseOptions } from './OptionsNode.js';
|
|
3
|
+
import { INCLUDE, INTERSECT, SELECTION } from '../constants.js';
|
|
4
|
+
import { paramRef, toArray } from '../util.js';
|
|
5
|
+
|
|
6
|
+
export function parseSelection(spec, ctx) {
|
|
7
|
+
const { select, include, ...options } = spec;
|
|
8
|
+
const opt = parseOptions(options, ctx);
|
|
9
|
+
if (include) {
|
|
10
|
+
opt.options.include = new IncludeNode(
|
|
11
|
+
toArray(include).map(ref => ctx.selectionRef(paramRef(ref)))
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
return new SelectionNode(select, opt);
|
|
15
|
+
}
|
|
3
16
|
|
|
4
17
|
export class SelectionNode extends ASTNode {
|
|
5
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Create a Selection AST node.
|
|
20
|
+
* @param {string} select The selection type.
|
|
21
|
+
* @param {OptionsNode} options Selection options.
|
|
22
|
+
*/
|
|
23
|
+
constructor(select = INTERSECT, options = new OptionsNode({})) {
|
|
6
24
|
super(SELECTION);
|
|
7
25
|
this.select = select;
|
|
8
|
-
this.
|
|
9
|
-
|
|
26
|
+
this.options = options;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
instantiate(ctx) {
|
|
30
|
+
const { select, options } = this;
|
|
31
|
+
return ctx.api.Selection[select](options.instantiate(ctx));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
codegen(ctx) {
|
|
35
|
+
const { select, options } = this;
|
|
36
|
+
return `${ctx.ns()}Selection.${select}(${options.codegen(ctx)})`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
toJSON() {
|
|
40
|
+
const { select, options } = this;
|
|
41
|
+
return { select, ...options.toJSON() };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class IncludeNode extends ASTNode {
|
|
46
|
+
constructor(refs) {
|
|
47
|
+
super(INCLUDE);
|
|
48
|
+
this.refs = refs;
|
|
10
49
|
}
|
|
11
50
|
|
|
12
51
|
instantiate(ctx) {
|
|
13
|
-
|
|
14
|
-
return ctx.api.Selection[select]({ cross, empty });
|
|
52
|
+
return this.refs.map(ref => ref.instantiate(ctx));
|
|
15
53
|
}
|
|
16
54
|
|
|
17
55
|
codegen(ctx) {
|
|
18
|
-
|
|
19
|
-
const args = [['cross', cross], ['empty', empty]]
|
|
20
|
-
.filter(a => a[1] != null)
|
|
21
|
-
.map(a => `${a[0]}: ${a[1]}`);
|
|
22
|
-
const arg = args.length ? `{ ${args.join(', ')} }` : '';
|
|
23
|
-
return `${ctx.ns()}Selection.${select}(${arg})`;
|
|
56
|
+
return `[${this.refs.map(ref => ref.codegen(ctx)).join(', ')}]`;
|
|
24
57
|
}
|
|
25
58
|
|
|
26
59
|
toJSON() {
|
|
27
|
-
|
|
28
|
-
return { select, cross, empty };
|
|
60
|
+
return this.refs.map(ref => ref.toJSON());
|
|
29
61
|
}
|
|
30
62
|
}
|
package/src/constants.js
CHANGED
package/src/parse-spec.js
CHANGED
|
@@ -68,7 +68,6 @@ export class ParseContext {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
parse(spec) {
|
|
71
|
-
// eslint-disable-next-line no-unused-vars
|
|
72
71
|
const {
|
|
73
72
|
meta,
|
|
74
73
|
config,
|
|
@@ -113,29 +112,67 @@ export class ParseContext {
|
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
/**
|
|
116
|
-
* Test if a value is param reference, if so,
|
|
117
|
-
* as needed and
|
|
115
|
+
* Test if a value is a param reference, if so, generates a parameter
|
|
116
|
+
* definition as needed and returns a new ParamRefNode. Otherwise,
|
|
117
|
+
* returns a LiteralNode for the given value.
|
|
118
118
|
* @param {*} value The value to test.
|
|
119
|
-
* @param {() => ParamNode | SelectionNode} [makeNode] A Param of Selection AST
|
|
120
|
-
* node constructor.
|
|
121
119
|
* @returns {ParamRefNode|LiteralNode} An AST node for the input value.
|
|
122
120
|
*/
|
|
123
|
-
maybeParam(value
|
|
124
|
-
const { params } = this;
|
|
121
|
+
maybeParam(value) {
|
|
125
122
|
const name = paramRef(value);
|
|
123
|
+
return name
|
|
124
|
+
? this.paramRef(name)
|
|
125
|
+
: new LiteralNode(value);
|
|
126
|
+
}
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Test if a value is a param reference, if so, generates a selection
|
|
130
|
+
* definition as needed and returns a new ParamRefNode. Otherwise,
|
|
131
|
+
* returns a LiteralNode for the given value.
|
|
132
|
+
* @param {*} value The value to test.
|
|
133
|
+
* @returns {ParamRefNode|LiteralNode} An AST node for the input value.
|
|
134
|
+
*/
|
|
135
|
+
maybeSelection(value) {
|
|
136
|
+
const name = paramRef(value);
|
|
137
|
+
return name
|
|
138
|
+
? this.selectionRef(name)
|
|
139
|
+
: new LiteralNode(value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Create a parameter reference. Generates a parameter definition if needed
|
|
144
|
+
* and returns a new ParamRefNode.
|
|
145
|
+
* @param {string} name The parameter name.
|
|
146
|
+
* @param {() => ParamNode | SelectionNode} [makeNode] A Param or Selection AST
|
|
147
|
+
* node constructor.
|
|
148
|
+
* @returns {ParamRefNode|null} A node referring to the param or selection.
|
|
149
|
+
*/
|
|
150
|
+
paramRef(name, makeNode = () => new ParamNode) {
|
|
151
|
+
const { params } = this;
|
|
152
|
+
if (!name) return null;
|
|
153
|
+
let p = params.get(name);
|
|
154
|
+
if (!p) {
|
|
155
|
+
p = makeNode();
|
|
156
|
+
params.set(name, p);
|
|
133
157
|
}
|
|
134
|
-
return new
|
|
158
|
+
return new ParamRefNode(name);
|
|
135
159
|
}
|
|
136
160
|
|
|
137
|
-
|
|
138
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Create a selection reference. Generates a selection definition if needed
|
|
163
|
+
* and returns a new ParamRefNode. Returns null if a non-selection parameter
|
|
164
|
+
* with the same name already exists and *strict* is true.
|
|
165
|
+
* @param {string} name The selection name.
|
|
166
|
+
* @param {boolean} [strict=false] Indicates if this method may return param
|
|
167
|
+
* references (false, default) or only selection references (true).
|
|
168
|
+
* @returns {ParamRefNode|null} A node referring to the param or selection.
|
|
169
|
+
*/
|
|
170
|
+
selectionRef(name, strict = false) {
|
|
171
|
+
const p = this.params.get(name);
|
|
172
|
+
if (strict && p && !(p instanceof SelectionNode)) {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
return this.paramRef(name, () => new SelectionNode);
|
|
139
176
|
}
|
|
140
177
|
|
|
141
178
|
error(message, data) {
|
package/src/spec/Param.ts
CHANGED
|
@@ -65,6 +65,13 @@ export interface Selection {
|
|
|
65
65
|
* false, a selection with no clauses selects all values.
|
|
66
66
|
*/
|
|
67
67
|
empty?: boolean;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Upstream selections whose clauses should be included as part of this
|
|
71
|
+
* selection. Any clauses or activations published to the upstream
|
|
72
|
+
* selections will be relayed to this selection.
|
|
73
|
+
*/
|
|
74
|
+
include?: ParamRef | ParamRef[];
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
/** A Param or Selection definition. */
|
package/src/spec/Spec.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DataDefinition } from './Data.js';
|
|
2
|
-
import { ParamDefinition } from './Param.js';
|
|
2
|
+
import { ParamDefinition, ParamRef } from './Param.js';
|
|
3
3
|
import { HConcat } from './HConcat.js';
|
|
4
4
|
import { VConcat } from './VConcat.js';
|
|
5
5
|
import { HSpace } from './HSpace.js';
|