@versatiles/png-renderer 2.5.0 → 2.6.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/README.md +1 -1
- package/dist/index.d.ts +49 -1
- package/dist/index.js +966 -778
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9830,6 +9830,21 @@ var v8_default = {
|
|
|
9830
9830
|
},
|
|
9831
9831
|
"property-type": "data-constant"
|
|
9832
9832
|
},
|
|
9833
|
+
"raster-layer-blend": {
|
|
9834
|
+
"type": "enum",
|
|
9835
|
+
"values": {
|
|
9836
|
+
"normal": {},
|
|
9837
|
+
"multiply": {},
|
|
9838
|
+
"color": {},
|
|
9839
|
+
"luminosity": {},
|
|
9840
|
+
"plus-lighter": {},
|
|
9841
|
+
"screen": {},
|
|
9842
|
+
"overlay": {}
|
|
9843
|
+
},
|
|
9844
|
+
"default": "normal",
|
|
9845
|
+
"property-type": "constant",
|
|
9846
|
+
"transition": false
|
|
9847
|
+
},
|
|
9833
9848
|
"raster-hue-rotate": {
|
|
9834
9849
|
"type": "number",
|
|
9835
9850
|
"default": 0,
|
|
@@ -10193,6 +10208,40 @@ var v8_default = {
|
|
|
10193
10208
|
// src/reference/latest.ts
|
|
10194
10209
|
const latest = v8_default;
|
|
10195
10210
|
|
|
10211
|
+
// src/expression/parsing_error.ts
|
|
10212
|
+
var ExpressionParsingError = class extends Error {
|
|
10213
|
+
constructor(key, message) {
|
|
10214
|
+
super(message);
|
|
10215
|
+
this.message = message;
|
|
10216
|
+
this.key = key;
|
|
10217
|
+
}
|
|
10218
|
+
};
|
|
10219
|
+
|
|
10220
|
+
// src/expression/scope.ts
|
|
10221
|
+
/**
|
|
10222
|
+
* Tracks `let` bindings during expression parsing.
|
|
10223
|
+
* @private
|
|
10224
|
+
*/
|
|
10225
|
+
var Scope = class Scope {
|
|
10226
|
+
constructor(parent, bindings = []) {
|
|
10227
|
+
this.parent = parent;
|
|
10228
|
+
this.bindings = {};
|
|
10229
|
+
for (const [name, expression] of bindings) this.bindings[name] = expression;
|
|
10230
|
+
}
|
|
10231
|
+
concat(bindings) {
|
|
10232
|
+
return new Scope(this, bindings);
|
|
10233
|
+
}
|
|
10234
|
+
get(name) {
|
|
10235
|
+
if (this.bindings[name]) return this.bindings[name];
|
|
10236
|
+
if (this.parent) return this.parent.get(name);
|
|
10237
|
+
throw new Error(`${name} not found in scope.`);
|
|
10238
|
+
}
|
|
10239
|
+
has(name) {
|
|
10240
|
+
if (this.bindings[name]) return true;
|
|
10241
|
+
return this.parent ? this.parent.has(name) : false;
|
|
10242
|
+
}
|
|
10243
|
+
};
|
|
10244
|
+
|
|
10196
10245
|
// src/expression/types.ts
|
|
10197
10246
|
const NullType = { kind: "null" };
|
|
10198
10247
|
const NumberType = { kind: "number" };
|
|
@@ -11464,6 +11513,25 @@ var Color$1 = class Color {
|
|
|
11464
11513
|
}
|
|
11465
11514
|
};
|
|
11466
11515
|
|
|
11516
|
+
// src/expression/types/collator.ts
|
|
11517
|
+
var Collator = class {
|
|
11518
|
+
constructor(caseSensitive, diacriticSensitive, locale) {
|
|
11519
|
+
if (caseSensitive) this.sensitivity = diacriticSensitive ? "variant" : "case";
|
|
11520
|
+
else this.sensitivity = diacriticSensitive ? "accent" : "base";
|
|
11521
|
+
this.locale = locale;
|
|
11522
|
+
this.collator = new Intl.Collator(this.locale ? this.locale : [], {
|
|
11523
|
+
sensitivity: this.sensitivity,
|
|
11524
|
+
usage: "search"
|
|
11525
|
+
});
|
|
11526
|
+
}
|
|
11527
|
+
compare(lhs, rhs) {
|
|
11528
|
+
return this.collator.compare(lhs, rhs);
|
|
11529
|
+
}
|
|
11530
|
+
resolvedLocale() {
|
|
11531
|
+
return new Intl.Collator(this.locale ? this.locale : []).resolvedOptions().locale;
|
|
11532
|
+
}
|
|
11533
|
+
};
|
|
11534
|
+
|
|
11467
11535
|
// src/expression/types/formatted.ts
|
|
11468
11536
|
const VERTICAL_ALIGN_OPTIONS = [
|
|
11469
11537
|
"bottom",
|
|
@@ -11742,25 +11810,6 @@ var ProjectionDefinition = class ProjectionDefinition {
|
|
|
11742
11810
|
}
|
|
11743
11811
|
};
|
|
11744
11812
|
|
|
11745
|
-
// src/expression/types/collator.ts
|
|
11746
|
-
var Collator = class {
|
|
11747
|
-
constructor(caseSensitive, diacriticSensitive, locale) {
|
|
11748
|
-
if (caseSensitive) this.sensitivity = diacriticSensitive ? "variant" : "case";
|
|
11749
|
-
else this.sensitivity = diacriticSensitive ? "accent" : "base";
|
|
11750
|
-
this.locale = locale;
|
|
11751
|
-
this.collator = new Intl.Collator(this.locale ? this.locale : [], {
|
|
11752
|
-
sensitivity: this.sensitivity,
|
|
11753
|
-
usage: "search"
|
|
11754
|
-
});
|
|
11755
|
-
}
|
|
11756
|
-
compare(lhs, rhs) {
|
|
11757
|
-
return this.collator.compare(lhs, rhs);
|
|
11758
|
-
}
|
|
11759
|
-
resolvedLocale() {
|
|
11760
|
-
return new Intl.Collator(this.locale ? this.locale : []).resolvedOptions().locale;
|
|
11761
|
-
}
|
|
11762
|
-
};
|
|
11763
|
-
|
|
11764
11813
|
// src/expression/values.ts
|
|
11765
11814
|
function validateRGBA(r, g, b, a) {
|
|
11766
11815
|
if (!(typeof r === "number" && r >= 0 && r <= 255 && typeof g === "number" && g >= 0 && g <= 255 && typeof b === "number" && b >= 0 && b <= 255)) return `Invalid rgba value [${(typeof a === "number" ? [
|
|
@@ -11852,539 +11901,100 @@ var Literal = class Literal {
|
|
|
11852
11901
|
}
|
|
11853
11902
|
};
|
|
11854
11903
|
|
|
11855
|
-
// src/expression/
|
|
11856
|
-
const
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
var
|
|
11863
|
-
constructor() {
|
|
11864
|
-
this.
|
|
11865
|
-
this.
|
|
11866
|
-
this.
|
|
11867
|
-
this.formattedSection = null;
|
|
11868
|
-
this._parseColorCache = /* @__PURE__ */ new Map();
|
|
11869
|
-
this.availableImages = null;
|
|
11870
|
-
this.canonical = null;
|
|
11871
|
-
}
|
|
11872
|
-
id() {
|
|
11873
|
-
return this.feature && "id" in this.feature ? this.feature.id : null;
|
|
11874
|
-
}
|
|
11875
|
-
geometryType() {
|
|
11876
|
-
return this.feature ? typeof this.feature.type === "number" ? geometryTypes[this.feature.type] : this.feature.type : null;
|
|
11904
|
+
// src/expression/definitions/assertion.ts
|
|
11905
|
+
const types$1 = {
|
|
11906
|
+
string: StringType,
|
|
11907
|
+
number: NumberType,
|
|
11908
|
+
boolean: BooleanType,
|
|
11909
|
+
object: ObjectType
|
|
11910
|
+
};
|
|
11911
|
+
var Assertion = class Assertion {
|
|
11912
|
+
constructor(type, args, key) {
|
|
11913
|
+
this.type = type;
|
|
11914
|
+
this.args = args;
|
|
11915
|
+
this.key = key;
|
|
11877
11916
|
}
|
|
11878
|
-
|
|
11879
|
-
|
|
11917
|
+
static parse(args, context) {
|
|
11918
|
+
if (args.length < 2) return context.error("Expected at least one argument.");
|
|
11919
|
+
let i = 1;
|
|
11920
|
+
let type;
|
|
11921
|
+
const name = args[0];
|
|
11922
|
+
if (name === "array") {
|
|
11923
|
+
let itemType;
|
|
11924
|
+
if (args.length > 2) {
|
|
11925
|
+
const type = args[1];
|
|
11926
|
+
if (typeof type !== "string" || !(type in types$1) || type === "object") return context.error("The item type argument of \"array\" must be one of string, number, boolean", 1);
|
|
11927
|
+
itemType = types$1[type];
|
|
11928
|
+
i++;
|
|
11929
|
+
} else itemType = ValueType;
|
|
11930
|
+
let N;
|
|
11931
|
+
if (args.length > 3) {
|
|
11932
|
+
if (args[2] !== null && (typeof args[2] !== "number" || args[2] < 0 || args[2] !== Math.floor(args[2]))) return context.error("The length argument to \"array\" must be a positive integer literal", 2);
|
|
11933
|
+
N = args[2];
|
|
11934
|
+
i++;
|
|
11935
|
+
}
|
|
11936
|
+
type = array(itemType, N);
|
|
11937
|
+
} else {
|
|
11938
|
+
if (!types$1[name]) throw new Error(`Types doesn't contain name = ${name}`);
|
|
11939
|
+
type = types$1[name];
|
|
11940
|
+
}
|
|
11941
|
+
const parsed = [];
|
|
11942
|
+
for (; i < args.length; i++) {
|
|
11943
|
+
const input = context.parse(args[i], i, ValueType);
|
|
11944
|
+
if (!input) return null;
|
|
11945
|
+
parsed.push(input);
|
|
11946
|
+
}
|
|
11947
|
+
return new Assertion(type, parsed, context.key);
|
|
11880
11948
|
}
|
|
11881
|
-
|
|
11882
|
-
|
|
11949
|
+
evaluate(ctx) {
|
|
11950
|
+
for (let i = 0; i < this.args.length; i++) {
|
|
11951
|
+
const value = this.args[i].evaluate(ctx);
|
|
11952
|
+
if (!checkSubtype(this.type, typeOf(value))) return value;
|
|
11953
|
+
else if (i === this.args.length - 1) throw new RuntimeError(`Expected value to be of type ${typeToString(this.type)}, but found ${typeToString(typeOf(value))} instead.`, this.key);
|
|
11954
|
+
}
|
|
11955
|
+
throw new Error();
|
|
11883
11956
|
}
|
|
11884
|
-
|
|
11885
|
-
|
|
11957
|
+
eachChild(fn) {
|
|
11958
|
+
this.args.forEach(fn);
|
|
11886
11959
|
}
|
|
11887
|
-
|
|
11888
|
-
|
|
11889
|
-
if (!cached) {
|
|
11890
|
-
cached = Color$1.parse(input);
|
|
11891
|
-
this._parseColorCache.set(input, cached);
|
|
11892
|
-
}
|
|
11893
|
-
return cached;
|
|
11960
|
+
outputDefined() {
|
|
11961
|
+
return this.args.every((arg) => arg.outputDefined());
|
|
11894
11962
|
}
|
|
11895
11963
|
};
|
|
11896
11964
|
|
|
11897
|
-
// src/expression/
|
|
11965
|
+
// src/expression/definitions/coercion.ts
|
|
11966
|
+
const types = {
|
|
11967
|
+
"to-boolean": BooleanType,
|
|
11968
|
+
"to-color": ColorType,
|
|
11969
|
+
"to-number": NumberType,
|
|
11970
|
+
"to-string": StringType
|
|
11971
|
+
};
|
|
11898
11972
|
/**
|
|
11899
|
-
*
|
|
11973
|
+
* Special form for error-coalescing coercion expressions "to-number",
|
|
11974
|
+
* "to-color". Since these coercions can fail at runtime, they accept multiple
|
|
11975
|
+
* arguments, only evaluating one at a time until one succeeds.
|
|
11976
|
+
*
|
|
11900
11977
|
* @private
|
|
11901
11978
|
*/
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
let lowerIndex = 0;
|
|
11905
|
-
let upperIndex = lastIndex;
|
|
11906
|
-
let currentIndex = 0;
|
|
11907
|
-
let currentValue, nextValue;
|
|
11908
|
-
while (lowerIndex <= upperIndex) {
|
|
11909
|
-
currentIndex = Math.floor((lowerIndex + upperIndex) / 2);
|
|
11910
|
-
currentValue = stops[currentIndex];
|
|
11911
|
-
nextValue = stops[currentIndex + 1];
|
|
11912
|
-
if (currentValue <= input) {
|
|
11913
|
-
if (currentIndex === lastIndex || input < nextValue) return currentIndex;
|
|
11914
|
-
lowerIndex = currentIndex + 1;
|
|
11915
|
-
} else if (currentValue > input) upperIndex = currentIndex - 1;
|
|
11916
|
-
else throw new RuntimeError("Input is not a number.", key);
|
|
11917
|
-
}
|
|
11918
|
-
return 0;
|
|
11919
|
-
}
|
|
11920
|
-
|
|
11921
|
-
// src/expression/definitions/step.ts
|
|
11922
|
-
var Step = class Step {
|
|
11923
|
-
constructor(type, input, stops, key) {
|
|
11979
|
+
var Coercion = class Coercion {
|
|
11980
|
+
constructor(type, args, key) {
|
|
11924
11981
|
this.type = type;
|
|
11925
|
-
this.
|
|
11982
|
+
this.args = args;
|
|
11926
11983
|
this.key = key;
|
|
11927
|
-
this.labels = [];
|
|
11928
|
-
this.outputs = [];
|
|
11929
|
-
for (const [label, expression] of stops) {
|
|
11930
|
-
this.labels.push(label);
|
|
11931
|
-
this.outputs.push(expression);
|
|
11932
|
-
}
|
|
11933
11984
|
}
|
|
11934
11985
|
static parse(args, context) {
|
|
11935
|
-
if (args.length
|
|
11936
|
-
|
|
11937
|
-
|
|
11938
|
-
if (
|
|
11939
|
-
const
|
|
11940
|
-
|
|
11941
|
-
|
|
11942
|
-
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
const labelKey = i;
|
|
11946
|
-
const valueKey = i + 1;
|
|
11947
|
-
if (typeof label !== "number") return context.error("Input/output pairs for \"step\" expressions must be defined using literal numeric values (not computed expressions) for the input values.", labelKey);
|
|
11948
|
-
if (stops.length && stops[stops.length - 1][0] >= label) return context.error("Input/output pairs for \"step\" expressions must be arranged with input values in strictly ascending order.", labelKey);
|
|
11949
|
-
const parsed = context.parse(value, valueKey, outputType);
|
|
11950
|
-
if (!parsed) return null;
|
|
11951
|
-
outputType = outputType || parsed.type;
|
|
11952
|
-
stops.push([label, parsed]);
|
|
11986
|
+
if (args.length < 2) return context.error("Expected at least one argument.");
|
|
11987
|
+
const name = args[0];
|
|
11988
|
+
if (!types[name]) throw new Error(`Can't parse ${name} as it is not part of the known types`);
|
|
11989
|
+
if ((name === "to-boolean" || name === "to-string") && args.length !== 2) return context.error("Expected one argument.");
|
|
11990
|
+
const type = types[name];
|
|
11991
|
+
const parsed = [];
|
|
11992
|
+
for (let i = 1; i < args.length; i++) {
|
|
11993
|
+
const input = context.parse(args[i], i, ValueType);
|
|
11994
|
+
if (!input) return null;
|
|
11995
|
+
parsed.push(input);
|
|
11953
11996
|
}
|
|
11954
|
-
return new
|
|
11955
|
-
}
|
|
11956
|
-
evaluate(ctx) {
|
|
11957
|
-
const labels = this.labels;
|
|
11958
|
-
const outputs = this.outputs;
|
|
11959
|
-
if (labels.length === 1) return outputs[0].evaluate(ctx);
|
|
11960
|
-
const value = this.input.evaluate(ctx);
|
|
11961
|
-
if (value <= labels[0]) return outputs[0].evaluate(ctx);
|
|
11962
|
-
const stopCount = labels.length;
|
|
11963
|
-
if (value >= labels[stopCount - 1]) return outputs[stopCount - 1].evaluate(ctx);
|
|
11964
|
-
return outputs[findStopLessThanOrEqualTo(labels, value, this.key)].evaluate(ctx);
|
|
11965
|
-
}
|
|
11966
|
-
eachChild(fn) {
|
|
11967
|
-
fn(this.input);
|
|
11968
|
-
for (const expression of this.outputs) fn(expression);
|
|
11969
|
-
}
|
|
11970
|
-
outputDefined() {
|
|
11971
|
-
return this.outputs.every((out) => out.outputDefined());
|
|
11972
|
-
}
|
|
11973
|
-
};
|
|
11974
|
-
|
|
11975
|
-
// node_modules/@mapbox/unitbezier/index.js
|
|
11976
|
-
function unitBezier(p1x, p1y, p2x, p2y) {
|
|
11977
|
-
const cx = 3 * p1x;
|
|
11978
|
-
const bx = 3 * (p2x - p1x) - cx;
|
|
11979
|
-
const ax = 1 - cx - bx;
|
|
11980
|
-
const cy = 3 * p1y;
|
|
11981
|
-
const by = 3 * (p2y - p1y) - cy;
|
|
11982
|
-
const ay = 1 - cy - by;
|
|
11983
|
-
return function solve(x, epsilon = 1e-6) {
|
|
11984
|
-
if (x <= 0) return 0;
|
|
11985
|
-
if (x >= 1) return 1;
|
|
11986
|
-
let t = x;
|
|
11987
|
-
for (let i = 0; i < 8; i++) {
|
|
11988
|
-
const x2 = ((ax * t + bx) * t + cx) * t - x;
|
|
11989
|
-
if (Math.abs(x2) < epsilon) return ((ay * t + by) * t + cy) * t;
|
|
11990
|
-
const d2 = (3 * ax * t + 2 * bx) * t + cx;
|
|
11991
|
-
if (Math.abs(d2) < 1e-6) break;
|
|
11992
|
-
t -= x2 / d2;
|
|
11993
|
-
}
|
|
11994
|
-
let t0 = 0;
|
|
11995
|
-
let t1 = 1;
|
|
11996
|
-
t = x;
|
|
11997
|
-
for (let i = 0; i < 20; i++) {
|
|
11998
|
-
const x2 = ((ax * t + bx) * t + cx) * t;
|
|
11999
|
-
if (Math.abs(x2 - x) < epsilon) break;
|
|
12000
|
-
if (x > x2) t0 = t;
|
|
12001
|
-
else t1 = t;
|
|
12002
|
-
t = (t0 + t1) * .5;
|
|
12003
|
-
}
|
|
12004
|
-
return ((ay * t + by) * t + cy) * t;
|
|
12005
|
-
};
|
|
12006
|
-
}
|
|
12007
|
-
|
|
12008
|
-
// src/expression/definitions/interpolate.ts
|
|
12009
|
-
var Interpolate = class Interpolate {
|
|
12010
|
-
constructor(type, operator, interpolation, input, stops, key) {
|
|
12011
|
-
this.type = type;
|
|
12012
|
-
this.operator = operator;
|
|
12013
|
-
this.interpolation = interpolation;
|
|
12014
|
-
this.input = input;
|
|
12015
|
-
this.key = key;
|
|
12016
|
-
this.labels = [];
|
|
12017
|
-
this.outputs = [];
|
|
12018
|
-
for (const [label, expression] of stops) {
|
|
12019
|
-
this.labels.push(label);
|
|
12020
|
-
this.outputs.push(expression);
|
|
12021
|
-
}
|
|
12022
|
-
}
|
|
12023
|
-
static interpolationFactor(interpolation, input, lower, upper) {
|
|
12024
|
-
let t = 0;
|
|
12025
|
-
if (interpolation.name === "exponential") t = exponentialInterpolation(input, interpolation.base, lower, upper);
|
|
12026
|
-
else if (interpolation.name === "linear") t = exponentialInterpolation(input, 1, lower, upper);
|
|
12027
|
-
else if (interpolation.name === "cubic-bezier") {
|
|
12028
|
-
const c = interpolation.controlPoints;
|
|
12029
|
-
t = unitBezier(c[0], c[1], c[2], c[3])(exponentialInterpolation(input, 1, lower, upper));
|
|
12030
|
-
}
|
|
12031
|
-
return t;
|
|
12032
|
-
}
|
|
12033
|
-
static parse(args, context) {
|
|
12034
|
-
let [operator, interpolation, input, ...rest] = args;
|
|
12035
|
-
if (!Array.isArray(interpolation) || interpolation.length === 0) return context.error("Expected an interpolation type expression.", 1);
|
|
12036
|
-
if (interpolation[0] === "linear") interpolation = { name: "linear" };
|
|
12037
|
-
else if (interpolation[0] === "exponential") {
|
|
12038
|
-
const base = interpolation[1];
|
|
12039
|
-
if (typeof base !== "number") return context.error("Exponential interpolation requires a numeric base.", 1, 1);
|
|
12040
|
-
interpolation = {
|
|
12041
|
-
name: "exponential",
|
|
12042
|
-
base
|
|
12043
|
-
};
|
|
12044
|
-
} else if (interpolation[0] === "cubic-bezier") {
|
|
12045
|
-
const controlPoints = interpolation.slice(1);
|
|
12046
|
-
if (controlPoints.length !== 4 || controlPoints.some((t) => typeof t !== "number" || t < 0 || t > 1)) return context.error("Cubic bezier interpolation requires four numeric arguments with values between 0 and 1.", 1);
|
|
12047
|
-
interpolation = {
|
|
12048
|
-
name: "cubic-bezier",
|
|
12049
|
-
controlPoints
|
|
12050
|
-
};
|
|
12051
|
-
} else return context.error(`Unknown interpolation type ${String(interpolation[0])}`, 1, 0);
|
|
12052
|
-
if (args.length - 1 < 4) return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
|
12053
|
-
if ((args.length - 1) % 2 !== 0) return context.error("Expected an even number of arguments.");
|
|
12054
|
-
input = context.parse(input, 2, NumberType);
|
|
12055
|
-
if (!input) return null;
|
|
12056
|
-
const stops = [];
|
|
12057
|
-
let outputType = null;
|
|
12058
|
-
if ((operator === "interpolate-hcl" || operator === "interpolate-lab") && context.expectedType != ColorArrayType) outputType = ColorType;
|
|
12059
|
-
else if (context.expectedType && context.expectedType.kind !== "value") outputType = context.expectedType;
|
|
12060
|
-
for (let i = 0; i < rest.length; i += 2) {
|
|
12061
|
-
const label = rest[i];
|
|
12062
|
-
const value = rest[i + 1];
|
|
12063
|
-
const labelKey = i + 3;
|
|
12064
|
-
const valueKey = i + 4;
|
|
12065
|
-
if (typeof label !== "number") return context.error("Input/output pairs for \"interpolate\" expressions must be defined using literal numeric values (not computed expressions) for the input values.", labelKey);
|
|
12066
|
-
if (stops.length && stops[stops.length - 1][0] >= label) return context.error("Input/output pairs for \"interpolate\" expressions must be arranged with input values in strictly ascending order.", labelKey);
|
|
12067
|
-
const parsed = context.parse(value, valueKey, outputType);
|
|
12068
|
-
if (!parsed) return null;
|
|
12069
|
-
outputType = outputType || parsed.type;
|
|
12070
|
-
stops.push([label, parsed]);
|
|
12071
|
-
}
|
|
12072
|
-
if (!verifyType(outputType, NumberType) && !verifyType(outputType, ProjectionDefinitionType) && !verifyType(outputType, ColorType) && !verifyType(outputType, PaddingType) && !verifyType(outputType, NumberArrayType) && !verifyType(outputType, ColorArrayType) && !verifyType(outputType, VariableAnchorOffsetCollectionType) && !verifyType(outputType, array(NumberType))) return context.error(`Type ${typeToString(outputType)} is not interpolatable.`);
|
|
12073
|
-
return new Interpolate(outputType, operator, interpolation, input, stops, context.key);
|
|
12074
|
-
}
|
|
12075
|
-
evaluate(ctx) {
|
|
12076
|
-
const labels = this.labels;
|
|
12077
|
-
const outputs = this.outputs;
|
|
12078
|
-
if (labels.length === 1) return outputs[0].evaluate(ctx);
|
|
12079
|
-
const value = this.input.evaluate(ctx);
|
|
12080
|
-
if (value <= labels[0]) return outputs[0].evaluate(ctx);
|
|
12081
|
-
const stopCount = labels.length;
|
|
12082
|
-
if (value >= labels[stopCount - 1]) return outputs[stopCount - 1].evaluate(ctx);
|
|
12083
|
-
const index = findStopLessThanOrEqualTo(labels, value, this.key);
|
|
12084
|
-
const lower = labels[index];
|
|
12085
|
-
const upper = labels[index + 1];
|
|
12086
|
-
const t = Interpolate.interpolationFactor(this.interpolation, value, lower, upper);
|
|
12087
|
-
const outputLower = outputs[index].evaluate(ctx);
|
|
12088
|
-
const outputUpper = outputs[index + 1].evaluate(ctx);
|
|
12089
|
-
switch (this.operator) {
|
|
12090
|
-
case "interpolate": switch (this.type.kind) {
|
|
12091
|
-
case "number": return interpolateNumber(outputLower, outputUpper, t);
|
|
12092
|
-
case "color": return Color$1.interpolate(outputLower, outputUpper, t);
|
|
12093
|
-
case "padding": return Padding.interpolate(outputLower, outputUpper, t);
|
|
12094
|
-
case "colorArray": return ColorArray.interpolate(outputLower, outputUpper, t);
|
|
12095
|
-
case "numberArray": return NumberArray.interpolate(outputLower, outputUpper, t);
|
|
12096
|
-
case "variableAnchorOffsetCollection": return VariableAnchorOffsetCollection.interpolate(outputLower, outputUpper, t, this.key);
|
|
12097
|
-
case "array": return interpolateArray(outputLower, outputUpper, t);
|
|
12098
|
-
case "projectionDefinition": return ProjectionDefinition.interpolate(outputLower, outputUpper, t);
|
|
12099
|
-
}
|
|
12100
|
-
case "interpolate-hcl": switch (this.type.kind) {
|
|
12101
|
-
case "color": return Color$1.interpolate(outputLower, outputUpper, t, "hcl");
|
|
12102
|
-
case "colorArray": return ColorArray.interpolate(outputLower, outputUpper, t, "hcl");
|
|
12103
|
-
}
|
|
12104
|
-
case "interpolate-lab": switch (this.type.kind) {
|
|
12105
|
-
case "color": return Color$1.interpolate(outputLower, outputUpper, t, "lab");
|
|
12106
|
-
case "colorArray": return ColorArray.interpolate(outputLower, outputUpper, t, "lab");
|
|
12107
|
-
}
|
|
12108
|
-
}
|
|
12109
|
-
}
|
|
12110
|
-
eachChild(fn) {
|
|
12111
|
-
fn(this.input);
|
|
12112
|
-
for (const expression of this.outputs) fn(expression);
|
|
12113
|
-
}
|
|
12114
|
-
outputDefined() {
|
|
12115
|
-
return this.outputs.every((out) => out.outputDefined());
|
|
12116
|
-
}
|
|
12117
|
-
};
|
|
12118
|
-
/**
|
|
12119
|
-
* Returns a ratio that can be used to interpolate between exponential function
|
|
12120
|
-
* stops.
|
|
12121
|
-
* 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,
|
|
12122
|
-
* and `a` and `b` are constants affording sufficient degrees of freedom to fit
|
|
12123
|
-
* the function to the given stops.
|
|
12124
|
-
*
|
|
12125
|
-
* Here's a bit of algebra that lets us compute `f(x)` directly from the stop
|
|
12126
|
-
* values without explicitly solving for `a` and `b`:
|
|
12127
|
-
*
|
|
12128
|
-
* First stop value: `f(x0) = y0 = a * base^x0 + b`
|
|
12129
|
-
* Second stop value: `f(x1) = y1 = a * base^x1 + b`
|
|
12130
|
-
* => `y1 - y0 = a(base^x1 - base^x0)`
|
|
12131
|
-
* => `a = (y1 - y0)/(base^x1 - base^x0)`
|
|
12132
|
-
*
|
|
12133
|
-
* Desired value: `f(x) = y = a * base^x + b`
|
|
12134
|
-
* => `f(x) = y0 + a * (base^x - base^x0)`
|
|
12135
|
-
*
|
|
12136
|
-
* From the above, we can replace the `a` in `a * (base^x - base^x0)` and do a
|
|
12137
|
-
* little algebra:
|
|
12138
|
-
* ```
|
|
12139
|
-
* a * (base^x - base^x0) = (y1 - y0)/(base^x1 - base^x0) * (base^x - base^x0)
|
|
12140
|
-
* = (y1 - y0) * (base^x - base^x0) / (base^x1 - base^x0)
|
|
12141
|
-
* ```
|
|
12142
|
-
*
|
|
12143
|
-
* If we let `(base^x - base^x0) / (base^x1 base^x0)`, then we have
|
|
12144
|
-
* `f(x) = y0 + (y1 - y0) * ratio`. In other words, `ratio` may be treated as
|
|
12145
|
-
* an interpolation factor between the two stops' output values.
|
|
12146
|
-
*
|
|
12147
|
-
* (Note: a slightly different form for `ratio`,
|
|
12148
|
-
* `(base^(x-x0) - 1) / (base^(x1-x0) - 1) `, is equivalent, but requires fewer
|
|
12149
|
-
* expensive `Math.pow()` operations.)
|
|
12150
|
-
*
|
|
12151
|
-
* @private
|
|
12152
|
-
*/
|
|
12153
|
-
function exponentialInterpolation(input, base, lowerValue, upperValue) {
|
|
12154
|
-
const difference = upperValue - lowerValue;
|
|
12155
|
-
const progress = input - lowerValue;
|
|
12156
|
-
if (difference === 0) return 0;
|
|
12157
|
-
else if (base === 1) return progress / difference;
|
|
12158
|
-
else return (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
|
|
12159
|
-
}
|
|
12160
|
-
const interpolateFactory = {
|
|
12161
|
-
color: Color$1.interpolate,
|
|
12162
|
-
number: interpolateNumber,
|
|
12163
|
-
padding: Padding.interpolate,
|
|
12164
|
-
numberArray: NumberArray.interpolate,
|
|
12165
|
-
colorArray: ColorArray.interpolate,
|
|
12166
|
-
variableAnchorOffsetCollection: VariableAnchorOffsetCollection.interpolate,
|
|
12167
|
-
array: interpolateArray
|
|
12168
|
-
};
|
|
12169
|
-
|
|
12170
|
-
// src/expression/definitions/format.ts
|
|
12171
|
-
var FormatExpression = class FormatExpression {
|
|
12172
|
-
constructor(sections) {
|
|
12173
|
-
this.type = FormattedType;
|
|
12174
|
-
this.sections = sections;
|
|
12175
|
-
}
|
|
12176
|
-
static parse(args, context) {
|
|
12177
|
-
if (args.length < 2) return context.error("Expected at least one argument.");
|
|
12178
|
-
const firstArg = args[1];
|
|
12179
|
-
if (!Array.isArray(firstArg) && typeof firstArg === "object") return context.error("First argument must be an image or text section.");
|
|
12180
|
-
const sections = [];
|
|
12181
|
-
let nextTokenMayBeObject = false;
|
|
12182
|
-
for (let i = 1; i <= args.length - 1; ++i) {
|
|
12183
|
-
const arg = args[i];
|
|
12184
|
-
if (nextTokenMayBeObject && typeof arg === "object" && !Array.isArray(arg)) {
|
|
12185
|
-
nextTokenMayBeObject = false;
|
|
12186
|
-
let scale = null;
|
|
12187
|
-
if (arg["font-scale"]) {
|
|
12188
|
-
scale = context.parse(arg["font-scale"], 1, NumberType);
|
|
12189
|
-
if (!scale) return null;
|
|
12190
|
-
}
|
|
12191
|
-
let font = null;
|
|
12192
|
-
if (arg["text-font"]) {
|
|
12193
|
-
font = context.parse(arg["text-font"], 1, array(StringType));
|
|
12194
|
-
if (!font) return null;
|
|
12195
|
-
}
|
|
12196
|
-
let textColor = null;
|
|
12197
|
-
if (arg["text-color"]) {
|
|
12198
|
-
textColor = context.parse(arg["text-color"], 1, ColorType);
|
|
12199
|
-
if (!textColor) return null;
|
|
12200
|
-
}
|
|
12201
|
-
let verticalAlign = null;
|
|
12202
|
-
if (arg["vertical-align"]) {
|
|
12203
|
-
if (typeof arg["vertical-align"] === "string" && !VERTICAL_ALIGN_OPTIONS.includes(arg["vertical-align"])) return context.error(`'vertical-align' must be one of: 'bottom', 'center', 'top' but found '${arg["vertical-align"]}' instead.`);
|
|
12204
|
-
verticalAlign = context.parse(arg["vertical-align"], 1, StringType);
|
|
12205
|
-
if (!verticalAlign) return null;
|
|
12206
|
-
}
|
|
12207
|
-
const lastExpression = sections[sections.length - 1];
|
|
12208
|
-
lastExpression.scale = scale;
|
|
12209
|
-
lastExpression.font = font;
|
|
12210
|
-
lastExpression.textColor = textColor;
|
|
12211
|
-
lastExpression.verticalAlign = verticalAlign;
|
|
12212
|
-
} else {
|
|
12213
|
-
const content = context.parse(args[i], 1, ValueType);
|
|
12214
|
-
if (!content) return null;
|
|
12215
|
-
const kind = content.type.kind;
|
|
12216
|
-
if (kind !== "string" && kind !== "value" && kind !== "null" && kind !== "resolvedImage") return context.error("Formatted text type must be 'string', 'value', 'image' or 'null'.");
|
|
12217
|
-
nextTokenMayBeObject = true;
|
|
12218
|
-
sections.push({
|
|
12219
|
-
content,
|
|
12220
|
-
scale: null,
|
|
12221
|
-
font: null,
|
|
12222
|
-
textColor: null,
|
|
12223
|
-
verticalAlign: null
|
|
12224
|
-
});
|
|
12225
|
-
}
|
|
12226
|
-
}
|
|
12227
|
-
return new FormatExpression(sections);
|
|
12228
|
-
}
|
|
12229
|
-
evaluate(ctx) {
|
|
12230
|
-
const evaluateSection = (section) => {
|
|
12231
|
-
const evaluatedContent = section.content.evaluate(ctx);
|
|
12232
|
-
if (typeOf(evaluatedContent) === ResolvedImageType) return new FormattedSection("", evaluatedContent, null, null, null, section.verticalAlign ? section.verticalAlign.evaluate(ctx) : null);
|
|
12233
|
-
return new FormattedSection(valueToString(evaluatedContent), null, section.scale ? section.scale.evaluate(ctx) : null, section.font ? section.font.evaluate(ctx).join(",") : null, section.textColor ? section.textColor.evaluate(ctx) : null, section.verticalAlign ? section.verticalAlign.evaluate(ctx) : null);
|
|
12234
|
-
};
|
|
12235
|
-
return new Formatted(this.sections.map(evaluateSection));
|
|
12236
|
-
}
|
|
12237
|
-
eachChild(fn) {
|
|
12238
|
-
for (const section of this.sections) {
|
|
12239
|
-
fn(section.content);
|
|
12240
|
-
if (section.scale) fn(section.scale);
|
|
12241
|
-
if (section.font) fn(section.font);
|
|
12242
|
-
if (section.textColor) fn(section.textColor);
|
|
12243
|
-
if (section.verticalAlign) fn(section.verticalAlign);
|
|
12244
|
-
}
|
|
12245
|
-
}
|
|
12246
|
-
outputDefined() {
|
|
12247
|
-
return false;
|
|
12248
|
-
}
|
|
12249
|
-
};
|
|
12250
|
-
|
|
12251
|
-
// src/util/classify_rings.ts
|
|
12252
|
-
/**
|
|
12253
|
-
* Classifies an array of rings into polygons with outer rings and holes
|
|
12254
|
-
* @param rings - the rings to classify
|
|
12255
|
-
* @param maxRings - the maximum number of rings to include in a polygon, use 0 to include all rings
|
|
12256
|
-
* @returns an array of polygons with internal rings as holes
|
|
12257
|
-
*/
|
|
12258
|
-
function classifyRings$1(rings, maxRings) {
|
|
12259
|
-
if (rings.length <= 1) return [rings];
|
|
12260
|
-
const polygons = [];
|
|
12261
|
-
let polygon;
|
|
12262
|
-
let ccw;
|
|
12263
|
-
for (const ring of rings) {
|
|
12264
|
-
const area = calculateSignedArea(ring);
|
|
12265
|
-
if (area === 0) continue;
|
|
12266
|
-
ring.area = Math.abs(area);
|
|
12267
|
-
if (ccw === void 0) ccw = area < 0;
|
|
12268
|
-
if (ccw === area < 0) {
|
|
12269
|
-
if (polygon) polygons.push(polygon);
|
|
12270
|
-
polygon = [ring];
|
|
12271
|
-
} else polygon.push(ring);
|
|
12272
|
-
}
|
|
12273
|
-
if (polygon) polygons.push(polygon);
|
|
12274
|
-
return polygons;
|
|
12275
|
-
}
|
|
12276
|
-
/**
|
|
12277
|
-
* Returns the signed area for the polygon ring. Positive areas are exterior rings and
|
|
12278
|
-
* have a clockwise winding. Negative areas are interior rings and have a counter clockwise
|
|
12279
|
-
* ordering.
|
|
12280
|
-
*
|
|
12281
|
-
* @param ring - Exterior or interior ring
|
|
12282
|
-
* @returns Signed area
|
|
12283
|
-
*/
|
|
12284
|
-
function calculateSignedArea(ring) {
|
|
12285
|
-
let sum = 0;
|
|
12286
|
-
for (let i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
|
|
12287
|
-
p1 = ring[i];
|
|
12288
|
-
p2 = ring[j];
|
|
12289
|
-
sum += (p2.x - p1.x) * (p1.y + p2.y);
|
|
12290
|
-
}
|
|
12291
|
-
return sum;
|
|
12292
|
-
}
|
|
12293
|
-
|
|
12294
|
-
// src/expression/definitions/assertion.ts
|
|
12295
|
-
const types$1 = {
|
|
12296
|
-
string: StringType,
|
|
12297
|
-
number: NumberType,
|
|
12298
|
-
boolean: BooleanType,
|
|
12299
|
-
object: ObjectType
|
|
12300
|
-
};
|
|
12301
|
-
var Assertion = class Assertion {
|
|
12302
|
-
constructor(type, args, key) {
|
|
12303
|
-
this.type = type;
|
|
12304
|
-
this.args = args;
|
|
12305
|
-
this.key = key;
|
|
12306
|
-
}
|
|
12307
|
-
static parse(args, context) {
|
|
12308
|
-
if (args.length < 2) return context.error("Expected at least one argument.");
|
|
12309
|
-
let i = 1;
|
|
12310
|
-
let type;
|
|
12311
|
-
const name = args[0];
|
|
12312
|
-
if (name === "array") {
|
|
12313
|
-
let itemType;
|
|
12314
|
-
if (args.length > 2) {
|
|
12315
|
-
const type = args[1];
|
|
12316
|
-
if (typeof type !== "string" || !(type in types$1) || type === "object") return context.error("The item type argument of \"array\" must be one of string, number, boolean", 1);
|
|
12317
|
-
itemType = types$1[type];
|
|
12318
|
-
i++;
|
|
12319
|
-
} else itemType = ValueType;
|
|
12320
|
-
let N;
|
|
12321
|
-
if (args.length > 3) {
|
|
12322
|
-
if (args[2] !== null && (typeof args[2] !== "number" || args[2] < 0 || args[2] !== Math.floor(args[2]))) return context.error("The length argument to \"array\" must be a positive integer literal", 2);
|
|
12323
|
-
N = args[2];
|
|
12324
|
-
i++;
|
|
12325
|
-
}
|
|
12326
|
-
type = array(itemType, N);
|
|
12327
|
-
} else {
|
|
12328
|
-
if (!types$1[name]) throw new Error(`Types doesn't contain name = ${name}`);
|
|
12329
|
-
type = types$1[name];
|
|
12330
|
-
}
|
|
12331
|
-
const parsed = [];
|
|
12332
|
-
for (; i < args.length; i++) {
|
|
12333
|
-
const input = context.parse(args[i], i, ValueType);
|
|
12334
|
-
if (!input) return null;
|
|
12335
|
-
parsed.push(input);
|
|
12336
|
-
}
|
|
12337
|
-
return new Assertion(type, parsed, context.key);
|
|
12338
|
-
}
|
|
12339
|
-
evaluate(ctx) {
|
|
12340
|
-
for (let i = 0; i < this.args.length; i++) {
|
|
12341
|
-
const value = this.args[i].evaluate(ctx);
|
|
12342
|
-
if (!checkSubtype(this.type, typeOf(value))) return value;
|
|
12343
|
-
else if (i === this.args.length - 1) throw new RuntimeError(`Expected value to be of type ${typeToString(this.type)}, but found ${typeToString(typeOf(value))} instead.`, this.key);
|
|
12344
|
-
}
|
|
12345
|
-
throw new Error();
|
|
12346
|
-
}
|
|
12347
|
-
eachChild(fn) {
|
|
12348
|
-
this.args.forEach(fn);
|
|
12349
|
-
}
|
|
12350
|
-
outputDefined() {
|
|
12351
|
-
return this.args.every((arg) => arg.outputDefined());
|
|
12352
|
-
}
|
|
12353
|
-
};
|
|
12354
|
-
|
|
12355
|
-
// src/expression/definitions/coercion.ts
|
|
12356
|
-
const types = {
|
|
12357
|
-
"to-boolean": BooleanType,
|
|
12358
|
-
"to-color": ColorType,
|
|
12359
|
-
"to-number": NumberType,
|
|
12360
|
-
"to-string": StringType
|
|
12361
|
-
};
|
|
12362
|
-
/**
|
|
12363
|
-
* Special form for error-coalescing coercion expressions "to-number",
|
|
12364
|
-
* "to-color". Since these coercions can fail at runtime, they accept multiple
|
|
12365
|
-
* arguments, only evaluating one at a time until one succeeds.
|
|
12366
|
-
*
|
|
12367
|
-
* @private
|
|
12368
|
-
*/
|
|
12369
|
-
var Coercion = class Coercion {
|
|
12370
|
-
constructor(type, args, key) {
|
|
12371
|
-
this.type = type;
|
|
12372
|
-
this.args = args;
|
|
12373
|
-
this.key = key;
|
|
12374
|
-
}
|
|
12375
|
-
static parse(args, context) {
|
|
12376
|
-
if (args.length < 2) return context.error("Expected at least one argument.");
|
|
12377
|
-
const name = args[0];
|
|
12378
|
-
if (!types[name]) throw new Error(`Can't parse ${name} as it is not part of the known types`);
|
|
12379
|
-
if ((name === "to-boolean" || name === "to-string") && args.length !== 2) return context.error("Expected one argument.");
|
|
12380
|
-
const type = types[name];
|
|
12381
|
-
const parsed = [];
|
|
12382
|
-
for (let i = 1; i < args.length; i++) {
|
|
12383
|
-
const input = context.parse(args[i], i, ValueType);
|
|
12384
|
-
if (!input) return null;
|
|
12385
|
-
parsed.push(input);
|
|
12386
|
-
}
|
|
12387
|
-
return new Coercion(type, parsed, context.key);
|
|
11997
|
+
return new Coercion(type, parsed, context.key);
|
|
12388
11998
|
}
|
|
12389
11999
|
evaluate(ctx) {
|
|
12390
12000
|
switch (this.type.kind) {
|
|
@@ -12467,8 +12077,172 @@ var Coercion = class Coercion {
|
|
|
12467
12077
|
eachChild(fn) {
|
|
12468
12078
|
this.args.forEach(fn);
|
|
12469
12079
|
}
|
|
12470
|
-
outputDefined() {
|
|
12471
|
-
return this.args.every((arg) => arg.outputDefined());
|
|
12080
|
+
outputDefined() {
|
|
12081
|
+
return this.args.every((arg) => arg.outputDefined());
|
|
12082
|
+
}
|
|
12083
|
+
};
|
|
12084
|
+
|
|
12085
|
+
// src/expression/evaluation_context.ts
|
|
12086
|
+
const geometryTypes = [
|
|
12087
|
+
"Unknown",
|
|
12088
|
+
"Point",
|
|
12089
|
+
"LineString",
|
|
12090
|
+
"Polygon"
|
|
12091
|
+
];
|
|
12092
|
+
var EvaluationContext = class {
|
|
12093
|
+
constructor() {
|
|
12094
|
+
this.globals = null;
|
|
12095
|
+
this.feature = null;
|
|
12096
|
+
this.featureState = null;
|
|
12097
|
+
this.formattedSection = null;
|
|
12098
|
+
this._parseColorCache = /* @__PURE__ */ new Map();
|
|
12099
|
+
this.availableImages = null;
|
|
12100
|
+
this.canonical = null;
|
|
12101
|
+
}
|
|
12102
|
+
id() {
|
|
12103
|
+
return this.feature && "id" in this.feature ? this.feature.id : null;
|
|
12104
|
+
}
|
|
12105
|
+
geometryType() {
|
|
12106
|
+
return this.feature ? typeof this.feature.type === "number" ? geometryTypes[this.feature.type] : this.feature.type : null;
|
|
12107
|
+
}
|
|
12108
|
+
geometry() {
|
|
12109
|
+
return this.feature && "geometry" in this.feature ? this.feature.geometry : null;
|
|
12110
|
+
}
|
|
12111
|
+
canonicalID() {
|
|
12112
|
+
return this.canonical;
|
|
12113
|
+
}
|
|
12114
|
+
properties() {
|
|
12115
|
+
return this.feature && this.feature.properties || {};
|
|
12116
|
+
}
|
|
12117
|
+
parseColor(input) {
|
|
12118
|
+
let cached = this._parseColorCache.get(input);
|
|
12119
|
+
if (!cached) {
|
|
12120
|
+
cached = Color$1.parse(input);
|
|
12121
|
+
this._parseColorCache.set(input, cached);
|
|
12122
|
+
}
|
|
12123
|
+
return cached;
|
|
12124
|
+
}
|
|
12125
|
+
};
|
|
12126
|
+
|
|
12127
|
+
// src/expression/parsing_context.ts
|
|
12128
|
+
/**
|
|
12129
|
+
* State associated parsing at a given point in an expression tree.
|
|
12130
|
+
* @private
|
|
12131
|
+
*/
|
|
12132
|
+
var ParsingContext = class ParsingContext {
|
|
12133
|
+
constructor(registry, isConstantFunc, path = [], expectedType, scope = new Scope(), errors = []) {
|
|
12134
|
+
this.registry = registry;
|
|
12135
|
+
this.path = path;
|
|
12136
|
+
this.key = path.map((part) => `[${part}]`).join("");
|
|
12137
|
+
this.scope = scope;
|
|
12138
|
+
this.errors = errors;
|
|
12139
|
+
this.expectedType = expectedType;
|
|
12140
|
+
this._isConstant = isConstantFunc;
|
|
12141
|
+
}
|
|
12142
|
+
/**
|
|
12143
|
+
* @param expr the JSON expression to parse
|
|
12144
|
+
* @param index the optional argument index if this expression is an argument of a parent expression that's being parsed
|
|
12145
|
+
* @param options
|
|
12146
|
+
* @param options.omitTypeAnnotations set true to omit inferred type annotations. Caller beware: with this option set, the parsed expression's type will NOT satisfy `expectedType` if it would normally be wrapped in an inferred annotation.
|
|
12147
|
+
* @private
|
|
12148
|
+
*/
|
|
12149
|
+
parse(expr, index, expectedType, bindings, options = {}) {
|
|
12150
|
+
if (index != null) return this.concat(index, expectedType, bindings)._parse(expr, options);
|
|
12151
|
+
return this._parse(expr, options);
|
|
12152
|
+
}
|
|
12153
|
+
_parse(expr, options) {
|
|
12154
|
+
if (expr === null || typeof expr === "string" || typeof expr === "boolean" || typeof expr === "number") expr = ["literal", expr];
|
|
12155
|
+
const key = this.key;
|
|
12156
|
+
function annotate(parsed, type, typeAnnotation) {
|
|
12157
|
+
if (typeAnnotation === "assert") return new Assertion(type, [parsed], key);
|
|
12158
|
+
else if (typeAnnotation === "coerce") return new Coercion(type, [parsed], key);
|
|
12159
|
+
else return parsed;
|
|
12160
|
+
}
|
|
12161
|
+
if (Array.isArray(expr)) {
|
|
12162
|
+
if (expr.length === 0) return this.error("Expected an array with at least one element. If you wanted a literal array, use [\"literal\", []].");
|
|
12163
|
+
const op = expr[0];
|
|
12164
|
+
if (typeof op !== "string") {
|
|
12165
|
+
this.error(`Expression name must be a string, but found ${typeof op} instead. If you wanted a literal array, use ["literal", [...]].`, 0);
|
|
12166
|
+
return null;
|
|
12167
|
+
}
|
|
12168
|
+
const Expr = this.registry[op];
|
|
12169
|
+
if (Expr) {
|
|
12170
|
+
let parsed = Expr.parse(expr, this);
|
|
12171
|
+
if (!parsed) return null;
|
|
12172
|
+
if (this.expectedType) {
|
|
12173
|
+
const expected = this.expectedType;
|
|
12174
|
+
const actual = parsed.type;
|
|
12175
|
+
if ((expected.kind === "string" || expected.kind === "number" || expected.kind === "boolean" || expected.kind === "object" || expected.kind === "array") && actual.kind === "value") parsed = annotate(parsed, expected, options.typeAnnotation || "assert");
|
|
12176
|
+
else if ("projectionDefinition" === expected.kind && [
|
|
12177
|
+
"string",
|
|
12178
|
+
"array",
|
|
12179
|
+
"value"
|
|
12180
|
+
].includes(actual.kind) || [
|
|
12181
|
+
"color",
|
|
12182
|
+
"formatted",
|
|
12183
|
+
"resolvedImage"
|
|
12184
|
+
].includes(expected.kind) && ["value", "string"].includes(actual.kind) || ["padding", "numberArray"].includes(expected.kind) && [
|
|
12185
|
+
"value",
|
|
12186
|
+
"number",
|
|
12187
|
+
"array"
|
|
12188
|
+
].includes(actual.kind) || "colorArray" === expected.kind && [
|
|
12189
|
+
"value",
|
|
12190
|
+
"string",
|
|
12191
|
+
"array"
|
|
12192
|
+
].includes(actual.kind) || "variableAnchorOffsetCollection" === expected.kind && ["value", "array"].includes(actual.kind)) parsed = annotate(parsed, expected, options.typeAnnotation || "coerce");
|
|
12193
|
+
else if (this.checkSubtype(expected, actual)) return null;
|
|
12194
|
+
}
|
|
12195
|
+
if (!(parsed instanceof Literal) && parsed.type.kind !== "resolvedImage" && this._isConstant(parsed)) {
|
|
12196
|
+
const ec = new EvaluationContext();
|
|
12197
|
+
try {
|
|
12198
|
+
parsed = new Literal(parsed.type, parsed.evaluate(ec));
|
|
12199
|
+
} catch (e) {
|
|
12200
|
+
this.error(e.message);
|
|
12201
|
+
return null;
|
|
12202
|
+
}
|
|
12203
|
+
}
|
|
12204
|
+
return parsed;
|
|
12205
|
+
}
|
|
12206
|
+
return this.error(`Unknown expression "${op}". If you wanted a literal array, use ["literal", [...]].`, 0);
|
|
12207
|
+
} else if (typeof expr === "undefined") return this.error("'undefined' value invalid. Use null instead.");
|
|
12208
|
+
else if (typeof expr === "object") return this.error("Bare objects invalid. Use [\"literal\", {...}] instead.");
|
|
12209
|
+
else return this.error(`Expected an array, but found ${typeof expr} instead.`);
|
|
12210
|
+
}
|
|
12211
|
+
/**
|
|
12212
|
+
* Returns a copy of this context suitable for parsing the subexpression at
|
|
12213
|
+
* index `index`, optionally appending to 'let' binding map.
|
|
12214
|
+
*
|
|
12215
|
+
* Note that `errors` property, intended for collecting errors while
|
|
12216
|
+
* parsing, is copied by reference rather than cloned.
|
|
12217
|
+
* @private
|
|
12218
|
+
*/
|
|
12219
|
+
concat(index, expectedType, bindings) {
|
|
12220
|
+
const path = typeof index === "number" ? this.path.concat(index) : this.path;
|
|
12221
|
+
const scope = bindings ? this.scope.concat(bindings) : this.scope;
|
|
12222
|
+
return new ParsingContext(this.registry, this._isConstant, path, expectedType || null, scope, this.errors);
|
|
12223
|
+
}
|
|
12224
|
+
/**
|
|
12225
|
+
* Push a parsing (or type checking) error into the `this.errors`
|
|
12226
|
+
* @param error The message
|
|
12227
|
+
* @param keys Optionally specify the source of the error at a child
|
|
12228
|
+
* of the current expression at `this.key`.
|
|
12229
|
+
* @private
|
|
12230
|
+
*/
|
|
12231
|
+
error(error, ...keys) {
|
|
12232
|
+
const key = `${this.key}${keys.map((k) => `[${k}]`).join("")}`;
|
|
12233
|
+
this.errors.push(new ExpressionParsingError(key, error));
|
|
12234
|
+
}
|
|
12235
|
+
/**
|
|
12236
|
+
* Returns null if `t` is a subtype of `expected`; otherwise returns an
|
|
12237
|
+
* error message and also pushes it to `this.errors`.
|
|
12238
|
+
* @param expected The expected type
|
|
12239
|
+
* @param t The actual type
|
|
12240
|
+
* @returns null if `t` is a subtype of `expected`; otherwise returns an error message
|
|
12241
|
+
*/
|
|
12242
|
+
checkSubtype(expected, t) {
|
|
12243
|
+
const error = checkSubtype(expected, t);
|
|
12244
|
+
if (error) this.error(error);
|
|
12245
|
+
return error;
|
|
12472
12246
|
}
|
|
12473
12247
|
};
|
|
12474
12248
|
|
|
@@ -12740,70 +12514,343 @@ var Case = class Case {
|
|
|
12740
12514
|
branches.push([test, result]);
|
|
12741
12515
|
outputType = outputType || result.type;
|
|
12742
12516
|
}
|
|
12743
|
-
const otherwise = context.parse(args[args.length - 1], args.length - 1, outputType);
|
|
12744
|
-
if (!otherwise) return null;
|
|
12745
|
-
if (!outputType) throw new Error("Can't infer output type");
|
|
12746
|
-
return new Case(outputType, branches, otherwise);
|
|
12517
|
+
const otherwise = context.parse(args[args.length - 1], args.length - 1, outputType);
|
|
12518
|
+
if (!otherwise) return null;
|
|
12519
|
+
if (!outputType) throw new Error("Can't infer output type");
|
|
12520
|
+
return new Case(outputType, branches, otherwise);
|
|
12521
|
+
}
|
|
12522
|
+
evaluate(ctx) {
|
|
12523
|
+
for (const [test, expression] of this.branches) if (test.evaluate(ctx)) return expression.evaluate(ctx);
|
|
12524
|
+
return this.otherwise.evaluate(ctx);
|
|
12525
|
+
}
|
|
12526
|
+
eachChild(fn) {
|
|
12527
|
+
for (const [test, expression] of this.branches) {
|
|
12528
|
+
fn(test);
|
|
12529
|
+
fn(expression);
|
|
12530
|
+
}
|
|
12531
|
+
fn(this.otherwise);
|
|
12532
|
+
}
|
|
12533
|
+
outputDefined() {
|
|
12534
|
+
return this.branches.every(([_, out]) => out.outputDefined()) && this.otherwise.outputDefined();
|
|
12535
|
+
}
|
|
12536
|
+
};
|
|
12537
|
+
|
|
12538
|
+
// src/expression/definitions/slice.ts
|
|
12539
|
+
var Slice = class Slice {
|
|
12540
|
+
constructor(type, input, beginIndex, key, endIndex) {
|
|
12541
|
+
this.type = type;
|
|
12542
|
+
this.input = input;
|
|
12543
|
+
this.beginIndex = beginIndex;
|
|
12544
|
+
this.key = key;
|
|
12545
|
+
this.endIndex = endIndex;
|
|
12546
|
+
}
|
|
12547
|
+
static parse(args, context) {
|
|
12548
|
+
if (args.length <= 2 || args.length >= 5) return context.error(`Expected 2 or 3 arguments, but found ${args.length - 1} instead.`);
|
|
12549
|
+
const input = context.parse(args[1], 1, ValueType);
|
|
12550
|
+
const beginIndex = context.parse(args[2], 2, NumberType);
|
|
12551
|
+
if (!input || !beginIndex) return null;
|
|
12552
|
+
if (!isValidType(input.type, [
|
|
12553
|
+
array(ValueType),
|
|
12554
|
+
StringType,
|
|
12555
|
+
ValueType
|
|
12556
|
+
])) return context.error(`Expected first argument to be of type array or string, but found ${typeToString(input.type)} instead`);
|
|
12557
|
+
if (args.length === 4) {
|
|
12558
|
+
const endIndex = context.parse(args[3], 3, NumberType);
|
|
12559
|
+
if (!endIndex) return null;
|
|
12560
|
+
return new Slice(input.type, input, beginIndex, context.key, endIndex);
|
|
12561
|
+
} else return new Slice(input.type, input, beginIndex, context.key);
|
|
12562
|
+
}
|
|
12563
|
+
evaluate(ctx) {
|
|
12564
|
+
const input = this.input.evaluate(ctx);
|
|
12565
|
+
const beginIndex = this.beginIndex.evaluate(ctx);
|
|
12566
|
+
let endIndex;
|
|
12567
|
+
if (this.endIndex) endIndex = this.endIndex.evaluate(ctx);
|
|
12568
|
+
if (isValidNativeType(input, ["string"])) return [...input].slice(beginIndex, endIndex).join("");
|
|
12569
|
+
else if (isValidNativeType(input, ["array"])) return input.slice(beginIndex, endIndex);
|
|
12570
|
+
else throw new RuntimeError(`Expected first argument to be of type array or string, but found ${typeToString(typeOf(input))} instead.`, this.key);
|
|
12571
|
+
}
|
|
12572
|
+
eachChild(fn) {
|
|
12573
|
+
fn(this.input);
|
|
12574
|
+
fn(this.beginIndex);
|
|
12575
|
+
if (this.endIndex) fn(this.endIndex);
|
|
12576
|
+
}
|
|
12577
|
+
outputDefined() {
|
|
12578
|
+
return false;
|
|
12579
|
+
}
|
|
12580
|
+
};
|
|
12581
|
+
|
|
12582
|
+
// src/expression/stops.ts
|
|
12583
|
+
/**
|
|
12584
|
+
* Returns the index of the last stop <= input, or 0 if it doesn't exist.
|
|
12585
|
+
* @private
|
|
12586
|
+
*/
|
|
12587
|
+
function findStopLessThanOrEqualTo(stops, input, key) {
|
|
12588
|
+
const lastIndex = stops.length - 1;
|
|
12589
|
+
let lowerIndex = 0;
|
|
12590
|
+
let upperIndex = lastIndex;
|
|
12591
|
+
let currentIndex = 0;
|
|
12592
|
+
let currentValue, nextValue;
|
|
12593
|
+
while (lowerIndex <= upperIndex) {
|
|
12594
|
+
currentIndex = Math.floor((lowerIndex + upperIndex) / 2);
|
|
12595
|
+
currentValue = stops[currentIndex];
|
|
12596
|
+
nextValue = stops[currentIndex + 1];
|
|
12597
|
+
if (currentValue <= input) {
|
|
12598
|
+
if (currentIndex === lastIndex || input < nextValue) return currentIndex;
|
|
12599
|
+
lowerIndex = currentIndex + 1;
|
|
12600
|
+
} else if (currentValue > input) upperIndex = currentIndex - 1;
|
|
12601
|
+
else throw new RuntimeError("Input is not a number.", key);
|
|
12602
|
+
}
|
|
12603
|
+
return 0;
|
|
12604
|
+
}
|
|
12605
|
+
|
|
12606
|
+
// src/expression/definitions/step.ts
|
|
12607
|
+
var Step = class Step {
|
|
12608
|
+
constructor(type, input, stops, key) {
|
|
12609
|
+
this.type = type;
|
|
12610
|
+
this.input = input;
|
|
12611
|
+
this.key = key;
|
|
12612
|
+
this.labels = [];
|
|
12613
|
+
this.outputs = [];
|
|
12614
|
+
for (const [label, expression] of stops) {
|
|
12615
|
+
this.labels.push(label);
|
|
12616
|
+
this.outputs.push(expression);
|
|
12617
|
+
}
|
|
12618
|
+
}
|
|
12619
|
+
static parse(args, context) {
|
|
12620
|
+
if (args.length - 1 < 4) return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
|
12621
|
+
if ((args.length - 1) % 2 !== 0) return context.error("Expected an even number of arguments.");
|
|
12622
|
+
const input = context.parse(args[1], 1, NumberType);
|
|
12623
|
+
if (!input) return null;
|
|
12624
|
+
const stops = [];
|
|
12625
|
+
let outputType = null;
|
|
12626
|
+
if (context.expectedType && context.expectedType.kind !== "value") outputType = context.expectedType;
|
|
12627
|
+
for (let i = 1; i < args.length; i += 2) {
|
|
12628
|
+
const label = i === 1 ? -Infinity : args[i];
|
|
12629
|
+
const value = args[i + 1];
|
|
12630
|
+
const labelKey = i;
|
|
12631
|
+
const valueKey = i + 1;
|
|
12632
|
+
if (typeof label !== "number") return context.error("Input/output pairs for \"step\" expressions must be defined using literal numeric values (not computed expressions) for the input values.", labelKey);
|
|
12633
|
+
if (stops.length && stops[stops.length - 1][0] >= label) return context.error("Input/output pairs for \"step\" expressions must be arranged with input values in strictly ascending order.", labelKey);
|
|
12634
|
+
const parsed = context.parse(value, valueKey, outputType);
|
|
12635
|
+
if (!parsed) return null;
|
|
12636
|
+
outputType = outputType || parsed.type;
|
|
12637
|
+
stops.push([label, parsed]);
|
|
12638
|
+
}
|
|
12639
|
+
return new Step(outputType, input, stops, context.key);
|
|
12640
|
+
}
|
|
12641
|
+
evaluate(ctx) {
|
|
12642
|
+
const labels = this.labels;
|
|
12643
|
+
const outputs = this.outputs;
|
|
12644
|
+
if (labels.length === 1) return outputs[0].evaluate(ctx);
|
|
12645
|
+
const value = this.input.evaluate(ctx);
|
|
12646
|
+
if (value <= labels[0]) return outputs[0].evaluate(ctx);
|
|
12647
|
+
const stopCount = labels.length;
|
|
12648
|
+
if (value >= labels[stopCount - 1]) return outputs[stopCount - 1].evaluate(ctx);
|
|
12649
|
+
return outputs[findStopLessThanOrEqualTo(labels, value, this.key)].evaluate(ctx);
|
|
12650
|
+
}
|
|
12651
|
+
eachChild(fn) {
|
|
12652
|
+
fn(this.input);
|
|
12653
|
+
for (const expression of this.outputs) fn(expression);
|
|
12654
|
+
}
|
|
12655
|
+
outputDefined() {
|
|
12656
|
+
return this.outputs.every((out) => out.outputDefined());
|
|
12657
|
+
}
|
|
12658
|
+
};
|
|
12659
|
+
|
|
12660
|
+
// node_modules/@mapbox/unitbezier/index.js
|
|
12661
|
+
function unitBezier(p1x, p1y, p2x, p2y) {
|
|
12662
|
+
const cx = 3 * p1x;
|
|
12663
|
+
const bx = 3 * (p2x - p1x) - cx;
|
|
12664
|
+
const ax = 1 - cx - bx;
|
|
12665
|
+
const cy = 3 * p1y;
|
|
12666
|
+
const by = 3 * (p2y - p1y) - cy;
|
|
12667
|
+
const ay = 1 - cy - by;
|
|
12668
|
+
return function solve(x, epsilon = 1e-6) {
|
|
12669
|
+
if (x <= 0) return 0;
|
|
12670
|
+
if (x >= 1) return 1;
|
|
12671
|
+
let t = x;
|
|
12672
|
+
for (let i = 0; i < 8; i++) {
|
|
12673
|
+
const x2 = ((ax * t + bx) * t + cx) * t - x;
|
|
12674
|
+
if (Math.abs(x2) < epsilon) return ((ay * t + by) * t + cy) * t;
|
|
12675
|
+
const d2 = (3 * ax * t + 2 * bx) * t + cx;
|
|
12676
|
+
if (Math.abs(d2) < 1e-6) break;
|
|
12677
|
+
t -= x2 / d2;
|
|
12678
|
+
}
|
|
12679
|
+
let t0 = 0;
|
|
12680
|
+
let t1 = 1;
|
|
12681
|
+
t = x;
|
|
12682
|
+
for (let i = 0; i < 20; i++) {
|
|
12683
|
+
const x2 = ((ax * t + bx) * t + cx) * t;
|
|
12684
|
+
if (Math.abs(x2 - x) < epsilon) break;
|
|
12685
|
+
if (x > x2) t0 = t;
|
|
12686
|
+
else t1 = t;
|
|
12687
|
+
t = (t0 + t1) * .5;
|
|
12688
|
+
}
|
|
12689
|
+
return ((ay * t + by) * t + cy) * t;
|
|
12690
|
+
};
|
|
12691
|
+
}
|
|
12692
|
+
|
|
12693
|
+
// src/expression/definitions/interpolate.ts
|
|
12694
|
+
var Interpolate = class Interpolate {
|
|
12695
|
+
constructor(type, operator, interpolation, input, stops, key) {
|
|
12696
|
+
this.type = type;
|
|
12697
|
+
this.operator = operator;
|
|
12698
|
+
this.interpolation = interpolation;
|
|
12699
|
+
this.input = input;
|
|
12700
|
+
this.key = key;
|
|
12701
|
+
this.labels = [];
|
|
12702
|
+
this.outputs = [];
|
|
12703
|
+
for (const [label, expression] of stops) {
|
|
12704
|
+
this.labels.push(label);
|
|
12705
|
+
this.outputs.push(expression);
|
|
12706
|
+
}
|
|
12707
|
+
}
|
|
12708
|
+
static interpolationFactor(interpolation, input, lower, upper) {
|
|
12709
|
+
let t = 0;
|
|
12710
|
+
if (interpolation.name === "exponential") t = exponentialInterpolation(input, interpolation.base, lower, upper);
|
|
12711
|
+
else if (interpolation.name === "linear") t = exponentialInterpolation(input, 1, lower, upper);
|
|
12712
|
+
else if (interpolation.name === "cubic-bezier") {
|
|
12713
|
+
const c = interpolation.controlPoints;
|
|
12714
|
+
t = unitBezier(c[0], c[1], c[2], c[3])(exponentialInterpolation(input, 1, lower, upper));
|
|
12715
|
+
}
|
|
12716
|
+
return t;
|
|
12717
|
+
}
|
|
12718
|
+
static parse(args, context) {
|
|
12719
|
+
let [operator, interpolation, input, ...rest] = args;
|
|
12720
|
+
if (!Array.isArray(interpolation) || interpolation.length === 0) return context.error("Expected an interpolation type expression.", 1);
|
|
12721
|
+
if (interpolation[0] === "linear") interpolation = { name: "linear" };
|
|
12722
|
+
else if (interpolation[0] === "exponential") {
|
|
12723
|
+
const base = interpolation[1];
|
|
12724
|
+
if (typeof base !== "number") return context.error("Exponential interpolation requires a numeric base.", 1, 1);
|
|
12725
|
+
interpolation = {
|
|
12726
|
+
name: "exponential",
|
|
12727
|
+
base
|
|
12728
|
+
};
|
|
12729
|
+
} else if (interpolation[0] === "cubic-bezier") {
|
|
12730
|
+
const controlPoints = interpolation.slice(1);
|
|
12731
|
+
if (controlPoints.length !== 4 || controlPoints.some((t) => typeof t !== "number" || t < 0 || t > 1)) return context.error("Cubic bezier interpolation requires four numeric arguments with values between 0 and 1.", 1);
|
|
12732
|
+
interpolation = {
|
|
12733
|
+
name: "cubic-bezier",
|
|
12734
|
+
controlPoints
|
|
12735
|
+
};
|
|
12736
|
+
} else return context.error(`Unknown interpolation type ${String(interpolation[0])}`, 1, 0);
|
|
12737
|
+
if (args.length - 1 < 4) return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
|
12738
|
+
if ((args.length - 1) % 2 !== 0) return context.error("Expected an even number of arguments.");
|
|
12739
|
+
input = context.parse(input, 2, NumberType);
|
|
12740
|
+
if (!input) return null;
|
|
12741
|
+
const stops = [];
|
|
12742
|
+
let outputType = null;
|
|
12743
|
+
if ((operator === "interpolate-hcl" || operator === "interpolate-lab") && context.expectedType != ColorArrayType) outputType = ColorType;
|
|
12744
|
+
else if (context.expectedType && context.expectedType.kind !== "value") outputType = context.expectedType;
|
|
12745
|
+
for (let i = 0; i < rest.length; i += 2) {
|
|
12746
|
+
const label = rest[i];
|
|
12747
|
+
const value = rest[i + 1];
|
|
12748
|
+
const labelKey = i + 3;
|
|
12749
|
+
const valueKey = i + 4;
|
|
12750
|
+
if (typeof label !== "number") return context.error("Input/output pairs for \"interpolate\" expressions must be defined using literal numeric values (not computed expressions) for the input values.", labelKey);
|
|
12751
|
+
if (stops.length && stops[stops.length - 1][0] >= label) return context.error("Input/output pairs for \"interpolate\" expressions must be arranged with input values in strictly ascending order.", labelKey);
|
|
12752
|
+
const parsed = context.parse(value, valueKey, outputType);
|
|
12753
|
+
if (!parsed) return null;
|
|
12754
|
+
outputType = outputType || parsed.type;
|
|
12755
|
+
stops.push([label, parsed]);
|
|
12756
|
+
}
|
|
12757
|
+
if (!verifyType(outputType, NumberType) && !verifyType(outputType, ProjectionDefinitionType) && !verifyType(outputType, ColorType) && !verifyType(outputType, PaddingType) && !verifyType(outputType, NumberArrayType) && !verifyType(outputType, ColorArrayType) && !verifyType(outputType, VariableAnchorOffsetCollectionType) && !verifyType(outputType, array(NumberType))) return context.error(`Type ${typeToString(outputType)} is not interpolatable.`);
|
|
12758
|
+
return new Interpolate(outputType, operator, interpolation, input, stops, context.key);
|
|
12747
12759
|
}
|
|
12748
12760
|
evaluate(ctx) {
|
|
12749
|
-
|
|
12750
|
-
|
|
12751
|
-
|
|
12752
|
-
|
|
12753
|
-
|
|
12754
|
-
|
|
12755
|
-
|
|
12761
|
+
const labels = this.labels;
|
|
12762
|
+
const outputs = this.outputs;
|
|
12763
|
+
if (labels.length === 1) return outputs[0].evaluate(ctx);
|
|
12764
|
+
const value = this.input.evaluate(ctx);
|
|
12765
|
+
if (value <= labels[0]) return outputs[0].evaluate(ctx);
|
|
12766
|
+
const stopCount = labels.length;
|
|
12767
|
+
if (value >= labels[stopCount - 1]) return outputs[stopCount - 1].evaluate(ctx);
|
|
12768
|
+
const index = findStopLessThanOrEqualTo(labels, value, this.key);
|
|
12769
|
+
const lower = labels[index];
|
|
12770
|
+
const upper = labels[index + 1];
|
|
12771
|
+
const t = Interpolate.interpolationFactor(this.interpolation, value, lower, upper);
|
|
12772
|
+
const outputLower = outputs[index].evaluate(ctx);
|
|
12773
|
+
const outputUpper = outputs[index + 1].evaluate(ctx);
|
|
12774
|
+
switch (this.operator) {
|
|
12775
|
+
case "interpolate": switch (this.type.kind) {
|
|
12776
|
+
case "number": return interpolateNumber(outputLower, outputUpper, t);
|
|
12777
|
+
case "color": return Color$1.interpolate(outputLower, outputUpper, t);
|
|
12778
|
+
case "padding": return Padding.interpolate(outputLower, outputUpper, t);
|
|
12779
|
+
case "colorArray": return ColorArray.interpolate(outputLower, outputUpper, t);
|
|
12780
|
+
case "numberArray": return NumberArray.interpolate(outputLower, outputUpper, t);
|
|
12781
|
+
case "variableAnchorOffsetCollection": return VariableAnchorOffsetCollection.interpolate(outputLower, outputUpper, t, this.key);
|
|
12782
|
+
case "array": return interpolateArray(outputLower, outputUpper, t);
|
|
12783
|
+
case "projectionDefinition": return ProjectionDefinition.interpolate(outputLower, outputUpper, t);
|
|
12784
|
+
}
|
|
12785
|
+
case "interpolate-hcl": switch (this.type.kind) {
|
|
12786
|
+
case "color": return Color$1.interpolate(outputLower, outputUpper, t, "hcl");
|
|
12787
|
+
case "colorArray": return ColorArray.interpolate(outputLower, outputUpper, t, "hcl");
|
|
12788
|
+
}
|
|
12789
|
+
case "interpolate-lab": switch (this.type.kind) {
|
|
12790
|
+
case "color": return Color$1.interpolate(outputLower, outputUpper, t, "lab");
|
|
12791
|
+
case "colorArray": return ColorArray.interpolate(outputLower, outputUpper, t, "lab");
|
|
12792
|
+
}
|
|
12756
12793
|
}
|
|
12757
|
-
fn(this.otherwise);
|
|
12758
|
-
}
|
|
12759
|
-
outputDefined() {
|
|
12760
|
-
return this.branches.every(([_, out]) => out.outputDefined()) && this.otherwise.outputDefined();
|
|
12761
|
-
}
|
|
12762
|
-
};
|
|
12763
|
-
|
|
12764
|
-
// src/expression/definitions/slice.ts
|
|
12765
|
-
var Slice = class Slice {
|
|
12766
|
-
constructor(type, input, beginIndex, key, endIndex) {
|
|
12767
|
-
this.type = type;
|
|
12768
|
-
this.input = input;
|
|
12769
|
-
this.beginIndex = beginIndex;
|
|
12770
|
-
this.key = key;
|
|
12771
|
-
this.endIndex = endIndex;
|
|
12772
|
-
}
|
|
12773
|
-
static parse(args, context) {
|
|
12774
|
-
if (args.length <= 2 || args.length >= 5) return context.error(`Expected 2 or 3 arguments, but found ${args.length - 1} instead.`);
|
|
12775
|
-
const input = context.parse(args[1], 1, ValueType);
|
|
12776
|
-
const beginIndex = context.parse(args[2], 2, NumberType);
|
|
12777
|
-
if (!input || !beginIndex) return null;
|
|
12778
|
-
if (!isValidType(input.type, [
|
|
12779
|
-
array(ValueType),
|
|
12780
|
-
StringType,
|
|
12781
|
-
ValueType
|
|
12782
|
-
])) return context.error(`Expected first argument to be of type array or string, but found ${typeToString(input.type)} instead`);
|
|
12783
|
-
if (args.length === 4) {
|
|
12784
|
-
const endIndex = context.parse(args[3], 3, NumberType);
|
|
12785
|
-
if (!endIndex) return null;
|
|
12786
|
-
return new Slice(input.type, input, beginIndex, context.key, endIndex);
|
|
12787
|
-
} else return new Slice(input.type, input, beginIndex, context.key);
|
|
12788
|
-
}
|
|
12789
|
-
evaluate(ctx) {
|
|
12790
|
-
const input = this.input.evaluate(ctx);
|
|
12791
|
-
const beginIndex = this.beginIndex.evaluate(ctx);
|
|
12792
|
-
let endIndex;
|
|
12793
|
-
if (this.endIndex) endIndex = this.endIndex.evaluate(ctx);
|
|
12794
|
-
if (isValidNativeType(input, ["string"])) return [...input].slice(beginIndex, endIndex).join("");
|
|
12795
|
-
else if (isValidNativeType(input, ["array"])) return input.slice(beginIndex, endIndex);
|
|
12796
|
-
else throw new RuntimeError(`Expected first argument to be of type array or string, but found ${typeToString(typeOf(input))} instead.`, this.key);
|
|
12797
12794
|
}
|
|
12798
12795
|
eachChild(fn) {
|
|
12799
12796
|
fn(this.input);
|
|
12800
|
-
|
|
12801
|
-
if (this.endIndex) fn(this.endIndex);
|
|
12797
|
+
for (const expression of this.outputs) fn(expression);
|
|
12802
12798
|
}
|
|
12803
12799
|
outputDefined() {
|
|
12804
|
-
return
|
|
12800
|
+
return this.outputs.every((out) => out.outputDefined());
|
|
12805
12801
|
}
|
|
12806
12802
|
};
|
|
12803
|
+
/**
|
|
12804
|
+
* Returns a ratio that can be used to interpolate between exponential function
|
|
12805
|
+
* stops.
|
|
12806
|
+
* 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,
|
|
12807
|
+
* and `a` and `b` are constants affording sufficient degrees of freedom to fit
|
|
12808
|
+
* the function to the given stops.
|
|
12809
|
+
*
|
|
12810
|
+
* Here's a bit of algebra that lets us compute `f(x)` directly from the stop
|
|
12811
|
+
* values without explicitly solving for `a` and `b`:
|
|
12812
|
+
*
|
|
12813
|
+
* First stop value: `f(x0) = y0 = a * base^x0 + b`
|
|
12814
|
+
* Second stop value: `f(x1) = y1 = a * base^x1 + b`
|
|
12815
|
+
* => `y1 - y0 = a(base^x1 - base^x0)`
|
|
12816
|
+
* => `a = (y1 - y0)/(base^x1 - base^x0)`
|
|
12817
|
+
*
|
|
12818
|
+
* Desired value: `f(x) = y = a * base^x + b`
|
|
12819
|
+
* => `f(x) = y0 + a * (base^x - base^x0)`
|
|
12820
|
+
*
|
|
12821
|
+
* From the above, we can replace the `a` in `a * (base^x - base^x0)` and do a
|
|
12822
|
+
* little algebra:
|
|
12823
|
+
* ```
|
|
12824
|
+
* a * (base^x - base^x0) = (y1 - y0)/(base^x1 - base^x0) * (base^x - base^x0)
|
|
12825
|
+
* = (y1 - y0) * (base^x - base^x0) / (base^x1 - base^x0)
|
|
12826
|
+
* ```
|
|
12827
|
+
*
|
|
12828
|
+
* If we let `(base^x - base^x0) / (base^x1 base^x0)`, then we have
|
|
12829
|
+
* `f(x) = y0 + (y1 - y0) * ratio`. In other words, `ratio` may be treated as
|
|
12830
|
+
* an interpolation factor between the two stops' output values.
|
|
12831
|
+
*
|
|
12832
|
+
* (Note: a slightly different form for `ratio`,
|
|
12833
|
+
* `(base^(x-x0) - 1) / (base^(x1-x0) - 1) `, is equivalent, but requires fewer
|
|
12834
|
+
* expensive `Math.pow()` operations.)
|
|
12835
|
+
*
|
|
12836
|
+
* @private
|
|
12837
|
+
*/
|
|
12838
|
+
function exponentialInterpolation(input, base, lowerValue, upperValue) {
|
|
12839
|
+
const difference = upperValue - lowerValue;
|
|
12840
|
+
const progress = input - lowerValue;
|
|
12841
|
+
if (difference === 0) return 0;
|
|
12842
|
+
else if (base === 1) return progress / difference;
|
|
12843
|
+
else return (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
|
|
12844
|
+
}
|
|
12845
|
+
const interpolateFactory = {
|
|
12846
|
+
color: Color$1.interpolate,
|
|
12847
|
+
number: interpolateNumber,
|
|
12848
|
+
padding: Padding.interpolate,
|
|
12849
|
+
numberArray: NumberArray.interpolate,
|
|
12850
|
+
colorArray: ColorArray.interpolate,
|
|
12851
|
+
variableAnchorOffsetCollection: VariableAnchorOffsetCollection.interpolate,
|
|
12852
|
+
array: interpolateArray
|
|
12853
|
+
};
|
|
12807
12854
|
|
|
12808
12855
|
// src/expression/definitions/coalesce.ts
|
|
12809
12856
|
var Coalesce = class Coalesce {
|
|
@@ -13076,6 +13123,87 @@ var NumberFormat = class NumberFormat {
|
|
|
13076
13123
|
}
|
|
13077
13124
|
};
|
|
13078
13125
|
|
|
13126
|
+
// src/expression/definitions/format.ts
|
|
13127
|
+
var FormatExpression = class FormatExpression {
|
|
13128
|
+
constructor(sections) {
|
|
13129
|
+
this.type = FormattedType;
|
|
13130
|
+
this.sections = sections;
|
|
13131
|
+
}
|
|
13132
|
+
static parse(args, context) {
|
|
13133
|
+
if (args.length < 2) return context.error("Expected at least one argument.");
|
|
13134
|
+
const firstArg = args[1];
|
|
13135
|
+
if (!Array.isArray(firstArg) && typeof firstArg === "object") return context.error("First argument must be an image or text section.");
|
|
13136
|
+
const sections = [];
|
|
13137
|
+
let nextTokenMayBeObject = false;
|
|
13138
|
+
for (let i = 1; i <= args.length - 1; ++i) {
|
|
13139
|
+
const arg = args[i];
|
|
13140
|
+
if (nextTokenMayBeObject && typeof arg === "object" && !Array.isArray(arg)) {
|
|
13141
|
+
nextTokenMayBeObject = false;
|
|
13142
|
+
let scale = null;
|
|
13143
|
+
if (arg["font-scale"]) {
|
|
13144
|
+
scale = context.parse(arg["font-scale"], 1, NumberType);
|
|
13145
|
+
if (!scale) return null;
|
|
13146
|
+
}
|
|
13147
|
+
let font = null;
|
|
13148
|
+
if (arg["text-font"]) {
|
|
13149
|
+
font = context.parse(arg["text-font"], 1, array(StringType));
|
|
13150
|
+
if (!font) return null;
|
|
13151
|
+
}
|
|
13152
|
+
let textColor = null;
|
|
13153
|
+
if (arg["text-color"]) {
|
|
13154
|
+
textColor = context.parse(arg["text-color"], 1, ColorType);
|
|
13155
|
+
if (!textColor) return null;
|
|
13156
|
+
}
|
|
13157
|
+
let verticalAlign = null;
|
|
13158
|
+
if (arg["vertical-align"]) {
|
|
13159
|
+
if (typeof arg["vertical-align"] === "string" && !VERTICAL_ALIGN_OPTIONS.includes(arg["vertical-align"])) return context.error(`'vertical-align' must be one of: 'bottom', 'center', 'top' but found '${arg["vertical-align"]}' instead.`);
|
|
13160
|
+
verticalAlign = context.parse(arg["vertical-align"], 1, StringType);
|
|
13161
|
+
if (!verticalAlign) return null;
|
|
13162
|
+
}
|
|
13163
|
+
const lastExpression = sections[sections.length - 1];
|
|
13164
|
+
lastExpression.scale = scale;
|
|
13165
|
+
lastExpression.font = font;
|
|
13166
|
+
lastExpression.textColor = textColor;
|
|
13167
|
+
lastExpression.verticalAlign = verticalAlign;
|
|
13168
|
+
} else {
|
|
13169
|
+
const content = context.parse(args[i], 1, ValueType);
|
|
13170
|
+
if (!content) return null;
|
|
13171
|
+
const kind = content.type.kind;
|
|
13172
|
+
if (kind !== "string" && kind !== "value" && kind !== "null" && kind !== "resolvedImage") return context.error("Formatted text type must be 'string', 'value', 'image' or 'null'.");
|
|
13173
|
+
nextTokenMayBeObject = true;
|
|
13174
|
+
sections.push({
|
|
13175
|
+
content,
|
|
13176
|
+
scale: null,
|
|
13177
|
+
font: null,
|
|
13178
|
+
textColor: null,
|
|
13179
|
+
verticalAlign: null
|
|
13180
|
+
});
|
|
13181
|
+
}
|
|
13182
|
+
}
|
|
13183
|
+
return new FormatExpression(sections);
|
|
13184
|
+
}
|
|
13185
|
+
evaluate(ctx) {
|
|
13186
|
+
const evaluateSection = (section) => {
|
|
13187
|
+
const evaluatedContent = section.content.evaluate(ctx);
|
|
13188
|
+
if (typeOf(evaluatedContent) === ResolvedImageType) return new FormattedSection("", evaluatedContent, null, null, null, section.verticalAlign ? section.verticalAlign.evaluate(ctx) : null);
|
|
13189
|
+
return new FormattedSection(valueToString(evaluatedContent), null, section.scale ? section.scale.evaluate(ctx) : null, section.font ? section.font.evaluate(ctx).join(",") : null, section.textColor ? section.textColor.evaluate(ctx) : null, section.verticalAlign ? section.verticalAlign.evaluate(ctx) : null);
|
|
13190
|
+
};
|
|
13191
|
+
return new Formatted(this.sections.map(evaluateSection));
|
|
13192
|
+
}
|
|
13193
|
+
eachChild(fn) {
|
|
13194
|
+
for (const section of this.sections) {
|
|
13195
|
+
fn(section.content);
|
|
13196
|
+
if (section.scale) fn(section.scale);
|
|
13197
|
+
if (section.font) fn(section.font);
|
|
13198
|
+
if (section.textColor) fn(section.textColor);
|
|
13199
|
+
if (section.verticalAlign) fn(section.verticalAlign);
|
|
13200
|
+
}
|
|
13201
|
+
}
|
|
13202
|
+
outputDefined() {
|
|
13203
|
+
return false;
|
|
13204
|
+
}
|
|
13205
|
+
};
|
|
13206
|
+
|
|
13079
13207
|
// src/expression/definitions/image.ts
|
|
13080
13208
|
var ImageExpression = class ImageExpression {
|
|
13081
13209
|
constructor(input) {
|
|
@@ -13425,21 +13553,64 @@ var TinyQueue = class {
|
|
|
13425
13553
|
}
|
|
13426
13554
|
data[pos] = item;
|
|
13427
13555
|
}
|
|
13428
|
-
_down(pos) {
|
|
13429
|
-
const { data, compare } = this;
|
|
13430
|
-
const halfLength = this.length >> 1;
|
|
13431
|
-
const item = data[pos];
|
|
13432
|
-
while (pos < halfLength) {
|
|
13433
|
-
let bestChild = (pos << 1) + 1;
|
|
13434
|
-
const right = bestChild + 1;
|
|
13435
|
-
if (right < this.length && compare(data[right], data[bestChild]) < 0) bestChild = right;
|
|
13436
|
-
if (compare(data[bestChild], item) >= 0) break;
|
|
13437
|
-
data[pos] = data[bestChild];
|
|
13438
|
-
pos = bestChild;
|
|
13439
|
-
}
|
|
13440
|
-
data[pos] = item;
|
|
13556
|
+
_down(pos) {
|
|
13557
|
+
const { data, compare } = this;
|
|
13558
|
+
const halfLength = this.length >> 1;
|
|
13559
|
+
const item = data[pos];
|
|
13560
|
+
while (pos < halfLength) {
|
|
13561
|
+
let bestChild = (pos << 1) + 1;
|
|
13562
|
+
const right = bestChild + 1;
|
|
13563
|
+
if (right < this.length && compare(data[right], data[bestChild]) < 0) bestChild = right;
|
|
13564
|
+
if (compare(data[bestChild], item) >= 0) break;
|
|
13565
|
+
data[pos] = data[bestChild];
|
|
13566
|
+
pos = bestChild;
|
|
13567
|
+
}
|
|
13568
|
+
data[pos] = item;
|
|
13569
|
+
}
|
|
13570
|
+
};
|
|
13571
|
+
|
|
13572
|
+
// src/util/classify_rings.ts
|
|
13573
|
+
/**
|
|
13574
|
+
* Classifies an array of rings into polygons with outer rings and holes
|
|
13575
|
+
* @param rings - the rings to classify
|
|
13576
|
+
* @param maxRings - the maximum number of rings to include in a polygon, use 0 to include all rings
|
|
13577
|
+
* @returns an array of polygons with internal rings as holes
|
|
13578
|
+
*/
|
|
13579
|
+
function classifyRings$1(rings, maxRings) {
|
|
13580
|
+
if (rings.length <= 1) return [rings];
|
|
13581
|
+
const polygons = [];
|
|
13582
|
+
let polygon;
|
|
13583
|
+
let ccw;
|
|
13584
|
+
for (const ring of rings) {
|
|
13585
|
+
const area = calculateSignedArea(ring);
|
|
13586
|
+
if (area === 0) continue;
|
|
13587
|
+
ring.area = Math.abs(area);
|
|
13588
|
+
if (ccw === void 0) ccw = area < 0;
|
|
13589
|
+
if (ccw === area < 0) {
|
|
13590
|
+
if (polygon) polygons.push(polygon);
|
|
13591
|
+
polygon = [ring];
|
|
13592
|
+
} else polygon.push(ring);
|
|
13593
|
+
}
|
|
13594
|
+
if (polygon) polygons.push(polygon);
|
|
13595
|
+
return polygons;
|
|
13596
|
+
}
|
|
13597
|
+
/**
|
|
13598
|
+
* Returns the signed area for the polygon ring. Positive areas are exterior rings and
|
|
13599
|
+
* have a clockwise winding. Negative areas are interior rings and have a counter clockwise
|
|
13600
|
+
* ordering.
|
|
13601
|
+
*
|
|
13602
|
+
* @param ring - Exterior or interior ring
|
|
13603
|
+
* @returns Signed area
|
|
13604
|
+
*/
|
|
13605
|
+
function calculateSignedArea(ring) {
|
|
13606
|
+
let sum = 0;
|
|
13607
|
+
for (let i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
|
|
13608
|
+
p1 = ring[i];
|
|
13609
|
+
p2 = ring[j];
|
|
13610
|
+
sum += (p2.x - p1.x) * (p1.y + p2.y);
|
|
13441
13611
|
}
|
|
13442
|
-
|
|
13612
|
+
return sum;
|
|
13613
|
+
}
|
|
13443
13614
|
|
|
13444
13615
|
// src/util/cheap_ruler.ts
|
|
13445
13616
|
const RE = 6378.137;
|
|
@@ -13999,162 +14170,6 @@ const expressions = {
|
|
|
13999
14170
|
"global-state": GlobalState
|
|
14000
14171
|
};
|
|
14001
14172
|
|
|
14002
|
-
// src/expression/parsing_error.ts
|
|
14003
|
-
var ExpressionParsingError = class extends Error {
|
|
14004
|
-
constructor(key, message) {
|
|
14005
|
-
super(message);
|
|
14006
|
-
this.message = message;
|
|
14007
|
-
this.key = key;
|
|
14008
|
-
}
|
|
14009
|
-
};
|
|
14010
|
-
|
|
14011
|
-
// src/expression/scope.ts
|
|
14012
|
-
/**
|
|
14013
|
-
* Tracks `let` bindings during expression parsing.
|
|
14014
|
-
* @private
|
|
14015
|
-
*/
|
|
14016
|
-
var Scope = class Scope {
|
|
14017
|
-
constructor(parent, bindings = []) {
|
|
14018
|
-
this.parent = parent;
|
|
14019
|
-
this.bindings = {};
|
|
14020
|
-
for (const [name, expression] of bindings) this.bindings[name] = expression;
|
|
14021
|
-
}
|
|
14022
|
-
concat(bindings) {
|
|
14023
|
-
return new Scope(this, bindings);
|
|
14024
|
-
}
|
|
14025
|
-
get(name) {
|
|
14026
|
-
if (this.bindings[name]) return this.bindings[name];
|
|
14027
|
-
if (this.parent) return this.parent.get(name);
|
|
14028
|
-
throw new Error(`${name} not found in scope.`);
|
|
14029
|
-
}
|
|
14030
|
-
has(name) {
|
|
14031
|
-
if (this.bindings[name]) return true;
|
|
14032
|
-
return this.parent ? this.parent.has(name) : false;
|
|
14033
|
-
}
|
|
14034
|
-
};
|
|
14035
|
-
|
|
14036
|
-
// src/expression/parsing_context.ts
|
|
14037
|
-
/**
|
|
14038
|
-
* State associated parsing at a given point in an expression tree.
|
|
14039
|
-
* @private
|
|
14040
|
-
*/
|
|
14041
|
-
var ParsingContext = class ParsingContext {
|
|
14042
|
-
constructor(registry, isConstantFunc, path = [], expectedType, scope = new Scope(), errors = []) {
|
|
14043
|
-
this.registry = registry;
|
|
14044
|
-
this.path = path;
|
|
14045
|
-
this.key = path.map((part) => `[${part}]`).join("");
|
|
14046
|
-
this.scope = scope;
|
|
14047
|
-
this.errors = errors;
|
|
14048
|
-
this.expectedType = expectedType;
|
|
14049
|
-
this._isConstant = isConstantFunc;
|
|
14050
|
-
}
|
|
14051
|
-
/**
|
|
14052
|
-
* @param expr the JSON expression to parse
|
|
14053
|
-
* @param index the optional argument index if this expression is an argument of a parent expression that's being parsed
|
|
14054
|
-
* @param options
|
|
14055
|
-
* @param options.omitTypeAnnotations set true to omit inferred type annotations. Caller beware: with this option set, the parsed expression's type will NOT satisfy `expectedType` if it would normally be wrapped in an inferred annotation.
|
|
14056
|
-
* @private
|
|
14057
|
-
*/
|
|
14058
|
-
parse(expr, index, expectedType, bindings, options = {}) {
|
|
14059
|
-
if (index != null) return this.concat(index, expectedType, bindings)._parse(expr, options);
|
|
14060
|
-
return this._parse(expr, options);
|
|
14061
|
-
}
|
|
14062
|
-
_parse(expr, options) {
|
|
14063
|
-
if (expr === null || typeof expr === "string" || typeof expr === "boolean" || typeof expr === "number") expr = ["literal", expr];
|
|
14064
|
-
const key = this.key;
|
|
14065
|
-
function annotate(parsed, type, typeAnnotation) {
|
|
14066
|
-
if (typeAnnotation === "assert") return new Assertion(type, [parsed], key);
|
|
14067
|
-
else if (typeAnnotation === "coerce") return new Coercion(type, [parsed], key);
|
|
14068
|
-
else return parsed;
|
|
14069
|
-
}
|
|
14070
|
-
if (Array.isArray(expr)) {
|
|
14071
|
-
if (expr.length === 0) return this.error("Expected an array with at least one element. If you wanted a literal array, use [\"literal\", []].");
|
|
14072
|
-
const op = expr[0];
|
|
14073
|
-
if (typeof op !== "string") {
|
|
14074
|
-
this.error(`Expression name must be a string, but found ${typeof op} instead. If you wanted a literal array, use ["literal", [...]].`, 0);
|
|
14075
|
-
return null;
|
|
14076
|
-
}
|
|
14077
|
-
const Expr = this.registry[op];
|
|
14078
|
-
if (Expr) {
|
|
14079
|
-
let parsed = Expr.parse(expr, this);
|
|
14080
|
-
if (!parsed) return null;
|
|
14081
|
-
if (this.expectedType) {
|
|
14082
|
-
const expected = this.expectedType;
|
|
14083
|
-
const actual = parsed.type;
|
|
14084
|
-
if ((expected.kind === "string" || expected.kind === "number" || expected.kind === "boolean" || expected.kind === "object" || expected.kind === "array") && actual.kind === "value") parsed = annotate(parsed, expected, options.typeAnnotation || "assert");
|
|
14085
|
-
else if ("projectionDefinition" === expected.kind && [
|
|
14086
|
-
"string",
|
|
14087
|
-
"array",
|
|
14088
|
-
"value"
|
|
14089
|
-
].includes(actual.kind) || [
|
|
14090
|
-
"color",
|
|
14091
|
-
"formatted",
|
|
14092
|
-
"resolvedImage"
|
|
14093
|
-
].includes(expected.kind) && ["value", "string"].includes(actual.kind) || ["padding", "numberArray"].includes(expected.kind) && [
|
|
14094
|
-
"value",
|
|
14095
|
-
"number",
|
|
14096
|
-
"array"
|
|
14097
|
-
].includes(actual.kind) || "colorArray" === expected.kind && [
|
|
14098
|
-
"value",
|
|
14099
|
-
"string",
|
|
14100
|
-
"array"
|
|
14101
|
-
].includes(actual.kind) || "variableAnchorOffsetCollection" === expected.kind && ["value", "array"].includes(actual.kind)) parsed = annotate(parsed, expected, options.typeAnnotation || "coerce");
|
|
14102
|
-
else if (this.checkSubtype(expected, actual)) return null;
|
|
14103
|
-
}
|
|
14104
|
-
if (!(parsed instanceof Literal) && parsed.type.kind !== "resolvedImage" && this._isConstant(parsed)) {
|
|
14105
|
-
const ec = new EvaluationContext();
|
|
14106
|
-
try {
|
|
14107
|
-
parsed = new Literal(parsed.type, parsed.evaluate(ec));
|
|
14108
|
-
} catch (e) {
|
|
14109
|
-
this.error(e.message);
|
|
14110
|
-
return null;
|
|
14111
|
-
}
|
|
14112
|
-
}
|
|
14113
|
-
return parsed;
|
|
14114
|
-
}
|
|
14115
|
-
return this.error(`Unknown expression "${op}". If you wanted a literal array, use ["literal", [...]].`, 0);
|
|
14116
|
-
} else if (typeof expr === "undefined") return this.error("'undefined' value invalid. Use null instead.");
|
|
14117
|
-
else if (typeof expr === "object") return this.error("Bare objects invalid. Use [\"literal\", {...}] instead.");
|
|
14118
|
-
else return this.error(`Expected an array, but found ${typeof expr} instead.`);
|
|
14119
|
-
}
|
|
14120
|
-
/**
|
|
14121
|
-
* Returns a copy of this context suitable for parsing the subexpression at
|
|
14122
|
-
* index `index`, optionally appending to 'let' binding map.
|
|
14123
|
-
*
|
|
14124
|
-
* Note that `errors` property, intended for collecting errors while
|
|
14125
|
-
* parsing, is copied by reference rather than cloned.
|
|
14126
|
-
* @private
|
|
14127
|
-
*/
|
|
14128
|
-
concat(index, expectedType, bindings) {
|
|
14129
|
-
const path = typeof index === "number" ? this.path.concat(index) : this.path;
|
|
14130
|
-
const scope = bindings ? this.scope.concat(bindings) : this.scope;
|
|
14131
|
-
return new ParsingContext(this.registry, this._isConstant, path, expectedType || null, scope, this.errors);
|
|
14132
|
-
}
|
|
14133
|
-
/**
|
|
14134
|
-
* Push a parsing (or type checking) error into the `this.errors`
|
|
14135
|
-
* @param error The message
|
|
14136
|
-
* @param keys Optionally specify the source of the error at a child
|
|
14137
|
-
* of the current expression at `this.key`.
|
|
14138
|
-
* @private
|
|
14139
|
-
*/
|
|
14140
|
-
error(error, ...keys) {
|
|
14141
|
-
const key = `${this.key}${keys.map((k) => `[${k}]`).join("")}`;
|
|
14142
|
-
this.errors.push(new ExpressionParsingError(key, error));
|
|
14143
|
-
}
|
|
14144
|
-
/**
|
|
14145
|
-
* Returns null if `t` is a subtype of `expected`; otherwise returns an
|
|
14146
|
-
* error message and also pushes it to `this.errors`.
|
|
14147
|
-
* @param expected The expected type
|
|
14148
|
-
* @param t The actual type
|
|
14149
|
-
* @returns null if `t` is a subtype of `expected`; otherwise returns an error message
|
|
14150
|
-
*/
|
|
14151
|
-
checkSubtype(expected, t) {
|
|
14152
|
-
const error = checkSubtype(expected, t);
|
|
14153
|
-
if (error) this.error(error);
|
|
14154
|
-
return error;
|
|
14155
|
-
}
|
|
14156
|
-
};
|
|
14157
|
-
|
|
14158
14173
|
// src/expression/compound_expression.ts
|
|
14159
14174
|
var CompoundExpression = class CompoundExpression {
|
|
14160
14175
|
constructor(name, type, evaluate, args, key) {
|
|
@@ -14730,6 +14745,20 @@ function isGlobalPropertyConstant(e, properties) {
|
|
|
14730
14745
|
return result;
|
|
14731
14746
|
}
|
|
14732
14747
|
|
|
14748
|
+
// src/util/result.ts
|
|
14749
|
+
function success(value) {
|
|
14750
|
+
return {
|
|
14751
|
+
result: "success",
|
|
14752
|
+
value
|
|
14753
|
+
};
|
|
14754
|
+
}
|
|
14755
|
+
function error(value) {
|
|
14756
|
+
return {
|
|
14757
|
+
result: "error",
|
|
14758
|
+
value
|
|
14759
|
+
};
|
|
14760
|
+
}
|
|
14761
|
+
|
|
14733
14762
|
// src/util/properties.ts
|
|
14734
14763
|
function supportsPropertyExpression(spec) {
|
|
14735
14764
|
return spec["property-type"] === "data-driven" || spec["property-type"] === "cross-faded-data-driven";
|
|
@@ -14966,20 +14995,6 @@ function interpolationFactor(input, base, lowerValue, upperValue) {
|
|
|
14966
14995
|
else return (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
|
|
14967
14996
|
}
|
|
14968
14997
|
|
|
14969
|
-
// src/util/result.ts
|
|
14970
|
-
function success(value) {
|
|
14971
|
-
return {
|
|
14972
|
-
result: "success",
|
|
14973
|
-
value
|
|
14974
|
-
};
|
|
14975
|
-
}
|
|
14976
|
-
function error(value) {
|
|
14977
|
-
return {
|
|
14978
|
-
result: "error",
|
|
14979
|
-
value
|
|
14980
|
-
};
|
|
14981
|
-
}
|
|
14982
|
-
|
|
14983
14998
|
// src/expression/index.ts
|
|
14984
14999
|
var StyleExpression = class {
|
|
14985
15000
|
constructor(expression, rootKey, propertySpec, globalState) {
|
|
@@ -15863,6 +15878,174 @@ async function loadGlyphRange(template, fontStack, start, fetchFn) {
|
|
|
15863
15878
|
}
|
|
15864
15879
|
}
|
|
15865
15880
|
|
|
15881
|
+
/**
|
|
15882
|
+
* A PNG file of RGBA pixels, for images that are drawn from a data URI, like the sheets of a
|
|
15883
|
+
* sprite. Without compression: its deflate stream holds the pixels in stored blocks, which needs
|
|
15884
|
+
* no dependency and runs in browsers too. The file is a little larger than the pixels.
|
|
15885
|
+
*/
|
|
15886
|
+
/** The CRC-32 table of PNG chunks, built on first use. */
|
|
15887
|
+
let crcTable;
|
|
15888
|
+
function crc32(bytes, start, end) {
|
|
15889
|
+
if (!crcTable) {
|
|
15890
|
+
crcTable = new Uint32Array(256);
|
|
15891
|
+
for (let n = 0; n < 256; n++) {
|
|
15892
|
+
let c = n;
|
|
15893
|
+
for (let k = 0; k < 8; k++)
|
|
15894
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
15895
|
+
crcTable[n] = c >>> 0;
|
|
15896
|
+
}
|
|
15897
|
+
}
|
|
15898
|
+
let crc = 0xffffffff;
|
|
15899
|
+
for (let i = start; i < end; i++)
|
|
15900
|
+
crc = crcTable[(crc ^ bytes[i]) & 0xff] ^ (crc >>> 8);
|
|
15901
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
15902
|
+
}
|
|
15903
|
+
/** The checksum of a zlib stream. */
|
|
15904
|
+
function adler32(bytes) {
|
|
15905
|
+
let a = 1;
|
|
15906
|
+
let b = 0;
|
|
15907
|
+
// sums of up to 5552 bytes cannot overflow before the modulo
|
|
15908
|
+
for (let i = 0; i < bytes.length;) {
|
|
15909
|
+
const end = Math.min(i + 5552, bytes.length);
|
|
15910
|
+
for (; i < end; i++) {
|
|
15911
|
+
a += bytes[i];
|
|
15912
|
+
b += a;
|
|
15913
|
+
}
|
|
15914
|
+
a %= 65521;
|
|
15915
|
+
b %= 65521;
|
|
15916
|
+
}
|
|
15917
|
+
return ((b << 16) | a) >>> 0;
|
|
15918
|
+
}
|
|
15919
|
+
/** The longest stored deflate block. */
|
|
15920
|
+
const MAX_BLOCK = 65535;
|
|
15921
|
+
/** A zlib stream of the bytes in stored deflate blocks. */
|
|
15922
|
+
function zlibStored(raw) {
|
|
15923
|
+
const blocks = Math.max(1, Math.ceil(raw.length / MAX_BLOCK));
|
|
15924
|
+
const out = new Uint8Array(2 + blocks * 5 + raw.length + 4);
|
|
15925
|
+
const view = new DataView(out.buffer);
|
|
15926
|
+
// deflate with a 32 KB window, no dictionary, the fastest level
|
|
15927
|
+
out[0] = 0x78;
|
|
15928
|
+
out[1] = 0x01;
|
|
15929
|
+
let at = 2;
|
|
15930
|
+
for (let block = 0; block < blocks; block++) {
|
|
15931
|
+
const start = block * MAX_BLOCK;
|
|
15932
|
+
const length = Math.min(MAX_BLOCK, raw.length - start);
|
|
15933
|
+
out[at] = block === blocks - 1 ? 1 : 0;
|
|
15934
|
+
view.setUint16(at + 1, length, true);
|
|
15935
|
+
view.setUint16(at + 3, ~length & 0xffff, true);
|
|
15936
|
+
out.set(raw.subarray(start, start + length), at + 5);
|
|
15937
|
+
at += 5 + length;
|
|
15938
|
+
}
|
|
15939
|
+
view.setUint32(at, adler32(raw));
|
|
15940
|
+
return out;
|
|
15941
|
+
}
|
|
15942
|
+
/** A chunk of a PNG file: its length, type, data and CRC. */
|
|
15943
|
+
function chunk(type, data) {
|
|
15944
|
+
const out = new Uint8Array(12 + data.length);
|
|
15945
|
+
const view = new DataView(out.buffer);
|
|
15946
|
+
view.setUint32(0, data.length);
|
|
15947
|
+
for (let i = 0; i < 4; i++)
|
|
15948
|
+
out[4 + i] = type.charCodeAt(i);
|
|
15949
|
+
out.set(data, 8);
|
|
15950
|
+
view.setUint32(8 + data.length, crc32(out, 4, 8 + data.length));
|
|
15951
|
+
return out;
|
|
15952
|
+
}
|
|
15953
|
+
/**
|
|
15954
|
+
* A PNG file of an image of `width` × `height` pixels, given as RGBA, row by row, not
|
|
15955
|
+
* premultiplied: as `ImageData` and MapLibre's `map.addImage` have them.
|
|
15956
|
+
* @throws If `data` does not hold `width * height` pixels.
|
|
15957
|
+
*/
|
|
15958
|
+
function encodePNG(width, height, data) {
|
|
15959
|
+
if (!Number.isInteger(width) || !Number.isInteger(height) || width <= 0 || height <= 0) {
|
|
15960
|
+
throw new Error(`An image must have a positive whole width and height, not ${String(width)} × ${String(height)}`);
|
|
15961
|
+
}
|
|
15962
|
+
if (data.length !== width * height * 4) {
|
|
15963
|
+
throw new Error(`An image of ${String(width)} × ${String(height)} pixels needs ${String(width * height * 4)} bytes, not ${String(data.length)}`);
|
|
15964
|
+
}
|
|
15965
|
+
const header = new Uint8Array(13);
|
|
15966
|
+
const view = new DataView(header.buffer);
|
|
15967
|
+
view.setUint32(0, width);
|
|
15968
|
+
view.setUint32(4, height);
|
|
15969
|
+
// 8 bits per channel, RGBA, no interlace
|
|
15970
|
+
header[8] = 8;
|
|
15971
|
+
header[9] = 6;
|
|
15972
|
+
// each row starts with its filter: none
|
|
15973
|
+
const row = width * 4;
|
|
15974
|
+
const raw = new Uint8Array((row + 1) * height);
|
|
15975
|
+
for (let y = 0; y < height; y++)
|
|
15976
|
+
raw.set(data.subarray(y * row, (y + 1) * row), y * (row + 1) + 1);
|
|
15977
|
+
const parts = [
|
|
15978
|
+
new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]),
|
|
15979
|
+
chunk('IHDR', header),
|
|
15980
|
+
chunk('IDAT', zlibStored(raw)),
|
|
15981
|
+
chunk('IEND', new Uint8Array(0)),
|
|
15982
|
+
];
|
|
15983
|
+
const png = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));
|
|
15984
|
+
let at = 0;
|
|
15985
|
+
for (const part of parts) {
|
|
15986
|
+
png.set(part, at);
|
|
15987
|
+
at += part.length;
|
|
15988
|
+
}
|
|
15989
|
+
return png;
|
|
15990
|
+
}
|
|
15991
|
+
|
|
15992
|
+
/**
|
|
15993
|
+
* The images in an atlas like the sprite's, each on a sheet of its own. An image that cannot be
|
|
15994
|
+
* drawn, e.g. with too few pixels, is left out with a warning.
|
|
15995
|
+
*/
|
|
15996
|
+
function imageAtlas(images, warn) {
|
|
15997
|
+
const atlas = new Map();
|
|
15998
|
+
for (const image of images) {
|
|
15999
|
+
const { id, width, height, data, pixelRatio = 1, sdf = false } = image;
|
|
16000
|
+
if (atlas.has(id)) {
|
|
16001
|
+
warn(`The image "${id}" is given twice in "images": the first one is drawn.`);
|
|
16002
|
+
continue;
|
|
16003
|
+
}
|
|
16004
|
+
if (!(pixelRatio > 0)) {
|
|
16005
|
+
warn(`The image "${id}" in "images" has no positive pixelRatio: it is left out.`);
|
|
16006
|
+
continue;
|
|
16007
|
+
}
|
|
16008
|
+
let png;
|
|
16009
|
+
try {
|
|
16010
|
+
png = encodePNG(width, height, data);
|
|
16011
|
+
}
|
|
16012
|
+
catch (error) {
|
|
16013
|
+
warn(`The image "${id}" in "images" is left out: ${error.message}.`);
|
|
16014
|
+
continue;
|
|
16015
|
+
}
|
|
16016
|
+
const buffer = png.buffer.slice(png.byteOffset, png.byteOffset + png.byteLength);
|
|
16017
|
+
atlas.set(id, {
|
|
16018
|
+
width,
|
|
16019
|
+
height,
|
|
16020
|
+
x: 0,
|
|
16021
|
+
y: 0,
|
|
16022
|
+
pixelRatio,
|
|
16023
|
+
sdf,
|
|
16024
|
+
sheetDataUri: `data:image/png;base64,${arrayBufferToBase64(buffer)}`,
|
|
16025
|
+
sheetWidth: width,
|
|
16026
|
+
sheetHeight: height,
|
|
16027
|
+
});
|
|
16028
|
+
}
|
|
16029
|
+
return atlas;
|
|
16030
|
+
}
|
|
16031
|
+
/**
|
|
16032
|
+
* The sprite's atlas with the images added, like `map.addImage` in MapLibre GL JS, which fails for
|
|
16033
|
+
* an id that the style has already: an image of the sprite keeps its place, with a warning.
|
|
16034
|
+
*/
|
|
16035
|
+
function withImages(sprite, images, warn) {
|
|
16036
|
+
if (images.size === 0)
|
|
16037
|
+
return sprite;
|
|
16038
|
+
const atlas = new Map(sprite);
|
|
16039
|
+
for (const [id, entry] of images) {
|
|
16040
|
+
if (atlas.has(id)) {
|
|
16041
|
+
warn(`The image "${id}" in "images" is in the sprite too: the sprite's is drawn.`);
|
|
16042
|
+
continue;
|
|
16043
|
+
}
|
|
16044
|
+
atlas.set(id, entry);
|
|
16045
|
+
}
|
|
16046
|
+
return atlas;
|
|
16047
|
+
}
|
|
16048
|
+
|
|
15866
16049
|
// DEFLATE is a complex format; to read this code, you should probably check the RFC first:
|
|
15867
16050
|
// https://tools.ietf.org/html/rfc1951
|
|
15868
16051
|
// You may also wish to take a look at the guide I made about this program:
|
|
@@ -21256,6 +21439,9 @@ class SVGMapRenderer {
|
|
|
21256
21439
|
#pmtiles;
|
|
21257
21440
|
#fetch;
|
|
21258
21441
|
#sprite;
|
|
21442
|
+
/** The images of {@link SVGMapRendererOptions.images}, encoded on first use. */
|
|
21443
|
+
#imageList;
|
|
21444
|
+
#images;
|
|
21259
21445
|
#sources;
|
|
21260
21446
|
#glyphRanges = new Map();
|
|
21261
21447
|
#onWarning;
|
|
@@ -21268,6 +21454,7 @@ class SVGMapRenderer {
|
|
|
21268
21454
|
constructor(options) {
|
|
21269
21455
|
this.#style = options.style;
|
|
21270
21456
|
this.#onWarning = options.onWarning ?? ((message) => console.warn(message));
|
|
21457
|
+
this.#imageList = options.images ?? [];
|
|
21271
21458
|
let labels =
|
|
21272
21459
|
// eslint-disable-next-line @typescript-eslint/no-deprecated -- still supported, mapped to `labels`
|
|
21273
21460
|
options.labels ?? (options.renderLabels === true ? 'glyphs-text' : 'none');
|
|
@@ -21395,7 +21582,8 @@ class SVGMapRenderer {
|
|
|
21395
21582
|
const sprite = loadSprite(this.#style, this.#fetch).then(({ atlas, complete }) => {
|
|
21396
21583
|
if (!complete && this.#sprite === sprite)
|
|
21397
21584
|
this.#sprite = undefined;
|
|
21398
|
-
|
|
21585
|
+
this.#images ??= imageAtlas(this.#imageList, (message) => this.#warn(message));
|
|
21586
|
+
return withImages(atlas, this.#images, (message) => this.#warn(message));
|
|
21399
21587
|
});
|
|
21400
21588
|
this.#sprite = sprite;
|
|
21401
21589
|
return sprite;
|