@mapwhit/tilerenderer 0.49.0 → 0.51.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/build/min/package.json +1 -1
- package/build/min/src/shaders/.dir +0 -0
- package/build/min/src/shaders/_prelude.fragment.glsl.js +14 -0
- package/build/min/src/shaders/_prelude.vertex.glsl.js +14 -0
- package/build/min/src/shaders/background.fragment.glsl.js +5 -0
- package/build/min/src/shaders/background.vertex.glsl.js +1 -0
- package/build/min/src/shaders/background_pattern.fragment.glsl.js +5 -0
- package/build/min/src/shaders/background_pattern.vertex.glsl.js +1 -0
- package/build/min/src/shaders/circle.fragment.glsl.js +20 -0
- package/build/min/src/shaders/circle.vertex.glsl.js +17 -0
- package/build/min/src/shaders/clipping_mask.fragment.glsl.js +1 -0
- package/build/min/src/shaders/clipping_mask.vertex.glsl.js +1 -0
- package/build/min/src/shaders/collision_box.fragment.glsl.js +1 -0
- package/build/min/src/shaders/collision_box.vertex.glsl.js +1 -0
- package/build/min/src/shaders/collision_circle.fragment.glsl.js +1 -0
- package/build/min/src/shaders/collision_circle.vertex.glsl.js +1 -0
- package/build/min/src/shaders/debug.fragment.glsl.js +1 -0
- package/build/min/src/shaders/debug.vertex.glsl.js +1 -0
- package/build/min/src/shaders/fill.fragment.glsl.js +10 -0
- package/build/min/src/shaders/fill.vertex.glsl.js +7 -0
- package/build/min/src/shaders/fill_extrusion.fragment.glsl.js +5 -0
- package/build/min/src/shaders/fill_extrusion.fragment.glsl.txt +1 -9
- package/build/min/src/shaders/fill_extrusion.vertex.glsl.js +9 -0
- package/build/min/src/shaders/fill_extrusion.vertex.glsl.txt +4 -4
- package/build/min/src/shaders/fill_extrusion_pattern.fragment.glsl.js +15 -0
- package/build/min/src/shaders/fill_extrusion_pattern.vertex.glsl.js +11 -0
- package/build/min/src/shaders/fill_outline.fragment.glsl.js +10 -0
- package/build/min/src/shaders/fill_outline.vertex.glsl.js +7 -0
- package/build/min/src/shaders/fill_outline_pattern.fragment.glsl.js +13 -0
- package/build/min/src/shaders/fill_outline_pattern.vertex.glsl.js +9 -0
- package/build/min/src/shaders/fill_pattern.fragment.glsl.js +13 -0
- package/build/min/src/shaders/fill_pattern.vertex.glsl.js +9 -0
- package/build/min/src/shaders/heatmap.fragment.glsl.js +10 -0
- package/build/min/src/shaders/heatmap.vertex.glsl.js +8 -0
- package/build/min/src/shaders/heatmap_texture.fragment.glsl.js +5 -0
- package/build/min/src/shaders/heatmap_texture.vertex.glsl.js +1 -0
- package/build/min/src/shaders/hillshade.fragment.glsl.js +7 -0
- package/build/min/src/shaders/hillshade.vertex.glsl.js +1 -0
- package/build/min/src/shaders/hillshade_prepare.fragment.glsl.js +8 -0
- package/build/min/src/shaders/hillshade_prepare.vertex.glsl.js +1 -0
- package/build/min/src/shaders/line.fragment.glsl.js +12 -0
- package/build/min/src/shaders/line.vertex.glsl.js +17 -0
- package/build/min/src/shaders/line_gradient.fragment.glsl.js +10 -0
- package/build/min/src/shaders/line_gradient.vertex.glsl.js +16 -0
- package/build/min/src/shaders/line_pattern.fragment.glsl.js +15 -0
- package/build/min/src/shaders/line_pattern.vertex.glsl.js +20 -0
- package/build/min/src/shaders/line_sdf.fragment.glsl.js +17 -0
- package/build/min/src/shaders/line_sdf.vertex.glsl.js +20 -0
- package/build/min/src/shaders/raster.fragment.glsl.js +5 -0
- package/build/min/src/shaders/raster.vertex.glsl.js +1 -0
- package/build/min/src/shaders/symbol_icon.fragment.glsl.js +9 -0
- package/build/min/src/shaders/symbol_icon.vertex.glsl.js +5 -0
- package/build/min/src/shaders/symbol_sdf.fragment.glsl.js +19 -0
- package/build/min/src/shaders/symbol_sdf.vertex.glsl.js +13 -0
- package/package.json +7 -7
- package/src/data/bucket/fill_bucket.js +1 -1
- package/src/data/bucket/fill_extrusion_bucket.js +2 -2
- package/src/data/bucket/line_bucket.js +1 -1
- package/src/data/bucket/symbol_bucket.js +16 -15
- package/src/data/feature_index.js +1 -1
- package/src/data/program_configuration.js +1 -1
- package/src/gl/color_mode.js +1 -1
- package/src/gl/value.js +1 -1
- package/src/render/draw_debug.js +1 -1
- package/src/render/draw_fill.js +1 -1
- package/src/render/draw_heatmap.js +1 -1
- package/src/render/glyph_manager.js +6 -130
- package/src/render/painter.js +1 -1
- package/src/render/uniform_binding.js +1 -1
- package/src/shaders/fill_extrusion.fragment.glsl +0 -7
- package/src/shaders/fill_extrusion.vertex.glsl +4 -4
- package/src/shaders/index.js +50 -50
- package/src/source/geojson_worker_source.js +4 -4
- package/src/source/geojson_wrapper.js +34 -26
- package/src/source/resources/glyphs.js +73 -0
- package/src/source/resources/images.js +68 -0
- package/src/source/resources/index.js +22 -0
- package/src/source/vector_tile_worker_source.js +5 -5
- package/src/source/worker.js +6 -5
- package/src/source/worker_tile.js +4 -4
- package/src/style/properties.js +1 -2
- package/src/style/style.js +3 -3
- package/src/style/style_layer/symbol_style_layer.js +1 -1
- package/src/style/style_layer.js +1 -1
- package/src/style-spec/feature_filter/index.js +43 -34
- package/src/style-spec/group_by_layout.js +10 -32
- package/src/style-spec/reference/v8.json +1 -1
- package/src/symbol/mergelines.js +1 -3
- package/src/symbol/placement.js +21 -2
- package/src/symbol/shaping.js +9 -18
- package/src/symbol/symbol_layout.js +1 -2
- package/src/symbol/symbol_size.js +1 -1
- package/src/symbol/transform_text.js +4 -8
- package/src/ui/map.js +11 -39
- package/src/util/browser.js +3 -18
- package/src/util/classify_rings.js +1 -1
- package/src/util/dom.js +0 -88
- package/src/util/find_pole_of_inaccessibility.js +2 -2
- package/src/util/web_worker_transfer.js +4 -4
- package/src/style/load_glyph_range.js +0 -17
- package/src/style-spec/expression/compound_expression.js +0 -132
- package/src/style-spec/expression/definitions/assertion.js +0 -116
- package/src/style-spec/expression/definitions/at.js +0 -57
- package/src/style-spec/expression/definitions/case.js +0 -73
- package/src/style-spec/expression/definitions/coalesce.js +0 -68
- package/src/style-spec/expression/definitions/coercion.js +0 -109
- package/src/style-spec/expression/definitions/collator.js +0 -102
- package/src/style-spec/expression/definitions/comparison.js +0 -193
- package/src/style-spec/expression/definitions/formatted.js +0 -123
- package/src/style-spec/expression/definitions/index.js +0 -356
- package/src/style-spec/expression/definitions/interpolate.js +0 -245
- package/src/style-spec/expression/definitions/length.js +0 -54
- package/src/style-spec/expression/definitions/let.js +0 -60
- package/src/style-spec/expression/definitions/literal.js +0 -69
- package/src/style-spec/expression/definitions/match.js +0 -142
- package/src/style-spec/expression/definitions/step.js +0 -116
- package/src/style-spec/expression/definitions/var.js +0 -38
- package/src/style-spec/expression/evaluation_context.js +0 -35
- package/src/style-spec/expression/index.js +0 -329
- package/src/style-spec/expression/is_constant.js +0 -63
- package/src/style-spec/expression/parsing_context.js +0 -212
- package/src/style-spec/expression/parsing_error.js +0 -9
- package/src/style-spec/expression/runtime_error.js +0 -12
- package/src/style-spec/expression/scope.js +0 -34
- package/src/style-spec/expression/stops.js +0 -37
- package/src/style-spec/expression/types.js +0 -88
- package/src/style-spec/expression/values.js +0 -126
- package/src/style-spec/function/convert.js +0 -234
- package/src/style-spec/function/index.js +0 -299
- package/src/style-spec/util/color.js +0 -73
- package/src/style-spec/util/color_spaces.js +0 -128
- package/src/style-spec/util/get_type.js +0 -18
- package/src/style-spec/util/interpolate.js +0 -21
- package/src/style-spec/util/properties.js +0 -17
- package/src/style-spec/util/result.js +0 -19
- package/src/ui/anchor.js +0 -24
- package/src/ui/bind_handlers.js +0 -199
- package/src/ui/events.js +0 -210
- package/src/ui/handler/box_zoom.js +0 -151
- package/src/ui/handler/dblclick_zoom.js +0 -91
- package/src/ui/handler/drag_pan.js +0 -285
- package/src/ui/handler/drag_rotate.js +0 -290
- package/src/ui/handler/frame.js +0 -28
- package/src/ui/handler/inertia.js +0 -45
- package/src/ui/handler/keyboard.js +0 -148
- package/src/ui/handler/scroll_zoom.js +0 -284
- package/src/ui/handler/touch_zoom_rotate.js +0 -263
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
const UnitBezier = require('@mapbox/unitbezier');
|
|
2
|
-
|
|
3
|
-
const interpolate = require('../../util/interpolate');
|
|
4
|
-
const { toString, ColorType, NumberType } = require('../types');
|
|
5
|
-
const { findStopLessThanOrEqualTo } = require('../stops');
|
|
6
|
-
const { hcl, lab } = require('../../util/color_spaces');
|
|
7
|
-
|
|
8
|
-
class Interpolate {
|
|
9
|
-
constructor(type, operator, interpolation, input, stops) {
|
|
10
|
-
this.type = type;
|
|
11
|
-
this.operator = operator;
|
|
12
|
-
this.interpolation = interpolation;
|
|
13
|
-
this.input = input;
|
|
14
|
-
|
|
15
|
-
this.labels = [];
|
|
16
|
-
this.outputs = [];
|
|
17
|
-
for (const [label, expression] of stops) {
|
|
18
|
-
this.labels.push(label);
|
|
19
|
-
this.outputs.push(expression);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static interpolationFactor(interpolation, input, lower, upper) {
|
|
24
|
-
let t = 0;
|
|
25
|
-
if (interpolation.name === 'exponential') {
|
|
26
|
-
t = exponentialInterpolation(input, interpolation.base, lower, upper);
|
|
27
|
-
} else if (interpolation.name === 'linear') {
|
|
28
|
-
t = exponentialInterpolation(input, 1, lower, upper);
|
|
29
|
-
} else if (interpolation.name === 'cubic-bezier') {
|
|
30
|
-
const c = interpolation.controlPoints;
|
|
31
|
-
const ub = new UnitBezier(c[0], c[1], c[2], c[3]);
|
|
32
|
-
t = ub.solve(exponentialInterpolation(input, 1, lower, upper));
|
|
33
|
-
}
|
|
34
|
-
return t;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
static parse(args, context) {
|
|
38
|
-
let [operator, interpolation, input, ...rest] = args;
|
|
39
|
-
|
|
40
|
-
if (!Array.isArray(interpolation) || interpolation.length === 0) {
|
|
41
|
-
return context.error('Expected an interpolation type expression.', 1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (interpolation[0] === 'linear') {
|
|
45
|
-
interpolation = { name: 'linear' };
|
|
46
|
-
} else if (interpolation[0] === 'exponential') {
|
|
47
|
-
const base = interpolation[1];
|
|
48
|
-
if (typeof base !== 'number') return context.error('Exponential interpolation requires a numeric base.', 1, 1);
|
|
49
|
-
interpolation = {
|
|
50
|
-
name: 'exponential',
|
|
51
|
-
base
|
|
52
|
-
};
|
|
53
|
-
} else if (interpolation[0] === 'cubic-bezier') {
|
|
54
|
-
const controlPoints = interpolation.slice(1);
|
|
55
|
-
if (controlPoints.length !== 4 || controlPoints.some(t => typeof t !== 'number' || t < 0 || t > 1)) {
|
|
56
|
-
return context.error(
|
|
57
|
-
'Cubic bezier interpolation requires four numeric arguments with values between 0 and 1.',
|
|
58
|
-
1
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interpolation = {
|
|
63
|
-
name: 'cubic-bezier',
|
|
64
|
-
controlPoints: controlPoints
|
|
65
|
-
};
|
|
66
|
-
} else {
|
|
67
|
-
return context.error(`Unknown interpolation type ${String(interpolation[0])}`, 1, 0);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (args.length - 1 < 4) {
|
|
71
|
-
return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if ((args.length - 1) % 2 !== 0) {
|
|
75
|
-
return context.error('Expected an even number of arguments.');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
input = context.parse(input, 2, NumberType);
|
|
79
|
-
if (!input) return null;
|
|
80
|
-
|
|
81
|
-
const stops = [];
|
|
82
|
-
|
|
83
|
-
let outputType = null;
|
|
84
|
-
if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') {
|
|
85
|
-
outputType = ColorType;
|
|
86
|
-
} else if (context.expectedType && context.expectedType.kind !== 'value') {
|
|
87
|
-
outputType = context.expectedType;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
for (let i = 0; i < rest.length; i += 2) {
|
|
91
|
-
const label = rest[i];
|
|
92
|
-
const value = rest[i + 1];
|
|
93
|
-
|
|
94
|
-
const labelKey = i + 3;
|
|
95
|
-
const valueKey = i + 4;
|
|
96
|
-
|
|
97
|
-
if (typeof label !== 'number') {
|
|
98
|
-
return context.error(
|
|
99
|
-
'Input/output pairs for "interpolate" expressions must be defined using literal numeric values (not computed expressions) for the input values.',
|
|
100
|
-
labelKey
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (stops.length && stops[stops.length - 1][0] >= label) {
|
|
105
|
-
return context.error(
|
|
106
|
-
'Input/output pairs for "interpolate" expressions must be arranged with input values in strictly ascending order.',
|
|
107
|
-
labelKey
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const parsed = context.parse(value, valueKey, outputType);
|
|
112
|
-
if (!parsed) return null;
|
|
113
|
-
outputType = outputType || parsed.type;
|
|
114
|
-
stops.push([label, parsed]);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
outputType.kind !== 'number' &&
|
|
119
|
-
outputType.kind !== 'color' &&
|
|
120
|
-
!(outputType.kind === 'array' && outputType.itemType.kind === 'number' && typeof outputType.N === 'number')
|
|
121
|
-
) {
|
|
122
|
-
return context.error(`Type ${toString(outputType)} is not interpolatable.`);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return new Interpolate(outputType, operator, interpolation, input, stops);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
evaluate(ctx) {
|
|
129
|
-
const labels = this.labels;
|
|
130
|
-
const outputs = this.outputs;
|
|
131
|
-
|
|
132
|
-
if (labels.length === 1) {
|
|
133
|
-
return outputs[0].evaluate(ctx);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const value = this.input.evaluate(ctx);
|
|
137
|
-
if (value <= labels[0]) {
|
|
138
|
-
return outputs[0].evaluate(ctx);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const stopCount = labels.length;
|
|
142
|
-
if (value >= labels[stopCount - 1]) {
|
|
143
|
-
return outputs[stopCount - 1].evaluate(ctx);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const index = findStopLessThanOrEqualTo(labels, value);
|
|
147
|
-
const lower = labels[index];
|
|
148
|
-
const upper = labels[index + 1];
|
|
149
|
-
const t = Interpolate.interpolationFactor(this.interpolation, value, lower, upper);
|
|
150
|
-
|
|
151
|
-
const outputLower = outputs[index].evaluate(ctx);
|
|
152
|
-
const outputUpper = outputs[index + 1].evaluate(ctx);
|
|
153
|
-
|
|
154
|
-
if (this.operator === 'interpolate') {
|
|
155
|
-
return interpolate[this.type.kind.toLowerCase()](outputLower, outputUpper, t);
|
|
156
|
-
}
|
|
157
|
-
if (this.operator === 'interpolate-hcl') {
|
|
158
|
-
return hcl.reverse(hcl.interpolate(hcl.forward(outputLower), hcl.forward(outputUpper), t));
|
|
159
|
-
}
|
|
160
|
-
return lab.reverse(lab.interpolate(lab.forward(outputLower), lab.forward(outputUpper), t));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
eachChild(fn) {
|
|
164
|
-
fn(this.input);
|
|
165
|
-
for (const expression of this.outputs) {
|
|
166
|
-
fn(expression);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
possibleOutputs() {
|
|
171
|
-
return [].concat(...this.outputs.map(output => output.possibleOutputs()));
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
serialize() {
|
|
175
|
-
let interpolation;
|
|
176
|
-
if (this.interpolation.name === 'linear') {
|
|
177
|
-
interpolation = ['linear'];
|
|
178
|
-
} else if (this.interpolation.name === 'exponential') {
|
|
179
|
-
if (this.interpolation.base === 1) {
|
|
180
|
-
interpolation = ['linear'];
|
|
181
|
-
} else {
|
|
182
|
-
interpolation = ['exponential', this.interpolation.base];
|
|
183
|
-
}
|
|
184
|
-
} else {
|
|
185
|
-
interpolation = ['cubic-bezier'].concat(this.interpolation.controlPoints);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const serialized = [this.operator, interpolation, this.input.serialize()];
|
|
189
|
-
|
|
190
|
-
for (let i = 0; i < this.labels.length; i++) {
|
|
191
|
-
serialized.push(this.labels[i], this.outputs[i].serialize());
|
|
192
|
-
}
|
|
193
|
-
return serialized;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Returns a ratio that can be used to interpolate between exponential function
|
|
199
|
-
* stops.
|
|
200
|
-
* How it works: Two consecutive stop values define a (scaled and shifted) exponential function `f(x) = a * base^x + b`, where `base` is the user-specified base,
|
|
201
|
-
* and `a` and `b` are constants affording sufficient degrees of freedom to fit
|
|
202
|
-
* the function to the given stops.
|
|
203
|
-
*
|
|
204
|
-
* Here's a bit of algebra that lets us compute `f(x)` directly from the stop
|
|
205
|
-
* values without explicitly solving for `a` and `b`:
|
|
206
|
-
*
|
|
207
|
-
* First stop value: `f(x0) = y0 = a * base^x0 + b`
|
|
208
|
-
* Second stop value: `f(x1) = y1 = a * base^x1 + b`
|
|
209
|
-
* => `y1 - y0 = a(base^x1 - base^x0)`
|
|
210
|
-
* => `a = (y1 - y0)/(base^x1 - base^x0)`
|
|
211
|
-
*
|
|
212
|
-
* Desired value: `f(x) = y = a * base^x + b`
|
|
213
|
-
* => `f(x) = y0 + a * (base^x - base^x0)`
|
|
214
|
-
*
|
|
215
|
-
* From the above, we can replace the `a` in `a * (base^x - base^x0)` and do a
|
|
216
|
-
* little algebra:
|
|
217
|
-
* ```
|
|
218
|
-
* a * (base^x - base^x0) = (y1 - y0)/(base^x1 - base^x0) * (base^x - base^x0)
|
|
219
|
-
* = (y1 - y0) * (base^x - base^x0) / (base^x1 - base^x0)
|
|
220
|
-
* ```
|
|
221
|
-
*
|
|
222
|
-
* If we let `(base^x - base^x0) / (base^x1 base^x0)`, then we have
|
|
223
|
-
* `f(x) = y0 + (y1 - y0) * ratio`. In other words, `ratio` may be treated as
|
|
224
|
-
* an interpolation factor between the two stops' output values.
|
|
225
|
-
*
|
|
226
|
-
* (Note: a slightly different form for `ratio`,
|
|
227
|
-
* `(base^(x-x0) - 1) / (base^(x1-x0) - 1) `, is equivalent, but requires fewer
|
|
228
|
-
* expensive `Math.pow()` operations.)
|
|
229
|
-
*
|
|
230
|
-
* @private
|
|
231
|
-
*/
|
|
232
|
-
function exponentialInterpolation(input, base, lowerValue, upperValue) {
|
|
233
|
-
const difference = upperValue - lowerValue;
|
|
234
|
-
const progress = input - lowerValue;
|
|
235
|
-
|
|
236
|
-
if (difference === 0) {
|
|
237
|
-
return 0;
|
|
238
|
-
}
|
|
239
|
-
if (base === 1) {
|
|
240
|
-
return progress / difference;
|
|
241
|
-
}
|
|
242
|
-
return (base ** progress - 1) / (base ** difference - 1);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
module.exports = Interpolate;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
const { NumberType, toString } = require('../types');
|
|
2
|
-
|
|
3
|
-
const { typeOf } = require('../values');
|
|
4
|
-
const RuntimeError = require('../runtime_error');
|
|
5
|
-
|
|
6
|
-
class Length {
|
|
7
|
-
constructor(input) {
|
|
8
|
-
this.type = NumberType;
|
|
9
|
-
this.input = input;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
static parse(args, context) {
|
|
13
|
-
if (args.length !== 2) return context.error(`Expected 1 argument, but found ${args.length - 1} instead.`);
|
|
14
|
-
|
|
15
|
-
const input = context.parse(args[1], 1);
|
|
16
|
-
if (!input) return null;
|
|
17
|
-
|
|
18
|
-
if (input.type.kind !== 'array' && input.type.kind !== 'string' && input.type.kind !== 'value')
|
|
19
|
-
return context.error(`Expected argument of type string or array, but found ${toString(input.type)} instead.`);
|
|
20
|
-
|
|
21
|
-
return new Length(input);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
evaluate(ctx) {
|
|
25
|
-
const input = this.input.evaluate(ctx);
|
|
26
|
-
if (typeof input === 'string') {
|
|
27
|
-
return input.length;
|
|
28
|
-
}
|
|
29
|
-
if (Array.isArray(input)) {
|
|
30
|
-
return input.length;
|
|
31
|
-
}
|
|
32
|
-
throw new RuntimeError(
|
|
33
|
-
`Expected value to be of type string or array, but found ${toString(typeOf(input))} instead.`
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
eachChild(fn) {
|
|
38
|
-
fn(this.input);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
possibleOutputs() {
|
|
42
|
-
return [undefined];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
serialize() {
|
|
46
|
-
const serialized = ['length'];
|
|
47
|
-
this.eachChild(child => {
|
|
48
|
-
serialized.push(child.serialize());
|
|
49
|
-
});
|
|
50
|
-
return serialized;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
module.exports = Length;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
class Let {
|
|
2
|
-
constructor(bindings, result) {
|
|
3
|
-
this.type = result.type;
|
|
4
|
-
this.bindings = [].concat(bindings);
|
|
5
|
-
this.result = result;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
evaluate(ctx) {
|
|
9
|
-
return this.result.evaluate(ctx);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
eachChild(fn) {
|
|
13
|
-
for (const binding of this.bindings) {
|
|
14
|
-
fn(binding[1]);
|
|
15
|
-
}
|
|
16
|
-
fn(this.result);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
static parse(args, context) {
|
|
20
|
-
if (args.length < 4) return context.error(`Expected at least 3 arguments, but found ${args.length - 1} instead.`);
|
|
21
|
-
|
|
22
|
-
const bindings = [];
|
|
23
|
-
for (let i = 1; i < args.length - 1; i += 2) {
|
|
24
|
-
const name = args[i];
|
|
25
|
-
|
|
26
|
-
if (typeof name !== 'string') {
|
|
27
|
-
return context.error(`Expected string, but found ${typeof name} instead.`, i);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (/[^a-zA-Z0-9_]/.test(name)) {
|
|
31
|
-
return context.error(`Variable names must contain only alphanumeric characters or '_'.`, i);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const value = context.parse(args[i + 1], i + 1);
|
|
35
|
-
if (!value) return null;
|
|
36
|
-
|
|
37
|
-
bindings.push([name, value]);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const result = context.parse(args[args.length - 1], args.length - 1, undefined, bindings);
|
|
41
|
-
if (!result) return null;
|
|
42
|
-
|
|
43
|
-
return new Let(bindings, result);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
possibleOutputs() {
|
|
47
|
-
return this.result.possibleOutputs();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
serialize() {
|
|
51
|
-
const serialized = ['let'];
|
|
52
|
-
for (const [name, expr] of this.bindings) {
|
|
53
|
-
serialized.push(name, expr.serialize());
|
|
54
|
-
}
|
|
55
|
-
serialized.push(this.result.serialize());
|
|
56
|
-
return serialized;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
module.exports = Let;
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const assert = require('assert');
|
|
2
|
-
const { isValue, typeOf, Color } = require('../values');
|
|
3
|
-
const { Formatted } = require('./formatted');
|
|
4
|
-
|
|
5
|
-
class Literal {
|
|
6
|
-
constructor(type, value) {
|
|
7
|
-
this.type = type;
|
|
8
|
-
this.value = value;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
static parse(args, context) {
|
|
12
|
-
if (args.length !== 2)
|
|
13
|
-
return context.error(`'literal' expression requires exactly one argument, but found ${args.length - 1} instead.`);
|
|
14
|
-
|
|
15
|
-
if (!isValue(args[1])) return context.error('invalid value');
|
|
16
|
-
|
|
17
|
-
const value = args[1];
|
|
18
|
-
let type = typeOf(value);
|
|
19
|
-
|
|
20
|
-
// special case: infer the item type if possible for zero-length arrays
|
|
21
|
-
const expected = context.expectedType;
|
|
22
|
-
if (
|
|
23
|
-
type.kind === 'array' &&
|
|
24
|
-
type.N === 0 &&
|
|
25
|
-
expected &&
|
|
26
|
-
expected.kind === 'array' &&
|
|
27
|
-
(typeof expected.N !== 'number' || expected.N === 0)
|
|
28
|
-
) {
|
|
29
|
-
type = expected;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return new Literal(type, value);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
evaluate() {
|
|
36
|
-
return this.value;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
eachChild() {}
|
|
40
|
-
|
|
41
|
-
possibleOutputs() {
|
|
42
|
-
return [this.value];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
serialize() {
|
|
46
|
-
if (this.type.kind === 'array' || this.type.kind === 'object') {
|
|
47
|
-
return ['literal', this.value];
|
|
48
|
-
}
|
|
49
|
-
if (this.value instanceof Color) {
|
|
50
|
-
// Constant-folding can generate Literal expressions that you
|
|
51
|
-
// couldn't actually generate with a "literal" expression,
|
|
52
|
-
// so we have to implement an equivalent serialization here
|
|
53
|
-
return ['rgba'].concat(this.value.toArray());
|
|
54
|
-
}
|
|
55
|
-
if (this.value instanceof Formatted) {
|
|
56
|
-
// Same as Color
|
|
57
|
-
return this.value.serialize();
|
|
58
|
-
}
|
|
59
|
-
assert(
|
|
60
|
-
this.value === null ||
|
|
61
|
-
typeof this.value === 'string' ||
|
|
62
|
-
typeof this.value === 'number' ||
|
|
63
|
-
typeof this.value === 'boolean'
|
|
64
|
-
);
|
|
65
|
-
return this.value;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
module.exports = Literal;
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
const assert = require('assert');
|
|
2
|
-
|
|
3
|
-
const { typeOf } = require('../values');
|
|
4
|
-
const { ValueType } = require('../types');
|
|
5
|
-
|
|
6
|
-
// Map input label values to output expression index
|
|
7
|
-
|
|
8
|
-
class Match {
|
|
9
|
-
constructor(inputType, outputType, input, cases, outputs, otherwise) {
|
|
10
|
-
this.inputType = inputType;
|
|
11
|
-
this.type = outputType;
|
|
12
|
-
this.input = input;
|
|
13
|
-
this.cases = cases;
|
|
14
|
-
this.outputs = outputs;
|
|
15
|
-
this.otherwise = otherwise;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static parse(args, context) {
|
|
19
|
-
if (args.length < 5) return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
|
20
|
-
if (args.length % 2 !== 1) return context.error('Expected an even number of arguments.');
|
|
21
|
-
|
|
22
|
-
let inputType;
|
|
23
|
-
let outputType;
|
|
24
|
-
if (context.expectedType && context.expectedType.kind !== 'value') {
|
|
25
|
-
outputType = context.expectedType;
|
|
26
|
-
}
|
|
27
|
-
const cases = {};
|
|
28
|
-
const outputs = [];
|
|
29
|
-
for (let i = 2; i < args.length - 1; i += 2) {
|
|
30
|
-
let labels = args[i];
|
|
31
|
-
const value = args[i + 1];
|
|
32
|
-
|
|
33
|
-
if (!Array.isArray(labels)) {
|
|
34
|
-
labels = [labels];
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const labelContext = context.concat(i);
|
|
38
|
-
if (labels.length === 0) {
|
|
39
|
-
return labelContext.error('Expected at least one branch label.');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
for (const label of labels) {
|
|
43
|
-
if (typeof label !== 'number' && typeof label !== 'string') {
|
|
44
|
-
return labelContext.error('Branch labels must be numbers or strings.');
|
|
45
|
-
}
|
|
46
|
-
if (typeof label === 'number' && Math.abs(label) > Number.MAX_SAFE_INTEGER) {
|
|
47
|
-
return labelContext.error(`Branch labels must be integers no larger than ${Number.MAX_SAFE_INTEGER}.`);
|
|
48
|
-
}
|
|
49
|
-
if (typeof label === 'number' && Math.floor(label) !== label) {
|
|
50
|
-
return labelContext.error('Numeric branch labels must be integer values.');
|
|
51
|
-
}
|
|
52
|
-
if (!inputType) {
|
|
53
|
-
inputType = typeOf(label);
|
|
54
|
-
} else if (labelContext.checkSubtype(inputType, typeOf(label))) {
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
if (typeof cases[String(label)] !== 'undefined') {
|
|
59
|
-
return labelContext.error('Branch labels must be unique.');
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
cases[String(label)] = outputs.length;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const result = context.parse(value, i, outputType);
|
|
66
|
-
if (!result) return null;
|
|
67
|
-
outputType = outputType || result.type;
|
|
68
|
-
outputs.push(result);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const input = context.parse(args[1], 1, ValueType);
|
|
72
|
-
if (!input) return null;
|
|
73
|
-
|
|
74
|
-
const otherwise = context.parse(args[args.length - 1], args.length - 1, outputType);
|
|
75
|
-
if (!otherwise) return null;
|
|
76
|
-
|
|
77
|
-
assert(inputType && outputType);
|
|
78
|
-
|
|
79
|
-
if (input.type.kind !== 'value' && context.concat(1).checkSubtype(inputType, input.type)) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return new Match(inputType, outputType, input, cases, outputs, otherwise);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
evaluate(ctx) {
|
|
87
|
-
const input = this.input.evaluate(ctx);
|
|
88
|
-
const output = (typeOf(input) === this.inputType && this.outputs[this.cases[input]]) || this.otherwise;
|
|
89
|
-
return output.evaluate(ctx);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
eachChild(fn) {
|
|
93
|
-
fn(this.input);
|
|
94
|
-
this.outputs.forEach(fn);
|
|
95
|
-
fn(this.otherwise);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
possibleOutputs() {
|
|
99
|
-
return [].concat(...this.outputs.map(out => out.possibleOutputs())).concat(this.otherwise.possibleOutputs());
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
serialize() {
|
|
103
|
-
const serialized = ['match', this.input.serialize()];
|
|
104
|
-
|
|
105
|
-
// Sort so serialization has an arbitrary defined order, even though
|
|
106
|
-
// branch order doesn't affect evaluation
|
|
107
|
-
const sortedLabels = Object.keys(this.cases).sort();
|
|
108
|
-
|
|
109
|
-
// Group branches by unique match expression to support condensed
|
|
110
|
-
// serializations of the form [case1, case2, ...] -> matchExpression
|
|
111
|
-
const groupedByOutput = [];
|
|
112
|
-
const outputLookup = {}; // lookup index into groupedByOutput for a given output expression
|
|
113
|
-
for (const label of sortedLabels) {
|
|
114
|
-
const outputIndex = outputLookup[this.cases[label]];
|
|
115
|
-
if (outputIndex === undefined) {
|
|
116
|
-
// First time seeing this output, add it to the end of the grouped list
|
|
117
|
-
outputLookup[this.cases[label]] = groupedByOutput.length;
|
|
118
|
-
groupedByOutput.push([this.cases[label], [label]]);
|
|
119
|
-
} else {
|
|
120
|
-
// We've seen this expression before, add the label to that output's group
|
|
121
|
-
groupedByOutput[outputIndex][1].push(label);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const coerceLabel = label => (this.inputType.kind === 'number' ? Number(label) : label);
|
|
126
|
-
|
|
127
|
-
for (const [outputIndex, labels] of groupedByOutput) {
|
|
128
|
-
if (labels.length === 1) {
|
|
129
|
-
// Only a single label matches this output expression
|
|
130
|
-
serialized.push(coerceLabel(labels[0]));
|
|
131
|
-
} else {
|
|
132
|
-
// Array of literal labels pointing to this output expression
|
|
133
|
-
serialized.push(labels.map(coerceLabel));
|
|
134
|
-
}
|
|
135
|
-
serialized.push(this.outputs[outputIndex].serialize());
|
|
136
|
-
}
|
|
137
|
-
serialized.push(this.otherwise.serialize());
|
|
138
|
-
return serialized;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
module.exports = Match;
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
const { NumberType } = require('../types');
|
|
2
|
-
|
|
3
|
-
const { findStopLessThanOrEqualTo } = require('../stops');
|
|
4
|
-
|
|
5
|
-
class Step {
|
|
6
|
-
constructor(type, input, stops) {
|
|
7
|
-
this.type = type;
|
|
8
|
-
this.input = input;
|
|
9
|
-
|
|
10
|
-
this.labels = [];
|
|
11
|
-
this.outputs = [];
|
|
12
|
-
for (const [label, expression] of stops) {
|
|
13
|
-
this.labels.push(label);
|
|
14
|
-
this.outputs.push(expression);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static parse(args, context) {
|
|
19
|
-
let [, input, ...rest] = args;
|
|
20
|
-
|
|
21
|
-
if (args.length - 1 < 4) {
|
|
22
|
-
return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if ((args.length - 1) % 2 !== 0) {
|
|
26
|
-
return context.error('Expected an even number of arguments.');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
input = context.parse(input, 1, NumberType);
|
|
30
|
-
if (!input) return null;
|
|
31
|
-
|
|
32
|
-
const stops = [];
|
|
33
|
-
|
|
34
|
-
let outputType = null;
|
|
35
|
-
if (context.expectedType && context.expectedType.kind !== 'value') {
|
|
36
|
-
outputType = context.expectedType;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
rest.unshift(Number.NEGATIVE_INFINITY);
|
|
40
|
-
|
|
41
|
-
for (let i = 0; i < rest.length; i += 2) {
|
|
42
|
-
const label = rest[i];
|
|
43
|
-
const value = rest[i + 1];
|
|
44
|
-
|
|
45
|
-
const labelKey = i + 1;
|
|
46
|
-
const valueKey = i + 2;
|
|
47
|
-
|
|
48
|
-
if (typeof label !== 'number') {
|
|
49
|
-
return context.error(
|
|
50
|
-
'Input/output pairs for "step" expressions must be defined using literal numeric values (not computed expressions) for the input values.',
|
|
51
|
-
labelKey
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (stops.length && stops[stops.length - 1][0] >= label) {
|
|
56
|
-
return context.error(
|
|
57
|
-
'Input/output pairs for "step" expressions must be arranged with input values in strictly ascending order.',
|
|
58
|
-
labelKey
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const parsed = context.parse(value, valueKey, outputType);
|
|
63
|
-
if (!parsed) return null;
|
|
64
|
-
outputType = outputType || parsed.type;
|
|
65
|
-
stops.push([label, parsed]);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return new Step(outputType, input, stops);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
evaluate(ctx) {
|
|
72
|
-
const labels = this.labels;
|
|
73
|
-
const outputs = this.outputs;
|
|
74
|
-
|
|
75
|
-
if (labels.length === 1) {
|
|
76
|
-
return outputs[0].evaluate(ctx);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const value = this.input.evaluate(ctx);
|
|
80
|
-
if (value <= labels[0]) {
|
|
81
|
-
return outputs[0].evaluate(ctx);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const stopCount = labels.length;
|
|
85
|
-
if (value >= labels[stopCount - 1]) {
|
|
86
|
-
return outputs[stopCount - 1].evaluate(ctx);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const index = findStopLessThanOrEqualTo(labels, value);
|
|
90
|
-
return outputs[index].evaluate(ctx);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
eachChild(fn) {
|
|
94
|
-
fn(this.input);
|
|
95
|
-
for (const expression of this.outputs) {
|
|
96
|
-
fn(expression);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
possibleOutputs() {
|
|
101
|
-
return [].concat(...this.outputs.map(output => output.possibleOutputs()));
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
serialize() {
|
|
105
|
-
const serialized = ['step', this.input.serialize()];
|
|
106
|
-
for (let i = 0; i < this.labels.length; i++) {
|
|
107
|
-
if (i > 0) {
|
|
108
|
-
serialized.push(this.labels[i]);
|
|
109
|
-
}
|
|
110
|
-
serialized.push(this.outputs[i].serialize());
|
|
111
|
-
}
|
|
112
|
-
return serialized;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
module.exports = Step;
|