@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.
@@ -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';
@@ -2,7 +2,7 @@ export class ParamRefNode extends ASTNode {
2
2
  constructor(name: any);
3
3
  name: any;
4
4
  instantiate(ctx: any): any;
5
- codegen(): string;
5
+ codegen(ctx: any): string;
6
6
  toJSON(): string;
7
7
  }
8
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
- constructor(select: string, cross: any, empty: any);
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
- cross: any;
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, generate a paramter definition
63
- * as needed and return a new ParamRefNode. Otherwise, return a LiteralNode.
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, makeNode?: () => ParamNode | SelectionNode): ParamRefNode | LiteralNode;
70
- maybeSelection(value: any): LiteralNode | ParamRefNode;
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.10.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": "mocha 'test/**/*-test.js' && tsc -p jsconfig.json",
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.10.0",
37
- "@uwdata/mosaic-sql": "^0.10.0",
38
- "@uwdata/vgplot": "^0.10.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": "94fc4f0d4efc622001f6afd6714d1e9dda745be2"
41
+ "gitHead": "861d616f39926a1d2aee83b59dbdd70b0b3caf12"
42
42
  }
@@ -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, cross, empty, date, value } = param;
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 new SelectionNode(select, cross, empty);
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 {
@@ -12,7 +12,7 @@ export class ParamRefNode extends ASTNode {
12
12
  return ctx.activeParams?.get(this.name);
13
13
  }
14
14
 
15
- codegen() {
15
+ codegen(ctx) { // eslint-disable-line no-unused-vars
16
16
  return toParamRef(this.name);
17
17
  }
18
18
 
@@ -1,30 +1,62 @@
1
1
  import { ASTNode } from './ASTNode.js';
2
- import { INTERSECT, SELECTION } from '../constants.js';
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
- constructor(select = INTERSECT, cross, empty) {
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.cross = cross;
9
- this.empty = empty;
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
- const { select, cross, empty } = this;
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
- const { select, cross, empty } = this;
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
- const { select, cross, empty } = this;
28
- return { select, cross, empty };
60
+ return this.refs.map(ref => ref.toJSON());
29
61
  }
30
62
  }
package/src/constants.js CHANGED
@@ -14,6 +14,7 @@ export const OPTIONS = 'options';
14
14
  export const SELECTION = 'selection';
15
15
  export const PARAMREF = 'paramref';
16
16
  export const PARAM = 'param';
17
+ export const INCLUDE = 'include';
17
18
 
18
19
  // param and selection types
19
20
  export const SELECT = 'select';
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, generate a paramter definition
117
- * as needed and return a new ParamRefNode. Otherwise, return a LiteralNode.
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, makeNode = () => new ParamNode) {
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
- if (name) {
128
- if (!params.has(name)) {
129
- const p = makeNode();
130
- params.set(name, p);
131
- }
132
- return new ParamRefNode(name);
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 LiteralNode(value);
158
+ return new ParamRefNode(name);
135
159
  }
136
160
 
137
- maybeSelection(value) {
138
- return this.maybeParam(value, () => new SelectionNode);
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';