This commit is contained in:
1
node_modules/@mapbox/jsonlint-lines-primitives/.npmignore
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/.npmignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
17
node_modules/@mapbox/jsonlint-lines-primitives/Makefile
generated
vendored
Normal file
17
node_modules/@mapbox/jsonlint-lines-primitives/Makefile
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
all: build test site
|
||||
|
||||
build:
|
||||
./node_modules/jison/lib/cli.js src/jsonlint.y src/jsonlint.l
|
||||
mv jsonlint.js lib/jsonlint.js
|
||||
node scripts/bundle.js | ./node_modules/uglify-js/bin/uglifyjs > web/jsonlint.js
|
||||
|
||||
site:
|
||||
cp web/jsonlint.js ../jsonlint-pages/jsonlint.js
|
||||
|
||||
deploy: site
|
||||
cd ../jsonlint-pages && git commit -a -m 'deploy site updates' && git push origin gh-pages
|
||||
|
||||
test: lib/jsonlint.js test/all-tests.js
|
||||
node test/all-tests.js
|
||||
|
||||
7
node_modules/@mapbox/jsonlint-lines-primitives/README.md
generated
vendored
Normal file
7
node_modules/@mapbox/jsonlint-lines-primitives/README.md
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
JSON Lint
|
||||
=========
|
||||
|
||||
A fork of the `lines-primitive` branch of [tmcw/jsonlint](https://github.com/tmcw/jsonlint), which is a fork of [zaach/jsonlint](https://github.com/zaach/jsonlint) that adds line number annotations to the parsed JSON.
|
||||
|
||||
This fork is used by Mapbox GL JS, specifically for providing helpful error messages when validating Mapbox GL style JSON documents.
|
||||
|
||||
92
node_modules/@mapbox/jsonlint-lines-primitives/lib/formatter.js
generated
vendored
Normal file
92
node_modules/@mapbox/jsonlint-lines-primitives/lib/formatter.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Manual formatter taken straight from https://github.com/umbrae/jsonlintdotcom
|
||||
**/
|
||||
|
||||
/*jslint white: true, devel: true, onevar: true, browser: true, undef: true, nomen: true, regexp: true, plusplus: false, bitwise: true, newcap: true, maxerr: 50, indent: 4 */
|
||||
|
||||
/**
|
||||
* jsl.format - Provide json reformatting in a character-by-character approach, so that even invalid JSON may be reformatted (to the best of its ability).
|
||||
*
|
||||
**/
|
||||
var formatter = (function () {
|
||||
|
||||
function repeat(s, count) {
|
||||
return new Array(count + 1).join(s);
|
||||
}
|
||||
|
||||
function formatJson(json, indentChars) {
|
||||
var i = 0,
|
||||
il = 0,
|
||||
tab = (typeof indentChars !== "undefined") ? indentChars : " ",
|
||||
newJson = "",
|
||||
indentLevel = 0,
|
||||
inString = false,
|
||||
currentChar = null;
|
||||
|
||||
for (i = 0, il = json.length; i < il; i += 1) {
|
||||
currentChar = json.charAt(i);
|
||||
|
||||
switch (currentChar) {
|
||||
case '{':
|
||||
case '[':
|
||||
if (!inString) {
|
||||
newJson += currentChar + "\n" + repeat(tab, indentLevel + 1);
|
||||
indentLevel += 1;
|
||||
} else {
|
||||
newJson += currentChar;
|
||||
}
|
||||
break;
|
||||
case '}':
|
||||
case ']':
|
||||
if (!inString) {
|
||||
indentLevel -= 1;
|
||||
newJson += "\n" + repeat(tab, indentLevel) + currentChar;
|
||||
} else {
|
||||
newJson += currentChar;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (!inString) {
|
||||
newJson += ",\n" + repeat(tab, indentLevel);
|
||||
} else {
|
||||
newJson += currentChar;
|
||||
}
|
||||
break;
|
||||
case ':':
|
||||
if (!inString) {
|
||||
newJson += ": ";
|
||||
} else {
|
||||
newJson += currentChar;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
case "\n":
|
||||
case "\t":
|
||||
if (inString) {
|
||||
newJson += currentChar;
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
if (i > 0 && json.charAt(i - 1) !== '\\') {
|
||||
inString = !inString;
|
||||
}
|
||||
newJson += currentChar;
|
||||
break;
|
||||
default:
|
||||
newJson += currentChar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return newJson;
|
||||
}
|
||||
|
||||
return { "formatJson": formatJson };
|
||||
|
||||
}());
|
||||
|
||||
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
||||
exports.formatter = formatter;
|
||||
}
|
||||
681
node_modules/@mapbox/jsonlint-lines-primitives/lib/jsonlint.js
generated
vendored
Normal file
681
node_modules/@mapbox/jsonlint-lines-primitives/lib/jsonlint.js
generated
vendored
Normal file
@@ -0,0 +1,681 @@
|
||||
/* parser generated by jison 0.4.15 */
|
||||
/*
|
||||
Returns a Parser object of the following structure:
|
||||
|
||||
Parser: {
|
||||
yy: {}
|
||||
}
|
||||
|
||||
Parser.prototype: {
|
||||
yy: {},
|
||||
trace: function(),
|
||||
symbols_: {associative list: name ==> number},
|
||||
terminals_: {associative list: number ==> name},
|
||||
productions_: [...],
|
||||
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
|
||||
table: [...],
|
||||
defaultActions: {...},
|
||||
parseError: function(str, hash),
|
||||
parse: function(input),
|
||||
|
||||
lexer: {
|
||||
EOF: 1,
|
||||
parseError: function(str, hash),
|
||||
setInput: function(input),
|
||||
input: function(),
|
||||
unput: function(str),
|
||||
more: function(),
|
||||
less: function(n),
|
||||
pastInput: function(),
|
||||
upcomingInput: function(),
|
||||
showPosition: function(),
|
||||
test_match: function(regex_match_array, rule_index),
|
||||
next: function(),
|
||||
lex: function(),
|
||||
begin: function(condition),
|
||||
popState: function(),
|
||||
_currentRules: function(),
|
||||
topState: function(),
|
||||
pushState: function(condition),
|
||||
|
||||
options: {
|
||||
ranges: boolean (optional: true ==> token location info will include a .range[] member)
|
||||
flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
|
||||
backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
|
||||
},
|
||||
|
||||
performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
|
||||
rules: [...],
|
||||
conditions: {associative list: name ==> set},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
token location info (@$, _$, etc.): {
|
||||
first_line: n,
|
||||
last_line: n,
|
||||
first_column: n,
|
||||
last_column: n,
|
||||
range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)
|
||||
}
|
||||
|
||||
|
||||
the parseError function receives a 'hash' object with these members for lexer and parser errors: {
|
||||
text: (matched text)
|
||||
token: (the produced terminal token, if any)
|
||||
line: (yylineno)
|
||||
}
|
||||
while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
|
||||
loc: (yylloc)
|
||||
expected: (string describing the set of expected tokens)
|
||||
recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
|
||||
}
|
||||
*/
|
||||
var parser = (function(){
|
||||
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,12],$V1=[1,13],$V2=[1,9],$V3=[1,10],$V4=[1,11],$V5=[1,14],$V6=[1,15],$V7=[14,18,22,24],$V8=[18,22],$V9=[22,24];
|
||||
var parser = {trace: function trace() { },
|
||||
yy: {},
|
||||
symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1},
|
||||
terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"},
|
||||
productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]],
|
||||
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
|
||||
/* this == yyval */
|
||||
|
||||
var $0 = $$.length - 1;
|
||||
switch (yystate) {
|
||||
case 1:
|
||||
// replace escaped characters with actual character
|
||||
this.$ = new String(yytext.replace(/\\(\\|")/g, "$"+"1")
|
||||
.replace(/\\n/g,'\n')
|
||||
.replace(/\\r/g,'\r')
|
||||
.replace(/\\t/g,'\t')
|
||||
.replace(/\\v/g,'\v')
|
||||
.replace(/\\f/g,'\f')
|
||||
.replace(/\\b/g,'\b'));
|
||||
this.$.__line__ = this._$.first_line;
|
||||
|
||||
break;
|
||||
case 2:
|
||||
|
||||
this.$ = new Number(yytext);
|
||||
this.$.__line__ = this._$.first_line;
|
||||
|
||||
break;
|
||||
case 3:
|
||||
|
||||
this.$ = null;
|
||||
|
||||
break;
|
||||
case 4:
|
||||
|
||||
this.$ = new Boolean(true);
|
||||
this.$.__line__ = this._$.first_line;
|
||||
|
||||
break;
|
||||
case 5:
|
||||
|
||||
this.$ = new Boolean(false);
|
||||
this.$.__line__ = this._$.first_line;
|
||||
|
||||
break;
|
||||
case 6:
|
||||
return this.$ = $$[$0-1];
|
||||
break;
|
||||
case 13:
|
||||
this.$ = {}; Object.defineProperty(this.$, '__line__', {
|
||||
value: this._$.first_line,
|
||||
enumerable: false
|
||||
})
|
||||
break;
|
||||
case 14: case 19:
|
||||
this.$ = $$[$0-1]; Object.defineProperty(this.$, '__line__', {
|
||||
value: this._$.first_line,
|
||||
enumerable: false
|
||||
})
|
||||
break;
|
||||
case 15:
|
||||
this.$ = [$$[$0-2], $$[$0]];
|
||||
break;
|
||||
case 16:
|
||||
this.$ = {}; this.$[$$[$0][0]] = $$[$0][1];
|
||||
break;
|
||||
case 17:
|
||||
this.$ = $$[$0-2]; $$[$0-2][$$[$0][0]] = $$[$0][1];
|
||||
break;
|
||||
case 18:
|
||||
this.$ = []; Object.defineProperty(this.$, '__line__', {
|
||||
value: this._$.first_line,
|
||||
enumerable: false
|
||||
})
|
||||
break;
|
||||
case 20:
|
||||
this.$ = [$$[$0]];
|
||||
break;
|
||||
case 21:
|
||||
this.$ = $$[$0-2]; $$[$0-2].push($$[$0]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
table: [{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,12:1,13:2,15:7,16:8,17:$V5,23:$V6},{1:[3]},{14:[1,16]},o($V7,[2,7]),o($V7,[2,8]),o($V7,[2,9]),o($V7,[2,10]),o($V7,[2,11]),o($V7,[2,12]),o($V7,[2,3]),o($V7,[2,4]),o($V7,[2,5]),o([14,18,21,22,24],[2,1]),o($V7,[2,2]),{3:20,4:$V0,18:[1,17],19:18,20:19},{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:23,15:7,16:8,17:$V5,23:$V6,24:[1,21],25:22},{1:[2,6]},o($V7,[2,13]),{18:[1,24],22:[1,25]},o($V8,[2,16]),{21:[1,26]},o($V7,[2,18]),{22:[1,28],24:[1,27]},o($V9,[2,20]),o($V7,[2,14]),{3:20,4:$V0,20:29},{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:30,15:7,16:8,17:$V5,23:$V6},o($V7,[2,19]),{3:5,4:$V0,5:6,6:$V1,7:3,8:$V2,9:4,10:$V3,11:$V4,13:31,15:7,16:8,17:$V5,23:$V6},o($V8,[2,17]),o($V8,[2,15]),o($V9,[2,21])],
|
||||
defaultActions: {16:[2,6]},
|
||||
parseError: function parseError(str, hash) {
|
||||
if (hash.recoverable) {
|
||||
this.trace(str);
|
||||
} else {
|
||||
throw new Error(str);
|
||||
}
|
||||
},
|
||||
parse: function parse(input) {
|
||||
var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
|
||||
var args = lstack.slice.call(arguments, 1);
|
||||
var lexer = Object.create(this.lexer);
|
||||
var sharedState = { yy: {} };
|
||||
for (var k in this.yy) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
|
||||
sharedState.yy[k] = this.yy[k];
|
||||
}
|
||||
}
|
||||
lexer.setInput(input, sharedState.yy);
|
||||
sharedState.yy.lexer = lexer;
|
||||
sharedState.yy.parser = this;
|
||||
if (typeof lexer.yylloc == 'undefined') {
|
||||
lexer.yylloc = {};
|
||||
}
|
||||
var yyloc = lexer.yylloc;
|
||||
lstack.push(yyloc);
|
||||
var ranges = lexer.options && lexer.options.ranges;
|
||||
if (typeof sharedState.yy.parseError === 'function') {
|
||||
this.parseError = sharedState.yy.parseError;
|
||||
} else {
|
||||
this.parseError = Object.getPrototypeOf(this).parseError;
|
||||
}
|
||||
function popStack(n) {
|
||||
stack.length = stack.length - 2 * n;
|
||||
vstack.length = vstack.length - n;
|
||||
lstack.length = lstack.length - n;
|
||||
}
|
||||
_token_stack:
|
||||
function lex() {
|
||||
var token;
|
||||
token = lexer.lex() || EOF;
|
||||
if (typeof token !== 'number') {
|
||||
token = self.symbols_[token] || token;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
|
||||
while (true) {
|
||||
state = stack[stack.length - 1];
|
||||
if (this.defaultActions[state]) {
|
||||
action = this.defaultActions[state];
|
||||
} else {
|
||||
if (symbol === null || typeof symbol == 'undefined') {
|
||||
symbol = lex();
|
||||
}
|
||||
action = table[state] && table[state][symbol];
|
||||
}
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
var errStr = '';
|
||||
expected = [];
|
||||
for (p in table[state]) {
|
||||
if (this.terminals_[p] && p > TERROR) {
|
||||
expected.push('\'' + this.terminals_[p] + '\'');
|
||||
}
|
||||
}
|
||||
if (lexer.showPosition) {
|
||||
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
|
||||
} else {
|
||||
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
|
||||
}
|
||||
this.parseError(errStr, {
|
||||
text: lexer.match,
|
||||
token: this.terminals_[symbol] || symbol,
|
||||
line: lexer.yylineno,
|
||||
loc: yyloc,
|
||||
expected: expected
|
||||
});
|
||||
}
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
|
||||
}
|
||||
switch (action[0]) {
|
||||
case 1:
|
||||
stack.push(symbol);
|
||||
vstack.push(lexer.yytext);
|
||||
lstack.push(lexer.yylloc);
|
||||
stack.push(action[1]);
|
||||
symbol = null;
|
||||
if (!preErrorSymbol) {
|
||||
yyleng = lexer.yyleng;
|
||||
yytext = lexer.yytext;
|
||||
yylineno = lexer.yylineno;
|
||||
yyloc = lexer.yylloc;
|
||||
if (recovering > 0) {
|
||||
recovering--;
|
||||
}
|
||||
} else {
|
||||
symbol = preErrorSymbol;
|
||||
preErrorSymbol = null;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
len = this.productions_[action[1]][1];
|
||||
yyval.$ = vstack[vstack.length - len];
|
||||
yyval._$ = {
|
||||
first_line: lstack[lstack.length - (len || 1)].first_line,
|
||||
last_line: lstack[lstack.length - 1].last_line,
|
||||
first_column: lstack[lstack.length - (len || 1)].first_column,
|
||||
last_column: lstack[lstack.length - 1].last_column
|
||||
};
|
||||
if (ranges) {
|
||||
yyval._$.range = [
|
||||
lstack[lstack.length - (len || 1)].range[0],
|
||||
lstack[lstack.length - 1].range[1]
|
||||
];
|
||||
}
|
||||
r = this.performAction.apply(yyval, [
|
||||
yytext,
|
||||
yyleng,
|
||||
yylineno,
|
||||
sharedState.yy,
|
||||
action[1],
|
||||
vstack,
|
||||
lstack
|
||||
].concat(args));
|
||||
if (typeof r !== 'undefined') {
|
||||
return r;
|
||||
}
|
||||
if (len) {
|
||||
stack = stack.slice(0, -1 * len * 2);
|
||||
vstack = vstack.slice(0, -1 * len);
|
||||
lstack = lstack.slice(0, -1 * len);
|
||||
}
|
||||
stack.push(this.productions_[action[1]][0]);
|
||||
vstack.push(yyval.$);
|
||||
lstack.push(yyval._$);
|
||||
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
|
||||
stack.push(newState);
|
||||
break;
|
||||
case 3:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}};
|
||||
/* generated by jison-lex 0.3.4 */
|
||||
var lexer = (function(){
|
||||
var lexer = ({
|
||||
|
||||
EOF:1,
|
||||
|
||||
parseError:function parseError(str, hash) {
|
||||
if (this.yy.parser) {
|
||||
this.yy.parser.parseError(str, hash);
|
||||
} else {
|
||||
throw new Error(str);
|
||||
}
|
||||
},
|
||||
|
||||
// resets the lexer, sets new input
|
||||
setInput:function (input, yy) {
|
||||
this.yy = yy || this.yy || {};
|
||||
this._input = input;
|
||||
this._more = this._backtrack = this.done = false;
|
||||
this.yylineno = this.yyleng = 0;
|
||||
this.yytext = this.matched = this.match = '';
|
||||
this.conditionStack = ['INITIAL'];
|
||||
this.yylloc = {
|
||||
first_line: 1,
|
||||
first_column: 0,
|
||||
last_line: 1,
|
||||
last_column: 0
|
||||
};
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range = [0,0];
|
||||
}
|
||||
this.offset = 0;
|
||||
return this;
|
||||
},
|
||||
|
||||
// consumes and returns one char from the input
|
||||
input:function () {
|
||||
var ch = this._input[0];
|
||||
this.yytext += ch;
|
||||
this.yyleng++;
|
||||
this.offset++;
|
||||
this.match += ch;
|
||||
this.matched += ch;
|
||||
var lines = ch.match(/(?:\r\n?|\n).*/g);
|
||||
if (lines) {
|
||||
this.yylineno++;
|
||||
this.yylloc.last_line++;
|
||||
} else {
|
||||
this.yylloc.last_column++;
|
||||
}
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range[1]++;
|
||||
}
|
||||
|
||||
this._input = this._input.slice(1);
|
||||
return ch;
|
||||
},
|
||||
|
||||
// unshifts one char (or a string) into the input
|
||||
unput:function (ch) {
|
||||
var len = ch.length;
|
||||
var lines = ch.split(/(?:\r\n?|\n)/g);
|
||||
|
||||
this._input = ch + this._input;
|
||||
this.yytext = this.yytext.substr(0, this.yytext.length - len);
|
||||
//this.yyleng -= len;
|
||||
this.offset -= len;
|
||||
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
|
||||
this.match = this.match.substr(0, this.match.length - 1);
|
||||
this.matched = this.matched.substr(0, this.matched.length - 1);
|
||||
|
||||
if (lines.length - 1) {
|
||||
this.yylineno -= lines.length - 1;
|
||||
}
|
||||
var r = this.yylloc.range;
|
||||
|
||||
this.yylloc = {
|
||||
first_line: this.yylloc.first_line,
|
||||
last_line: this.yylineno + 1,
|
||||
first_column: this.yylloc.first_column,
|
||||
last_column: lines ?
|
||||
(lines.length === oldLines.length ? this.yylloc.first_column : 0)
|
||||
+ oldLines[oldLines.length - lines.length].length - lines[0].length :
|
||||
this.yylloc.first_column - len
|
||||
};
|
||||
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
|
||||
}
|
||||
this.yyleng = this.yytext.length;
|
||||
return this;
|
||||
},
|
||||
|
||||
// When called from action, caches matched text and appends it on next action
|
||||
more:function () {
|
||||
this._more = true;
|
||||
return this;
|
||||
},
|
||||
|
||||
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
|
||||
reject:function () {
|
||||
if (this.options.backtrack_lexer) {
|
||||
this._backtrack = true;
|
||||
} else {
|
||||
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
|
||||
text: "",
|
||||
token: null,
|
||||
line: this.yylineno
|
||||
});
|
||||
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
// retain first n characters of the match
|
||||
less:function (n) {
|
||||
this.unput(this.match.slice(n));
|
||||
},
|
||||
|
||||
// displays already matched input, i.e. for error messages
|
||||
pastInput:function () {
|
||||
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
||||
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
|
||||
},
|
||||
|
||||
// displays upcoming input, i.e. for error messages
|
||||
upcomingInput:function () {
|
||||
var next = this.match;
|
||||
if (next.length < 20) {
|
||||
next += this._input.substr(0, 20-next.length);
|
||||
}
|
||||
return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
|
||||
},
|
||||
|
||||
// displays the character position where the lexing error occurred, i.e. for error messages
|
||||
showPosition:function () {
|
||||
var pre = this.pastInput();
|
||||
var c = new Array(pre.length + 1).join("-");
|
||||
return pre + this.upcomingInput() + "\n" + c + "^";
|
||||
},
|
||||
|
||||
// test the lexed token: return FALSE when not a match, otherwise return token
|
||||
test_match:function (match, indexed_rule) {
|
||||
var token,
|
||||
lines,
|
||||
backup;
|
||||
|
||||
if (this.options.backtrack_lexer) {
|
||||
// save context
|
||||
backup = {
|
||||
yylineno: this.yylineno,
|
||||
yylloc: {
|
||||
first_line: this.yylloc.first_line,
|
||||
last_line: this.last_line,
|
||||
first_column: this.yylloc.first_column,
|
||||
last_column: this.yylloc.last_column
|
||||
},
|
||||
yytext: this.yytext,
|
||||
match: this.match,
|
||||
matches: this.matches,
|
||||
matched: this.matched,
|
||||
yyleng: this.yyleng,
|
||||
offset: this.offset,
|
||||
_more: this._more,
|
||||
_input: this._input,
|
||||
yy: this.yy,
|
||||
conditionStack: this.conditionStack.slice(0),
|
||||
done: this.done
|
||||
};
|
||||
if (this.options.ranges) {
|
||||
backup.yylloc.range = this.yylloc.range.slice(0);
|
||||
}
|
||||
}
|
||||
|
||||
lines = match[0].match(/(?:\r\n?|\n).*/g);
|
||||
if (lines) {
|
||||
this.yylineno += lines.length;
|
||||
}
|
||||
this.yylloc = {
|
||||
first_line: this.yylloc.last_line,
|
||||
last_line: this.yylineno + 1,
|
||||
first_column: this.yylloc.last_column,
|
||||
last_column: lines ?
|
||||
lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
|
||||
this.yylloc.last_column + match[0].length
|
||||
};
|
||||
this.yytext += match[0];
|
||||
this.match += match[0];
|
||||
this.matches = match;
|
||||
this.yyleng = this.yytext.length;
|
||||
if (this.options.ranges) {
|
||||
this.yylloc.range = [this.offset, this.offset += this.yyleng];
|
||||
}
|
||||
this._more = false;
|
||||
this._backtrack = false;
|
||||
this._input = this._input.slice(match[0].length);
|
||||
this.matched += match[0];
|
||||
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
|
||||
if (this.done && this._input) {
|
||||
this.done = false;
|
||||
}
|
||||
if (token) {
|
||||
return token;
|
||||
} else if (this._backtrack) {
|
||||
// recover context
|
||||
for (var k in backup) {
|
||||
this[k] = backup[k];
|
||||
}
|
||||
return false; // rule action called reject() implying the next rule should be tested instead.
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// return next match in input
|
||||
next:function () {
|
||||
if (this.done) {
|
||||
return this.EOF;
|
||||
}
|
||||
if (!this._input) {
|
||||
this.done = true;
|
||||
}
|
||||
|
||||
var token,
|
||||
match,
|
||||
tempMatch,
|
||||
index;
|
||||
if (!this._more) {
|
||||
this.yytext = '';
|
||||
this.match = '';
|
||||
}
|
||||
var rules = this._currentRules();
|
||||
for (var i = 0; i < rules.length; i++) {
|
||||
tempMatch = this._input.match(this.rules[rules[i]]);
|
||||
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
||||
match = tempMatch;
|
||||
index = i;
|
||||
if (this.options.backtrack_lexer) {
|
||||
token = this.test_match(tempMatch, rules[i]);
|
||||
if (token !== false) {
|
||||
return token;
|
||||
} else if (this._backtrack) {
|
||||
match = false;
|
||||
continue; // rule action called reject() implying a rule MISmatch.
|
||||
} else {
|
||||
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
|
||||
return false;
|
||||
}
|
||||
} else if (!this.options.flex) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
token = this.test_match(match, rules[index]);
|
||||
if (token !== false) {
|
||||
return token;
|
||||
}
|
||||
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
|
||||
return false;
|
||||
}
|
||||
if (this._input === "") {
|
||||
return this.EOF;
|
||||
} else {
|
||||
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
|
||||
text: "",
|
||||
token: null,
|
||||
line: this.yylineno
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// return next match that has a token
|
||||
lex:function lex() {
|
||||
var r = this.next();
|
||||
if (r) {
|
||||
return r;
|
||||
} else {
|
||||
return this.lex();
|
||||
}
|
||||
},
|
||||
|
||||
// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
|
||||
begin:function begin(condition) {
|
||||
this.conditionStack.push(condition);
|
||||
},
|
||||
|
||||
// pop the previously active lexer condition state off the condition stack
|
||||
popState:function popState() {
|
||||
var n = this.conditionStack.length - 1;
|
||||
if (n > 0) {
|
||||
return this.conditionStack.pop();
|
||||
} else {
|
||||
return this.conditionStack[0];
|
||||
}
|
||||
},
|
||||
|
||||
// produce the lexer rule set which is active for the currently active lexer condition state
|
||||
_currentRules:function _currentRules() {
|
||||
if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
|
||||
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
|
||||
} else {
|
||||
return this.conditions["INITIAL"].rules;
|
||||
}
|
||||
},
|
||||
|
||||
// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
|
||||
topState:function topState(n) {
|
||||
n = this.conditionStack.length - 1 - Math.abs(n || 0);
|
||||
if (n >= 0) {
|
||||
return this.conditionStack[n];
|
||||
} else {
|
||||
return "INITIAL";
|
||||
}
|
||||
},
|
||||
|
||||
// alias for begin(condition)
|
||||
pushState:function pushState(condition) {
|
||||
this.begin(condition);
|
||||
},
|
||||
|
||||
// return the number of states currently on the stack
|
||||
stateStackSize:function stateStackSize() {
|
||||
return this.conditionStack.length;
|
||||
},
|
||||
options: {},
|
||||
performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
|
||||
var YYSTATE=YY_START;
|
||||
switch($avoiding_name_collisions) {
|
||||
case 0:/* skip whitespace */
|
||||
break;
|
||||
case 1:return 6
|
||||
break;
|
||||
case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4
|
||||
break;
|
||||
case 3:return 17
|
||||
break;
|
||||
case 4:return 18
|
||||
break;
|
||||
case 5:return 23
|
||||
break;
|
||||
case 6:return 24
|
||||
break;
|
||||
case 7:return 22
|
||||
break;
|
||||
case 8:return 21
|
||||
break;
|
||||
case 9:return 10
|
||||
break;
|
||||
case 10:return 11
|
||||
break;
|
||||
case 11:return 8
|
||||
break;
|
||||
case 12:return 14
|
||||
break;
|
||||
case 13:return 'INVALID'
|
||||
break;
|
||||
}
|
||||
},
|
||||
rules: [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/],
|
||||
conditions: {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}}
|
||||
});
|
||||
return lexer;
|
||||
})();
|
||||
parser.lexer = lexer;
|
||||
function Parser () {
|
||||
this.yy = {};
|
||||
}
|
||||
Parser.prototype = parser;parser.Parser = Parser;
|
||||
return new Parser;
|
||||
})();
|
||||
|
||||
|
||||
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
||||
exports.parser = parser;
|
||||
exports.Parser = parser.Parser;
|
||||
exports.parse = function () { return parser.parse.apply(parser, arguments); };
|
||||
}
|
||||
34
node_modules/@mapbox/jsonlint-lines-primitives/package.json
generated
vendored
Normal file
34
node_modules/@mapbox/jsonlint-lines-primitives/package.json
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"author": "Zach Carter <zach@carter.name> (http://zaa.ch)",
|
||||
"name": "@mapbox/jsonlint-lines-primitives",
|
||||
"description": "Validate JSON",
|
||||
"keywords": [
|
||||
"json",
|
||||
"validation",
|
||||
"lint",
|
||||
"jsonlint"
|
||||
],
|
||||
"version": "2.0.2",
|
||||
"preferGlobal": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/mapbox/jsonlint.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "http://github.com/mapbox/jsonlint/issues"
|
||||
},
|
||||
"main": "lib/jsonlint.js",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"test": "*",
|
||||
"jison": "*",
|
||||
"uglify-js": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node test/all-tests.js"
|
||||
},
|
||||
"optionalDependencies": {}
|
||||
}
|
||||
8
node_modules/@mapbox/jsonlint-lines-primitives/scripts/bundle.js
generated
vendored
Normal file
8
node_modules/@mapbox/jsonlint-lines-primitives/scripts/bundle.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
var fs = require('fs');
|
||||
|
||||
var source = "var jsonlint = (function(){var require=true,module=false;var exports={};" +
|
||||
fs.readFileSync(__dirname+'/../lib/jsonlint.js', 'utf8') +
|
||||
"return exports;})()";
|
||||
|
||||
console.log(source);
|
||||
|
||||
24
node_modules/@mapbox/jsonlint-lines-primitives/src/jsonlint.l
generated
vendored
Normal file
24
node_modules/@mapbox/jsonlint-lines-primitives/src/jsonlint.l
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
int "-"?([0-9]|[1-9][0-9]+)
|
||||
exp [eE][-+]?[0-9]+
|
||||
frac "."[0-9]+
|
||||
|
||||
%%
|
||||
\s+ /* skip whitespace */
|
||||
|
||||
{int}{frac}?{exp}?\b return 'NUMBER'
|
||||
\"(?:'\\'[\\"bfnrt/]|'\\u'[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*\" yytext = yytext.substr(1,yyleng-2); return 'STRING'
|
||||
|
||||
"{" return '{'
|
||||
"}" return '}'
|
||||
"[" return '['
|
||||
"]" return ']'
|
||||
"," return ','
|
||||
":" return ':'
|
||||
"true" return 'TRUE'
|
||||
"false" return 'FALSE'
|
||||
"null" return 'NULL'
|
||||
<<EOF>> return 'EOF'
|
||||
. return 'INVALID'
|
||||
|
||||
%%
|
||||
|
||||
110
node_modules/@mapbox/jsonlint-lines-primitives/src/jsonlint.y
generated
vendored
Normal file
110
node_modules/@mapbox/jsonlint-lines-primitives/src/jsonlint.y
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
%start JSONText
|
||||
|
||||
/*
|
||||
ECMA-262 5th Edition, 15.12.1 The JSON Grammar.
|
||||
*/
|
||||
|
||||
|
||||
%%
|
||||
|
||||
JSONString
|
||||
: STRING
|
||||
{ // replace escaped characters with actual character
|
||||
$$ = new String(yytext.replace(/\\(\\|")/g, "$"+"1")
|
||||
.replace(/\\n/g,'\n')
|
||||
.replace(/\\r/g,'\r')
|
||||
.replace(/\\t/g,'\t')
|
||||
.replace(/\\v/g,'\v')
|
||||
.replace(/\\f/g,'\f')
|
||||
.replace(/\\b/g,'\b'));
|
||||
$$.__line__ = @$.first_line;
|
||||
}
|
||||
;
|
||||
|
||||
JSONNumber
|
||||
: NUMBER
|
||||
{
|
||||
$$ = new Number(yytext);
|
||||
$$.__line__ = @$.first_line;
|
||||
}
|
||||
;
|
||||
|
||||
JSONNullLiteral
|
||||
: NULL
|
||||
{
|
||||
$$ = null;
|
||||
}
|
||||
;
|
||||
|
||||
JSONBooleanLiteral
|
||||
: TRUE
|
||||
{
|
||||
$$ = new Boolean(true);
|
||||
$$.__line__ = @$.first_line;
|
||||
}
|
||||
| FALSE
|
||||
{
|
||||
$$ = new Boolean(false);
|
||||
$$.__line__ = @$.first_line;
|
||||
}
|
||||
;
|
||||
|
||||
JSONText
|
||||
: JSONValue EOF
|
||||
{return $$ = $1;}
|
||||
;
|
||||
|
||||
JSONValue
|
||||
: JSONNullLiteral
|
||||
| JSONBooleanLiteral
|
||||
| JSONString
|
||||
| JSONNumber
|
||||
| JSONObject
|
||||
| JSONArray
|
||||
;
|
||||
|
||||
JSONObject
|
||||
: '{' '}'
|
||||
{$$ = {}; Object.defineProperty($$, '__line__', {
|
||||
value: @$.first_line,
|
||||
enumerable: false
|
||||
})}
|
||||
| '{' JSONMemberList '}'
|
||||
{$$ = $2; Object.defineProperty($$, '__line__', {
|
||||
value: @$.first_line,
|
||||
enumerable: false
|
||||
})}
|
||||
;
|
||||
|
||||
JSONMember
|
||||
: JSONString ':' JSONValue
|
||||
{$$ = [$1, $3];}
|
||||
;
|
||||
|
||||
JSONMemberList
|
||||
: JSONMember
|
||||
{{$$ = {}; $$[$1[0]] = $1[1];}}
|
||||
| JSONMemberList ',' JSONMember
|
||||
{$$ = $1; $1[$3[0]] = $3[1];}
|
||||
;
|
||||
|
||||
JSONArray
|
||||
: '[' ']'
|
||||
{$$ = []; Object.defineProperty($$, '__line__', {
|
||||
value: @$.first_line,
|
||||
enumerable: false
|
||||
})}
|
||||
| '[' JSONElementList ']'
|
||||
{$$ = $2; Object.defineProperty($$, '__line__', {
|
||||
value: @$.first_line,
|
||||
enumerable: false
|
||||
})}
|
||||
;
|
||||
|
||||
JSONElementList
|
||||
: JSONValue
|
||||
{$$ = [$1];}
|
||||
| JSONElementList ',' JSONValue
|
||||
{$$ = $1; $1.push($3);}
|
||||
;
|
||||
|
||||
210
node_modules/@mapbox/jsonlint-lines-primitives/test/all-tests.js
generated
vendored
Normal file
210
node_modules/@mapbox/jsonlint-lines-primitives/test/all-tests.js
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
var fs = require("fs"),
|
||||
assert = require("assert"),
|
||||
parser = require("../lib/jsonlint").parser;
|
||||
|
||||
exports["test string with line break"] = function () {
|
||||
var json = '{"foo": "bar\nbar"}';
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test string literal"] = function () {
|
||||
var json = '"foo"';
|
||||
assert.equal(parser.parse(json), "foo");
|
||||
assert.equal(parser.parse(json).__line__, 1);
|
||||
};
|
||||
|
||||
exports["test number literal"] = function () {
|
||||
var json = '1234';
|
||||
assert.equal(parser.parse(json), 1234);
|
||||
assert.equal(parser.parse(json).__line__, 1);
|
||||
};
|
||||
|
||||
exports["test null literal"] = function () {
|
||||
var json = 'null';
|
||||
assert.equal(parser.parse(json), null);
|
||||
};
|
||||
|
||||
exports["test boolean literal"] = function () {
|
||||
var json = 'true';
|
||||
assert.equal(parser.parse(json), true);
|
||||
assert.equal(parser.parse(json).__line__, 1);
|
||||
};
|
||||
|
||||
exports["test unclosed array"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/2.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test unquotedkey keys must be quoted"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/3.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test extra comma"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/4.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test double extra comma"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/5.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test missing value"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/6.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test comma after the close"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/7.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test extra close"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/8.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test extra comma after value"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/9.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test extra value after close with misplaced quotes"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/10.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test illegal expression addition"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/11.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test illegal invocation of alert"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/12.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test numbers cannot have leading zeroes"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/13.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test numbers cannot be hex"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/14.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test illegal backslash escape \\0"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/15.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test unquoted text"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/16.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test illegal backslash escape \\x"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/17.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test missing colon"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/19.json")
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test double colon"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/20.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test comma instead of colon"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/21.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test colon instead of comma"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/22.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test bad raw value"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/23.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test single quotes"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/24.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test tab character in string"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/25.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test tab character in string 2"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/26.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test line break in string"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/27.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test line break in string in array"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/28.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test 0e"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/29.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test 0e+"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/30.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test 0e+ 1"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/31.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test comma instead of closing brace"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/32.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
};
|
||||
|
||||
exports["test bracket mismatch"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/33.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
}
|
||||
|
||||
exports["test extra brace"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/fails/34.json").toString();
|
||||
assert["throws"](function () {parser.parse(json)}, "should throw error");
|
||||
}
|
||||
|
||||
exports["test pass-1"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/passes/1.json").toString();
|
||||
assert.doesNotThrow(function () {parser.parse(json)}, "should pass");
|
||||
}
|
||||
|
||||
exports["test pass-2"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/passes/2.json").toString();
|
||||
assert.doesNotThrow(function () {parser.parse(json)}, "should pass");
|
||||
}
|
||||
|
||||
exports["test pass-3"] = function () {
|
||||
var json = fs.readFileSync(__dirname + "/passes/3.json").toString();
|
||||
assert.doesNotThrow(function () {parser.parse(json)}, "should pass");
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
require("test").run(exports);
|
||||
}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/10.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/10.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Extra value after close": true} "misplaced quoted value"
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/11.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/11.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Illegal expression": 1 + 2}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/12.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/12.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Illegal invocation": alert()}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/13.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/13.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Numbers cannot have leading zeroes": 013}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/14.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/14.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Numbers cannot be hex": 0x14}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/15.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/15.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["Illegal backslash escape: \x15"]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/16.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/16.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[\naked]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/17.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/17.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["Illegal backslash escape: \017"]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/19.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/19.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Missing colon" null}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/2.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/2.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["Unclosed array"
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/20.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/20.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Double colon":: null}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/21.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/21.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Comma instead of colon", null}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/22.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/22.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["Colon instead of comma": false]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/23.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/23.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["Bad value", truth]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/24.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/24.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
['single quote']
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/25.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/25.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[" tab character in string "]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/26.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/26.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["tab\ character\ in\ string\ "]
|
||||
2
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/27.json
generated
vendored
Normal file
2
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/27.json
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
["line
|
||||
break"]
|
||||
2
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/28.json
generated
vendored
Normal file
2
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/28.json
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
["line\
|
||||
break"]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/29.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/29.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[0e]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/3.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/3.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{unquoted_key: "keys must be quoted"}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/30.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/30.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[0e+]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/31.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/31.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[0e+-1]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/32.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/32.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Comma instead if closing brace": true,
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/33.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/33.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["mismatch"}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/34.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/34.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"extra brace": 1}}
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/4.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/4.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["extra comma",]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/5.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/5.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["double extra comma",,]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/6.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/6.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[ , "<-- missing value"]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/7.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/7.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["Comma after the close"],
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/8.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/8.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
["Extra close"]]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/9.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/fails/9.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"Extra comma": true,}
|
||||
58
node_modules/@mapbox/jsonlint-lines-primitives/test/passes/1.json
generated
vendored
Normal file
58
node_modules/@mapbox/jsonlint-lines-primitives/test/passes/1.json
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
[
|
||||
"JSON Test Pattern pass1",
|
||||
{"object with 1 member":["array with 1 element"]},
|
||||
{},
|
||||
[],
|
||||
-42,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
{
|
||||
"integer": 1234567890,
|
||||
"real": -9876.543210,
|
||||
"e": 0.123456789e-12,
|
||||
"E": 1.234567890E+34,
|
||||
"": 23456789012E66,
|
||||
"zero": 0,
|
||||
"one": 1,
|
||||
"space": " ",
|
||||
"quote": "\"",
|
||||
"backslash": "\\",
|
||||
"controls": "\b\f\n\r\t",
|
||||
"slash": "/ & \/",
|
||||
"alpha": "abcdefghijklmnopqrstuvwyz",
|
||||
"ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",
|
||||
"digit": "0123456789",
|
||||
"0123456789": "digit",
|
||||
"special": "`1~!@#$%^&*()_+-={':[,]}|;.</>?",
|
||||
"hex": "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A",
|
||||
"true": true,
|
||||
"false": false,
|
||||
"null": null,
|
||||
"array":[ ],
|
||||
"object":{ },
|
||||
"address": "50 St. James Street",
|
||||
"url": "http://www.JSON.org/",
|
||||
"comment": "// /* <!-- --",
|
||||
"# -- --> */": " ",
|
||||
" s p a c e d " :[1,2 , 3
|
||||
|
||||
,
|
||||
|
||||
4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],
|
||||
"jsontext": "{\"object with 1 member\":[\"array with 1 element\"]}",
|
||||
"quotes": "" \u0022 %22 0x22 034 "",
|
||||
"\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"
|
||||
: "A key can be any string"
|
||||
},
|
||||
0.5 ,98.6
|
||||
,
|
||||
99.44
|
||||
,
|
||||
|
||||
1066,
|
||||
1e1,
|
||||
0.1e1,
|
||||
1e-1,
|
||||
1e00,2e+00,2e-00
|
||||
,"rosebud"]
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/test/passes/2.json
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/test/passes/2.json
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
[[[[[[[[[[[[[[[[[[["Not too deep"]]]]]]]]]]]]]]]]]]]
|
||||
6
node_modules/@mapbox/jsonlint-lines-primitives/test/passes/3.json
generated
vendored
Normal file
6
node_modules/@mapbox/jsonlint-lines-primitives/test/passes/3.json
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"JSON Test Pattern pass3": {
|
||||
"The outermost value": "must be an object or array.",
|
||||
"In this test": "It is an object."
|
||||
}
|
||||
}
|
||||
334
node_modules/@mapbox/jsonlint-lines-primitives/web/json2.js
generated
vendored
Normal file
334
node_modules/@mapbox/jsonlint-lines-primitives/web/json2.js
generated
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
|
||||
/*jslint evil: true, strict: false */
|
||||
|
||||
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||
test, toJSON, toString, valueOf
|
||||
*/
|
||||
|
||||
|
||||
// Create a JSON object only if one does not already exist. We create the
|
||||
// methods in a closure to avoid creating global variables.
|
||||
|
||||
if (!this.JSON) {
|
||||
this.JSON = {};
|
||||
}
|
||||
|
||||
(function () {
|
||||
|
||||
function f(n) {
|
||||
// Format integers to have at least two digits.
|
||||
return n < 10 ? '0' + n : n;
|
||||
}
|
||||
|
||||
if (typeof Date.prototype.toJSON !== 'function') {
|
||||
|
||||
Date.prototype.toJSON = function (key) {
|
||||
|
||||
return isFinite(this.valueOf()) ?
|
||||
this.getUTCFullYear() + '-' +
|
||||
f(this.getUTCMonth() + 1) + '-' +
|
||||
f(this.getUTCDate()) + 'T' +
|
||||
f(this.getUTCHours()) + ':' +
|
||||
f(this.getUTCMinutes()) + ':' +
|
||||
f(this.getUTCSeconds()) + 'Z' : null;
|
||||
};
|
||||
|
||||
String.prototype.toJSON =
|
||||
Number.prototype.toJSON =
|
||||
Boolean.prototype.toJSON = function (key) {
|
||||
return this.valueOf();
|
||||
};
|
||||
}
|
||||
|
||||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||
gap,
|
||||
indent,
|
||||
meta = { // table of character substitutions
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
},
|
||||
rep;
|
||||
|
||||
|
||||
function quote(string) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe escape
|
||||
// sequences.
|
||||
|
||||
escapable.lastIndex = 0;
|
||||
return escapable.test(string) ?
|
||||
'"' + string.replace(escapable, function (a) {
|
||||
var c = meta[a];
|
||||
return typeof c === 'string' ? c :
|
||||
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
}) + '"' :
|
||||
'"' + string + '"';
|
||||
}
|
||||
|
||||
|
||||
function str(key, holder) {
|
||||
|
||||
// Produce a string from holder[key].
|
||||
|
||||
var i, // The loop counter.
|
||||
k, // The member key.
|
||||
v, // The member value.
|
||||
length,
|
||||
mind = gap,
|
||||
partial,
|
||||
value = holder[key];
|
||||
|
||||
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||
|
||||
if (value && typeof value === 'object' &&
|
||||
typeof value.toJSON === 'function') {
|
||||
value = value.toJSON(key);
|
||||
}
|
||||
|
||||
// If we were called with a replacer function, then call the replacer to
|
||||
// obtain a replacement value.
|
||||
|
||||
if (typeof rep === 'function') {
|
||||
value = rep.call(holder, key, value);
|
||||
}
|
||||
|
||||
// What happens next depends on the value's type.
|
||||
|
||||
switch (typeof value) {
|
||||
case 'string':
|
||||
return quote(value);
|
||||
|
||||
case 'number':
|
||||
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
|
||||
return isFinite(value) ? String(value) : 'null';
|
||||
|
||||
case 'boolean':
|
||||
case 'null':
|
||||
|
||||
// If the value is a boolean or null, convert it to a string. Note:
|
||||
// typeof null does not produce 'null'. The case is included here in
|
||||
// the remote chance that this gets fixed someday.
|
||||
|
||||
return String(value);
|
||||
|
||||
// If the type is 'object', we might be dealing with an object or an array or
|
||||
// null.
|
||||
|
||||
case 'object':
|
||||
|
||||
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||
// so watch out for that case.
|
||||
|
||||
if (!value) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
// Make an array to hold the partial results of stringifying this object value.
|
||||
|
||||
gap += indent;
|
||||
partial = [];
|
||||
|
||||
// Is the value an array?
|
||||
|
||||
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||
|
||||
// The value is an array. Stringify every element. Use null as a placeholder
|
||||
// for non-JSON values.
|
||||
|
||||
length = value.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
partial[i] = str(i, value) || 'null';
|
||||
}
|
||||
|
||||
// Join all of the elements together, separated with commas, and wrap them in
|
||||
// brackets.
|
||||
|
||||
v = partial.length === 0 ? '[]' :
|
||||
gap ? '[\n' + gap +
|
||||
partial.join(',\n' + gap) + '\n' +
|
||||
mind + ']' :
|
||||
'[' + partial.join(',') + ']';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
|
||||
// If the replacer is an array, use it to select the members to be stringified.
|
||||
|
||||
if (rep && typeof rep === 'object') {
|
||||
length = rep.length;
|
||||
for (i = 0; i < length; i += 1) {
|
||||
k = rep[i];
|
||||
if (typeof k === 'string') {
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
// Otherwise, iterate through all of the keys in the object.
|
||||
|
||||
for (k in value) {
|
||||
if (Object.hasOwnProperty.call(value, k)) {
|
||||
v = str(k, value);
|
||||
if (v) {
|
||||
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Join all of the member texts together, separated with commas,
|
||||
// and wrap them in braces.
|
||||
|
||||
v = partial.length === 0 ? '{}' :
|
||||
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
|
||||
mind + '}' : '{' + partial.join(',') + '}';
|
||||
gap = mind;
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
// If the JSON object does not yet have a stringify method, give it one.
|
||||
|
||||
if (typeof JSON.stringify !== 'function') {
|
||||
JSON.stringify = function (value, replacer, space) {
|
||||
|
||||
// The stringify method takes a value and an optional replacer, and an optional
|
||||
// space parameter, and returns a JSON text. The replacer can be a function
|
||||
// that can replace values, or an array of strings that will select the keys.
|
||||
// A default replacer method can be provided. Use of the space parameter can
|
||||
// produce text that is more easily readable.
|
||||
|
||||
var i;
|
||||
gap = '';
|
||||
indent = '';
|
||||
|
||||
// If the space parameter is a number, make an indent string containing that
|
||||
// many spaces.
|
||||
|
||||
if (typeof space === 'number') {
|
||||
for (i = 0; i < space; i += 1) {
|
||||
indent += ' ';
|
||||
}
|
||||
|
||||
// If the space parameter is a string, it will be used as the indent string.
|
||||
|
||||
} else if (typeof space === 'string') {
|
||||
indent = space;
|
||||
}
|
||||
|
||||
// If there is a replacer, it must be a function or an array.
|
||||
// Otherwise, throw an error.
|
||||
|
||||
rep = replacer;
|
||||
if (replacer && typeof replacer !== 'function' &&
|
||||
(typeof replacer !== 'object' ||
|
||||
typeof replacer.length !== 'number')) {
|
||||
throw new Error('JSON.stringify');
|
||||
}
|
||||
|
||||
// Make a fake root object containing our value under the key of ''.
|
||||
// Return the result of stringifying the value.
|
||||
|
||||
return str('', {'': value});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// If the JSON object does not yet have a parse method, give it one.
|
||||
|
||||
if (typeof JSON.parse !== 'function') {
|
||||
JSON.parse = function (text, reviver) {
|
||||
|
||||
// The parse method takes a text and an optional reviver function, and returns
|
||||
// a JavaScript value if the text is a valid JSON text.
|
||||
|
||||
var j;
|
||||
|
||||
function walk(holder, key) {
|
||||
|
||||
// The walk method is used to recursively walk the resulting structure so
|
||||
// that modifications can be made.
|
||||
|
||||
var k, v, value = holder[key];
|
||||
if (value && typeof value === 'object') {
|
||||
for (k in value) {
|
||||
if (Object.hasOwnProperty.call(value, k)) {
|
||||
v = walk(value, k);
|
||||
if (v !== undefined) {
|
||||
value[k] = v;
|
||||
} else {
|
||||
delete value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return reviver.call(holder, key, value);
|
||||
}
|
||||
|
||||
|
||||
// Parsing happens in four stages. In the first stage, we replace certain
|
||||
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||
|
||||
cx.lastIndex = 0;
|
||||
if (cx.test(text)) {
|
||||
text = text.replace(cx, function (a) {
|
||||
return '\\u' +
|
||||
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||
});
|
||||
}
|
||||
|
||||
// In the second stage, we run the text against regular expressions that look
|
||||
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||
// because they can cause invocation, and '=' because it can cause mutation.
|
||||
// But just to be safe, we want to reject all unexpected forms.
|
||||
|
||||
// We split the second stage into 4 regexp operations in order to work around
|
||||
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||
// we look to see that the remaining characters are only whitespace or ']' or
|
||||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||
|
||||
if (/^[\],:{}\s]*$/.
|
||||
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
|
||||
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
|
||||
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||
|
||||
// In the third stage we use the eval function to compile the text into a
|
||||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||
// in parens to eliminate the ambiguity.
|
||||
|
||||
j = eval('(' + text + ')');
|
||||
|
||||
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||
// each name/value pair to a reviver function for possible transformation.
|
||||
|
||||
return typeof reviver === 'function' ?
|
||||
walk({'': j}, '') : j;
|
||||
}
|
||||
|
||||
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||
|
||||
throw new SyntaxError('JSON.parse');
|
||||
};
|
||||
}
|
||||
}());
|
||||
59
node_modules/@mapbox/jsonlint-lines-primitives/web/jsonlint.html
generated
vendored
Normal file
59
node_modules/@mapbox/jsonlint-lines-primitives/web/jsonlint.html
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>JSON Lint</title>
|
||||
<script src="json2.js"></script>
|
||||
<script src="jsonlint.js"></script>
|
||||
<script>
|
||||
window.onload = function () {
|
||||
document.getElementById("button").onclick = function () {
|
||||
try {
|
||||
var result = jsonlint.parse(document.getElementById("source").value);
|
||||
if (result) {
|
||||
document.getElementById("result").innerHTML = "JSON is valid!";
|
||||
document.getElementById("result").className = "pass";
|
||||
if (document.getElementById("reformat").checked) {
|
||||
document.getElementById("source").value = JSON.stringify(result, null, " ");
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
document.getElementById("result").innerHTML = e;
|
||||
document.getElementById("result").className = "fail";
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {font-family: sans-serif;}
|
||||
#result {
|
||||
padding: 1em;
|
||||
}
|
||||
.pass {
|
||||
background-color: #efe;
|
||||
color: #393;
|
||||
border: 2px solid #393;
|
||||
}
|
||||
.fail {
|
||||
background-color: #fee;
|
||||
color: #933;
|
||||
border: 2px solid #933;
|
||||
}
|
||||
textarea { width: 100%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>JSON Lint</h1>
|
||||
<p>A pure JavaScript version of the service provided at <a href="http://jsonlint.com/">jsonlint.com</a>.</p>
|
||||
<textarea id="source" rows="20" cols="50">
|
||||
|
||||
</textarea>
|
||||
<p>
|
||||
<button id="button">Validate</button>
|
||||
<input type="checkbox" value="yes" id="reformat" /><label for="reformat">reformat JSON</label>
|
||||
</p>
|
||||
<h2>Results</h2>
|
||||
<pre id="result"></pre>
|
||||
<p><a href="http://github.com/zaach/jsonlint">project on github</a></p>
|
||||
</body>
|
||||
</html>
|
||||
1
node_modules/@mapbox/jsonlint-lines-primitives/web/jsonlint.js
generated
vendored
Normal file
1
node_modules/@mapbox/jsonlint-lines-primitives/web/jsonlint.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
10
node_modules/@mapbox/mapbox-gl-style-spec/.eslintrc
generated
vendored
Normal file
10
node_modules/@mapbox/mapbox-gl-style-spec/.eslintrc
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["rollup.config.js", "test.js"],
|
||||
"rules": {
|
||||
"flowtype/require-valid-file-annotation": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
564
node_modules/@mapbox/mapbox-gl-style-spec/CHANGELOG.md
generated
vendored
Normal file
564
node_modules/@mapbox/mapbox-gl-style-spec/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,564 @@
|
||||
## 13.27.0
|
||||
|
||||
### Bug fixes 🐞
|
||||
|
||||
* Fix overwriting all feature ids while setting promoteIds on other layers with an object. ([#12322](https://github.com/mapbox/mapbox-gl-js/pull/12322)) (h/t [yongjun21](https://github.com/yongjun21))
|
||||
|
||||
## 13.26.0
|
||||
|
||||
### Features ✨
|
||||
|
||||
* Add unit option to number-format expression. ([#11839](https://github.com/mapbox/mapbox-gl-js/pull/11839)) (h/t [varna](https://github.com/varna))
|
||||
|
||||
### Bug fixes 🐞
|
||||
|
||||
* Fix a bug where `id` expression didn't correctly handle a value of 0. ([#12000](https://github.com/mapbox/mapbox-gl-js/pull/12000))
|
||||
|
||||
## 13.25.0
|
||||
|
||||
### Features ✨
|
||||
|
||||
* Extend atmospheric `fog` with three new style specification properties: `high-color`, `space-color` and `star-intensity` to allow the design of atmosphere around the globe and night skies. ([#11590](https://github.com/mapbox/mapbox-gl-js/pull/11590))
|
||||
* Add a new line layer paint property in the style specification: `line-trim-offset` that can be used to create a custom fade out with improved update performance over `line-gradient`. ([#11570](https://github.com/mapbox/mapbox-gl-js/pull/11570))
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
* Add `source` field requirement to terrain exaggeration in the style specification. ([#11664](https://github.com/mapbox/mapbox-gl-js/pull/11664))
|
||||
|
||||
## 13.24.0
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
* Fix error on `gl-style-validate` script. ([#11538](https://github.com/mapbox/mapbox-gl-js/pull/11538))
|
||||
* Allow the second argument to the `in` expression operator to be an empty string. ([#11547](https://github.com/mapbox/mapbox-gl-js/pull/11547))
|
||||
* Fix error on some valid `filter` expressions. ([#11475](https://github.com/mapbox/mapbox-gl-js/pull/11475))
|
||||
|
||||
## 13.23.1
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Improve `coalesce` expressions to return a `ResolvedImage` when images are missing. ([#11371](https://github.com/mapbox/mapbox-gl-js/pull/11371))
|
||||
|
||||
## 13.23.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Add a `projection` root property that allows a non-mercator projection to be set as a style's default projection. ([#11124](https://github.com/mapbox/mapbox-gl-js/pull/11124))
|
||||
* Add support for using `["pitch"]` and `["distance-from-camera"]` expressions within the `filter` of a symbol layer. ([#10795](https://github.com/mapbox/mapbox-gl-js/pull/10795))
|
||||
|
||||
## 13.22.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Added `protected` field to mapbox-api-supported validation. ([#10968](https://github.com/mapbox/mapbox-gl-js/pull/10968))
|
||||
|
||||
## 13.21.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add support for `text-writing-mode` property when using `symbol-placement: line` text labels. ([#10647](https://github.com/mapbox/mapbox-gl-js/pull/10647))
|
||||
* Note: This change will bring following changes for CJK text block:
|
||||
* 1. For vertical CJK text, all the characters including Latin and Numbers will be vertically placed now. Previously, Latin and Numbers are horizontally placed.
|
||||
* 2. For horizontal CJK text, it may have a slight horizontal shift due to the anchor shift.
|
||||
|
||||
## 13.20.1
|
||||
|
||||
### 🐞 Bug fixes
|
||||
|
||||
* Increase strictness of the style API validation for source types ([#10779](https://github.com/mapbox/mapbox-gl-js/pull/10779))
|
||||
* Remove strictly-increasing requirement for fog range validation ([#10772](https://github.com/mapbox/mapbox-gl-js/pull/10772))
|
||||
|
||||
## 13.20.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Add configurable fog as a root style specification ([#10564](https://github.com/mapbox/mapbox-gl-js/pull/10564))
|
||||
* Add support for data-driven expressions in `line-dasharray` and `line-cap` properties. ([#10591](https://github.com/mapbox/mapbox-gl-js/pull/10591))
|
||||
* Add support for data-driven `text-line-height` ([#10612](https://github.com/mapbox/mapbox-gl-js/pull/10612))
|
||||
|
||||
## 13.19.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Added array support to minimums and maximums, allowing for validation of multi-dimensional style-spec value constraints. ([#10272](https://github.com/mapbox/mapbox-gl-js/pull/10272))
|
||||
|
||||
## 13.18.1
|
||||
|
||||
### 🐞 Bug fixes
|
||||
* Fixed a bug where `map.setStyle` couldn't be used to enable terrain. ([#10177](https://github.com/mapbox/mapbox-gl-js/pull/10177))
|
||||
|
||||
## 13.18.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Add 3D terrain feature. All layer types and markers can now be extruded using the new `terrain` root level style-spec property or with the function `map.setTerrain()`. ([#1489](https://github.com/mapbox/mapbox-gl-js/issues/1489))
|
||||
* Add support for unlocked pitch up to 85° (previously 60°). ([#3731](https://github.com/mapbox/mapbox-gl-js/issues/3731))
|
||||
* Add a new sky layer acting as an infinite background above the horizon line. This layer can be used from the style-spec and has two types: `atmospheric` and `gradient`.
|
||||
|
||||
## 13.17.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add a `filter` option for GeoJSON sources to filter out features prior to processing (e.g. before clustering). [#9864](https://github.com/mapbox/mapbox-gl-js/pull/9864)
|
||||
|
||||
## 13.16.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Added `volatile` source property to control storing the tiles in local storage. ([9702](https://github.com/mapbox/mapbox-gl-js/pull/9702))
|
||||
|
||||
* Added `clusterMinPoints` option for clustered GeoJSON sources that defines the minimum number of points to form a cluster. ([#9748](https://github.com/mapbox/mapbox-gl-js/pull/9748))
|
||||
|
||||
## 13.15.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `distance` expression to `style-spec`. This expression returns the shortest distance between a feature and an input geometry ([#9655](https://github.com/mapbox/mapbox-gl-js/pull/9655))
|
||||
|
||||
## 13.14.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `index-of` and `slice` expressions to search arrays and strings for the first occurrence of a specified value and return a section of the original array or string ([#9450](https://github.com/mapbox/mapbox-gl-js/pull/9450)) (h/t [lbutler](https://github.com/lbutler))
|
||||
|
||||
## 13.13.1
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Expose `expression.isExpressionFilter(..)` from the bundle. ([#9530](https://github.com/mapbox/mapbox-gl-js/pull/9530))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Fix a broken module import where the `style-spec` package was importing files from `mapbox-gl-js`, it's parent repo, causing downstream build systems to break. ([#9522](https://github.com/mapbox/mapbox-gl-js/pull/9522))
|
||||
|
||||
## 13.13.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `within` expression for testing whether an evaluated feature lies within a given GeoJSON object ([#9352](https://github.com/mapbox/mapbox-gl-js/pull/9352)). For example:<br>
|
||||
`"icon-opacity": ["case", ["==", ["within", "some-polygon"], true], 1,
|
||||
["==", ["within", "some-polygon"], false], 0]`
|
||||
* Improve scaling of patterns used in `line-pattern` on all device resolutions and pixel ratios ([#9266](https://github.com/mapbox/mapbox-gl-js/pull/9266))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Allow needle argument to `in` expression to be false ([#9295](https://github.com/mapbox/mapbox-gl-js/pull/9295))
|
||||
* Fix a bug where `icon-image` expression that evaluates to an empty string (`''`) produced a warning ([#9380](https://github.com/mapbox/mapbox-gl-js/pull/9380))
|
||||
* Prevent exception resulting from `line-dash-array` of empty length ([#9385](https://github.com/mapbox/mapbox-gl-js/pull/9385))
|
||||
|
||||
## 13.12.0
|
||||
|
||||
* Update `image` expression SDK support table ([#9228](https://github.com/mapbox/mapbox-gl-js/pull/9228))
|
||||
* Fix `promoteId` for line layers ([#9210](https://github.com/mapbox/mapbox-gl-js/pull/9210), [#9212](https://github.com/mapbox/mapbox-gl-js/pull/9212))
|
||||
|
||||
## 13.11.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `promoteId` option to use a feature property as ID for feature state ([#8987](https://github.com/mapbox/mapbox-gl-js/pull/8987))
|
||||
* Update `symbol-avoid-edges` documentation regarding global collision detection ([#9157](https://github.com/mapbox/mapbox-gl-js/pull/9157))
|
||||
* Remove reference to `in` function which has been replaced by the `in` expression ([#9102](https://github.com/mapbox/mapbox-gl-js/pull/9102))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Fix bug where `symbol-sort-key` was not used for collisions that crossed tile boundaries ([#9054](https://github.com/mapbox/mapbox-gl-js/pull/9054))
|
||||
|
||||
## 13.10.2
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Fix style validation error messages not being displayed ([#9073](https://github.com/mapbox/mapbox-gl-js/pull/9073))
|
||||
|
||||
## 13.10.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add ability to insert images into text labels using an `image` expression within a `format` expression: `"text-field": ["format", "Some text", ["image", "my-image"], "some more text"]` ([#8904](https://github.com/mapbox/mapbox-gl-js/pull/8904))
|
||||
* Add `in` expression. It can check if a value is in an array (`["in", value, array]`) or a substring is in a string (`["in", substring, string]`) ([#8876](https://github.com/mapbox/mapbox-gl-js/pull/8876))
|
||||
* Add support for stretchable images (aka nine-part or nine-patch images). Stretchable images can be used with `icon-text-fit` to draw resized images with unstretched corners and borders. ([#8997](https://github.com/mapbox/mapbox-gl-js/pull/8997))
|
||||
* Add an es modules build of for mapbox-gl-style-spec in dist/ ([#8247](https://github.com/mapbox/mapbox-gl-js/pull/8247)) (h/t [ahocevar](https://github.com/ahocevar))
|
||||
|
||||
## 13.9.1
|
||||
|
||||
### ✨ Improvement
|
||||
* Rename `Image` type to `ResolvedImage`, to better represent the result of an `image` expression evaluation. ([#8901](https://github.com/mapbox/mapbox-gl-js/pull/8901))
|
||||
|
||||
## 13.9.0
|
||||
|
||||
* Add `image` expression operator to determine image availability ([#8684](https://github.com/mapbox/mapbox-gl-js/pull/8684))
|
||||
* Add a style-spec function to validate that styles are compatible with the Mapbox API ([#8663](https://github.com/mapbox/mapbox-gl-js/pull/8663))
|
||||
|
||||
## 13.8.0
|
||||
|
||||
- Introduce `text-writing-mode` symbol layer property to allow placing point labels vertically. [#8399](https://github.com/mapbox/mapbox-gl-js/pull/8399)
|
||||
- Allow `text-color` to be used in formatted expressions to be able to draw different parts of a label in different colors. [#8068](https://github.com/mapbox/mapbox-gl-js/pull/8068)
|
||||
- Improve conversion of legacy filters with duplicate values. [#8542](https://github.com/mapbox/mapbox-gl-js/pull/8542)
|
||||
|
||||
## 13.7.2
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Fix SDK support spec section for variable label placement ([#8384](https://github.com/mapbox/mapbox-gl-js/pull/8384)) (h/t [@pozdnyakov](https://github.com/pozdnyakov))
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add SDK support spec section for text-radial-offset ([#8401](https://github.com/mapbox/mapbox-gl-js/pull/8401))
|
||||
* Add `*-sort-key` layout property for circle, fill, line ([#8467](https://github.com/mapbox/mapbox-gl-js/pull/8467))
|
||||
* Expose convertFilter API in the style specification ([#8493](https://github.com/mapbox/mapbox-gl-js/pull/8493))
|
||||
|
||||
## 13.7.1
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Fix format expression options validation ([#8339](https://github.com/mapbox/mapbox-gl-js/pull/8339))
|
||||
* Fix SDK support information for style properties added in v13.7.0: ([#8384](https://github.com/mapbox/mapbox-gl-js/pull/8384))
|
||||
* Add missing SDK support section for `text-radial-offset` property
|
||||
* Assign SDK versions for `text-variable-anchor` and `text-justify: auto`
|
||||
|
||||
## 13.7.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `text-radial-offset` style property ([#7596](https://github.com/mapbox/mapbox-gl-js/pull/7596))
|
||||
* Add `text-variable-anchor` style property ([#7596](https://github.com/mapbox/mapbox-gl-js/pull/7596))
|
||||
* Add `auto` value to `text-justify` style property ([#7596](https://github.com/mapbox/mapbox-gl-js/pull/7596))
|
||||
|
||||
## 13.6.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `clusterProperties` option for aggregated cluster properties ([#2412](https://github.com/mapbox/mapbox-gl-js/issues/2412), fixed by [#7584](https://github.com/mapbox/mapbox-gl-js/pull/7584))
|
||||
* Add `number-format` expression ([#7626](https://github.com/mapbox/mapbox-gl-js/pull/7626))
|
||||
* Add `symbol-sort-key` style property ([#7678](https://github.com/mapbox/mapbox-gl-js/pull/7678))
|
||||
|
||||
## 13.5.0
|
||||
|
||||
### Features and improvements
|
||||
* Flattens `all` expressions in converted filters ([#7679](https://github.com/mapbox/mapbox-gl-js/pull/7679))
|
||||
* Compatibility tables are updated ([#7574](https://github.com/mapbox/mapbox-gl-js/pull/7574))
|
||||
|
||||
## 13.4.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* **Tighten style validation**
|
||||
* Disallow expressions as stop values ([#7396](https://github.com/mapbox/mapbox-gl-js/pull/7396))
|
||||
* Disallow `feature-state` expressions in filters ([#7366](https://github.com/mapbox/mapbox-gl-js/pull/7366))
|
||||
|
||||
## 13.3.0
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* **Expressions**
|
||||
* Fix `let` expression stripping expected type during parsing ([#7300](https://github.com/mapbox/mapbox-gl-js/issues/7300), fixed by [#7301](https://github.com/mapbox/mapbox-gl-js/pull/7301))
|
||||
* Fix superfluous wrapping of literals in `literal` expression ([#7336](https://github.com/mapbox/mapbox-gl-js/issues/7336), fixed by [#7337](https://github.com/mapbox/mapbox-gl-js/pull/7337))
|
||||
* Allow calling `to-color` on values that are already of type `Color` ([#7260](https://github.com/mapbox/mapbox-gl-js/pull/7260))
|
||||
* Fix `to-array` for empty arrays (([#7261](https://github.com/mapbox/mapbox-gl-js/pull/7261)))
|
||||
* Fix identity functions for `text-field` when using formatted text ([#7351](https://github.com/mapbox/mapbox-gl-js/pull/7351))
|
||||
* Fix coercion of `null` to `0` in `to-number` expression ([#7083](https://github.com/mapbox/mapbox-gl-js/issues/7083), fixed by [#7274](https://github.com/mapbox/mapbox-gl-js/pull/7274))
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `fill-extrusion-vertical-gradient` property for controlling shading of fill extrusions ([#5768](https://github.com/mapbox/mapbox-gl-js/issues/5768), fixed by [#6841](https://github.com/mapbox/mapbox-gl-js/pull/6841))
|
||||
|
||||
## 13.2.0
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Update the style-spec's old `gl-style-migrate` script to include conversion of legacy functions and filters to their expression equivalents ([#6927](https://github.com/mapbox/mapbox-gl-js/issues/6927), fixed by [#7095](https://github.com/mapbox/mapbox-gl-js/pull/7095))
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `symbol-z-order` symbol layout property to style spec ([#7219](https://github.com/mapbox/mapbox-gl-js/pull/7219))
|
||||
* Implement data-driven styling support for `*-pattern properties` ([#6289](https://github.com/mapbox/mapbox-gl-js/pull/6289))
|
||||
|
||||
## 13.1.1
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Fix broken module import in mapboxgl-style-spec (v13.0.1) ([#6984](https://github.com/mapbox/mapbox-gl-js/issues/6984), fixed by [#6997](https://api.github.com/repos/mapbox/mapbox-gl-js/pulls/6997))
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Improve formatting for style output ([#7029](https://github.com/mapbox/mapbox-gl-js/pull/7029))
|
||||
|
||||
## 13.1.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `raster-resampling` raster paint property ([#6411](https://github.com/mapbox/mapbox-gl-js/pull/6411)) (h/t [andrewharvey](https://github.com/andrewharvey))
|
||||
* Add `symbol-placement: line-center` ([#6821](https://github.com/mapbox/mapbox-gl-js/pull/6821))
|
||||
|
||||
## 13.0.1
|
||||
|
||||
### ⚠️ Breaking changes
|
||||
* Align implicit type behavior of `match` expressions with with `case/==` ([#6684](https://github.com/mapbox/mapbox-gl-js/pull/6684))
|
||||
* Update spec so that documentation can automatically capture which functions and expressions can be used with which properties ([#6521](https://github.com/mapbox/mapbox-gl-js/pull/6521))
|
||||
|
||||
### ✨ Features and improvements
|
||||
* Add `feature-state` [#6263](https://github.com/mapbox/mapbox-gl-js/pull/6263)
|
||||
* Add support for GeoJSON attribution ([#6364](https://github.com/mapbox/mapbox-gl-js/pull/6364)) (h/t [andrewharvey](https://github.com/andrewharvey))
|
||||
* Upgrade to Flow 0.69 ([#6594](https://github.com/mapbox/mapbox-gl-js/pull/6594))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
* Use named exports for style-spec entrypoint module ([#6601](https://github.com/mapbox/mapbox-gl-js/issues/6601)
|
||||
|
||||
## 13.0.0
|
||||
Malformed package published to NPM.
|
||||
|
||||
## 12.0.0
|
||||
|
||||
### ⚠️ Breaking changes
|
||||
* The `"to-string"` expression operator now converts null to an empty string rather than to `"null"`. [#6534](https://github.com/mapbox/mapbox-gl-js/pull/6534)
|
||||
|
||||
### ✨ Features and improvements
|
||||
* 🌈 Add line-gradient property [#6303](https://github.com/mapbox/mapbox-gl-js/pull/6303)
|
||||
* Add collator expression for controlling case and diacritic sensitivity in string comparisons [#6270](https://github.com/mapbox/mapbox-gl-js/pull/6270)
|
||||
* Add `is-supported-script` expression for determining if a script is supported. [#6260](https://github.com/mapbox/mapbox-gl-js/pull/6260)
|
||||
* Add `collator` expression for controlling case and diacritic sensitivity in string comparisons [#6270](https://github.com/mapbox/mapbox-gl-js/pull/6270)
|
||||
* Add `abs`, `round`, `floor`, and `ceil` expression operators [#6496](https://github.com/mapbox/mapbox-gl-js/pull/6496)
|
||||
* Add support for Mapzen Terrarium tiles in raster-dem sources [#6110](https://github.com/mapbox/mapbox-gl-js/pull/6110)
|
||||
|
||||
### 🐛 Bug fixes
|
||||
- Fix Rollup build [6575](https://github.com/mapbox/mapbox-gl-js/pull/6575)
|
||||
|
||||
## 11.1.1
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
* Update SDK support information for `text-font`, and `heatmap-color`, and `hillshade` layer properties.
|
||||
|
||||
## 11.1.0
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Avoid use of `new Function` for filters by converting old-style filters to expressions [#5665](https://github.com/mapbox/mapbox-gl-js/pull/5665).
|
||||
|
||||
## 11.0.0
|
||||
|
||||
### ⚠️ Breaking changes
|
||||
|
||||
* Remove constants validating code [#5885](https://github.com/mapbox/mapbox-gl-js/pull/5885)
|
||||
* `"colorSpace": "hcl"` now uses shortest-path interpolation for hue [#5811](https://github.com/mapbox/mapbox-gl-js/issues/5811)
|
||||
|
||||
### ✨ Features and improvements
|
||||
|
||||
* Introduce client-side hillshading with `raster-dem` source type and `hillshade` layer type [#5286](https://github.com/mapbox/mapbox-gl-js/pull/5286)
|
||||
* Add Color#toString and expose Color publicly [#5866](https://github.com/mapbox/mapbox-gl-js/pull/5866)
|
||||
* Improve typing for `==` and `!=` expressions [#5840](https://github.com/mapbox/mapbox-gl-js/pull/5840)
|
||||
* Made `coalesce` expressions more useful [#5755](https://github.com/mapbox/mapbox-gl-js/issues/5755)
|
||||
* Enable implicit type assertions for array types [#5738](https://github.com/mapbox/mapbox-gl-js/pull/5738)
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
* Fix standalone browser build [#5736](https://github.com/mapbox/mapbox-gl-js/pull/5736), [#5906](https://github.com/mapbox/mapbox-gl-js/pull/5906)
|
||||
* Handle NaN as input to step and interpolate expressions [#5757](https://github.com/mapbox/mapbox-gl-js/pull/5757)
|
||||
* Fix style diffing for changes to GeoJSON sources [#5745](https://github.com/mapbox/mapbox-gl-js/pull/5745)
|
||||
* Mark layer "type" property as required [#5849](https://github.com/mapbox/mapbox-gl-js/pull/5849)
|
||||
|
||||
## 10.1.0
|
||||
|
||||
* Remove support for validating and migrating v6 styles [#5604](https://github.com/mapbox/mapbox-gl-js/pull/5604)
|
||||
* Remove support for validating v7 styles [#5604](https://github.com/mapbox/mapbox-gl-js/pull/5604)
|
||||
* Remove spaces after commas in `to-string` representation of colors [#5480](https://github.com/mapbox/mapbox-gl-js/pull/5480)
|
||||
* Fix bugs preventing `mapbox-gl-style-spec` package on NPM from being used externally [#5502](https://github.com/mapbox/mapbox-gl-js/pull/5502)
|
||||
* Fix flow-typed interface generator [#5478](https://github.com/mapbox/mapbox-gl-js/pull/5478)
|
||||
* Export `function` [#5584](https://github.com/mapbox/mapbox-gl-js/pull/5584)
|
||||
* Export `StylePropertySpecification` type [#5593](https://github.com/mapbox/mapbox-gl-js/pull/5593)
|
||||
* Split the `source_tile` entry in the JSON schema into `source_vector` and `source_raster` [#5604](https://github.com/mapbox/mapbox-gl-js/pull/5604)
|
||||
|
||||
### Validation Changes
|
||||
|
||||
* Require that `heatmap-color` use expressions instead of stop functions [#5624](https://github.com/mapbox/mapbox-gl-js/issues/5624)
|
||||
* Remove support for including `{tokens}` in expressions for `text-field` and `icon-image` [#5599](https://github.com/mapbox/mapbox-gl-js/issues/5599)
|
||||
* Disallow interpolation in expressions for `line-dasharray` [#5519](https://github.com/mapbox/mapbox-gl-js/pull/5519)
|
||||
* Validate that zoom expressions only appear at the top level of an expression [#5609](https://github.com/mapbox/mapbox-gl-js/issues/5609)
|
||||
* Validate that `step` and `interpolate` expressions don't have any duplicate stops [#5605](https://github.com/mapbox/mapbox-gl-js/issues/5605)
|
||||
* Split `curve` expression into `step` and `interpolate` expressions [#5542](https://github.com/mapbox/mapbox-gl-js/pull/5542)
|
||||
* Validate expression values for enum-typed properties [#5589](https://github.com/mapbox/mapbox-gl-js/pull/5589)
|
||||
* Improve validation to catch uses of deprecated function syntax [#5667](https://github.com/mapbox/mapbox-gl-js/pull/5667)
|
||||
|
||||
## 10.0.1
|
||||
|
||||
* Fix bug preventing @mapbox/mapbox-gl-style-spec package from being usable outside of mapbox-gl-js (#5502)
|
||||
|
||||
## 10.0.0
|
||||
|
||||
* Add expression and heatmap layer support. See Mapbox GL JS v0.40.1 changelog entry for details.
|
||||
|
||||
## 9.0.1
|
||||
|
||||
* Remove `fast-stable-stringify` dependency (#5152)
|
||||
|
||||
## 9.0.0
|
||||
|
||||
* Fix validation error on categorical zoom-and-property functions (#4220)
|
||||
* Relax requirement that styles using "icon-image" must have a "sprite"
|
||||
* Prevent infinite loop in binarySearchForIndex when duplicate stops are present. (#4503)
|
||||
* Ensure generated composite function stops are in the correct order (#4509)
|
||||
* Update SDK support matrices to be current as of GL JS v0.35.1, iOS SDK v3.5.0, Android SDK 5.0.0
|
||||
* Remove support for implicitly-categorical functions
|
||||
* BREAKING CHANGE: the API for the `function` module has changed. The `interpolated` and `piecewise-constant` exports
|
||||
were replaced with a single unnamed export, a function which accepts an object conforming to the style spec "function"
|
||||
definition, and an object defining a style spec property. It handles color parsing and validation of feature values
|
||||
internally.
|
||||
* Functions now support a "default" property.
|
||||
* `parseColor` was promoted from gl-js.
|
||||
|
||||
## 8.11.0
|
||||
|
||||
* Merge `feature-filter` repository into this repository #639
|
||||
|
||||
## 8.10.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.10.0.
|
||||
|
||||
### Style Specification Changes
|
||||
|
||||
* Added `colorSpace` option to functions
|
||||
* Added `fill-extrusion` layer type
|
||||
* Add top-level `light` property
|
||||
* Remove increase maximum `maxzoom` to 24
|
||||
* Deprecate paint classes :warning:
|
||||
* Increase strictness of function validation
|
||||
|
||||
### Reference JSON & API Changes
|
||||
|
||||
* Added `deref` utility
|
||||
* Added `group_by_layout` utility
|
||||
* Merge `mapbox-gl-function` repository into this repository
|
||||
|
||||
## 8.9.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.9.0.
|
||||
|
||||
* Added identity functions
|
||||
* Added `auto` value which represents the calculated default value
|
||||
|
||||
## 8.8.1
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.8.1.
|
||||
|
||||
* Fixed style validation for layers with invalid types
|
||||
|
||||
## 8.8.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.8.0.
|
||||
|
||||
* Clarified documentation around fill-opacity.
|
||||
* Update function documentation and validation for property functions.
|
||||
* Add text-pitch-alignment property.
|
||||
* Add icon-text-fit, icon-text-fit-padding properties.
|
||||
|
||||
## 8.7.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.7.0.
|
||||
|
||||
* Add support for has / !has operators.
|
||||
|
||||
## 8.6.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.6.0.
|
||||
|
||||
* Added support for zoom and feature driven functions.
|
||||
|
||||
## 8.4.2
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.4.2.
|
||||
|
||||
* Refactored style validator to expose more granular validation methods
|
||||
|
||||
## 8.4.1
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.4.1.
|
||||
|
||||
* Revert ramp validation checks that broke some styles.
|
||||
|
||||
## 8.4.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.4.0.
|
||||
|
||||
* Added `cluster`, `clusterRadius`, `clusterMaxZoom` GeoJSON source properties.
|
||||
|
||||
## 8.3.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.3.0.
|
||||
|
||||
* Added `line-offset` style property
|
||||
|
||||
## 8.2.1
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.2.1.
|
||||
|
||||
* Enforce that all layers that use a vector source specify a "source-layer"
|
||||
|
||||
## 8.2.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.2.0.
|
||||
|
||||
* Add inline `example` property.
|
||||
* Enforce that all style properties must have documentation in `doc` property.
|
||||
* Create minified style specs with `doc` and `example` properties removed.
|
||||
* `validate` now validates against minified style spec.
|
||||
* `format` now accepts `space` option to use with `JSON.stringify`.
|
||||
* Remove `gl-style-spritify`. Mapbox GL sprites are now created automatically by
|
||||
the Mapbox style APIs, or for hand-crafted styles, by [spritezero-cli](https://github.com/mapbox/spritezero-cli).
|
||||
|
||||
## 8.1.0
|
||||
|
||||
v8.0.0 styles are fully compatible with v8.1.0.
|
||||
|
||||
* [BREAKING] Simplified layout/paint layer property types to more closely align
|
||||
with v7 types.
|
||||
* Fixed migration script compatibility with newer versions of Node.js and io.js
|
||||
* Removed `constants` from schema, they were deprecated in v8
|
||||
* Added style diff utility to generate semantic deltas between two stylesheets
|
||||
* Added `visibility` property to `circle` layer type
|
||||
* Added `pitch` property to stylesheet
|
||||
|
||||
## 8.0.0
|
||||
|
||||
Introduction of Mapbox GL style specification v8. To migrate a v7 style to v8,
|
||||
use the `gl-style-migrate` script as described in the README.
|
||||
|
||||
* [BREAKING] The value of the `text-font` property is now an array of
|
||||
strings, rather than a single comma separated string.
|
||||
* [BREAKING] Renamed `symbol-min-distance` to `symbol-spacing`.
|
||||
* [BREAKING] Renamed `background-image` to `background-pattern`.
|
||||
* [BREAKING] Renamed `line-image` to `line-pattern`.
|
||||
* [BREAKING] Renamed `fill-image` to `fill-pattern`.
|
||||
* [BREAKING] Renamed the `url` property of the video source type to `urls`.
|
||||
* [BREAKING] Coordinates in video sources are now specified in [lon, lat] order.
|
||||
* [BREAKING] Removed `text-max-size` and `icon-max-size` properties; these
|
||||
are now calculated automatically.
|
||||
* [BREAKING] `text-size` and `icon-size` are now layout properties instead of paint properties.
|
||||
* [BREAKING] Constants are no longer supported. If you are editing styles by
|
||||
hand and want to use constants, you can use a preprocessing step with a tool
|
||||
like [ScreeSS](https://github.com/screee/screess).
|
||||
* [BREAKING] The format for `mapbox://` glyphs URLs has changed; you should
|
||||
now use `mapbox://fonts/mapbox/{fontstack}/{range}.pbf`.
|
||||
* [BREAKING] Reversed the priority of layers for calculating label placement:
|
||||
labels for layers that appear later in the style now have priority over earlier
|
||||
layers.
|
||||
* Added a new `image` source type.
|
||||
* Added a new `circle` layer type.
|
||||
* Default map center location can now be set in the style.
|
||||
* Added `mapbox://` sprite URLs `mapbox://sprite/{user | "mapbox"}/{id}`
|
||||
|
||||
## 7.5.0
|
||||
|
||||
* Added gl-style-composite script, for auto-compositing sources in a style.
|
||||
|
||||
## 7.4.1
|
||||
|
||||
* Use JSON.stringify for formatting instead of js-beautify
|
||||
|
||||
## 7.0.0
|
||||
|
||||
Introduction of Mapbox GL style specification v7.
|
||||
|
||||
* [BREAKING] Improve dashed lines (#234)
|
||||
* [BREAKING] Remove prerendered layers (#232)
|
||||
* Explicit visibility property (#212)
|
||||
* Functions for all properties (#237)
|
||||
|
||||
## 6.0.0 (Style spec v6)
|
||||
|
||||
Introduction of Mapbox GL style specification v6.
|
||||
|
||||
* [BREAKING] New filter syntax (#178)
|
||||
* [BREAKING] Line gap property (#131)
|
||||
* [BREAKING] Remove dashes from min/max-zoom (#175)
|
||||
* [BREAKING] New layout/paint terminology (#166)
|
||||
* [BREAKING] Single text positioning property (#197)
|
||||
* Added requirements (#200)
|
||||
* Added minimum, maximum, and period values (#198)
|
||||
|
||||
## 0.0.5 (in progress)
|
||||
|
||||
* [BREAKING] Switch to suffix for transition properties (`transition-*` -> `*-transition`).
|
||||
* Added support for remote, non-Mapbox TileJSON sources.
|
||||
* [BREAKING] Source `minZoom` and `maxZoom` renamed to `minzoom` and `maxzoom to match TileJSON.
|
||||
* Added support for `mapbox://` glyph URLs.
|
||||
* [BREAKING] Renamed `raster-fade` to `raster-fade-duration`.
|
||||
* Added background-opacity property.
|
||||
* Added "tokens" property to string values that can autocomplete fields from layers
|
||||
* Added "units" property to describe value types
|
||||
|
||||
## 0.0.4 (Aug 8 2014)
|
||||
|
||||
* Initial public release
|
||||
59
node_modules/@mapbox/mapbox-gl-style-spec/README.md
generated
vendored
Normal file
59
node_modules/@mapbox/mapbox-gl-style-spec/README.md
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
# Mapbox GL style specification & utilities
|
||||
|
||||
This directory contains code and reference files that define the Mapbox GL style specification and provides some utilities for working with Mapbox styles.
|
||||
|
||||
## npm package
|
||||
|
||||
The Mapbox GL style specification and utilities are published as a seperate npm
|
||||
package so that they can be installed without the bulk of GL JS.
|
||||
|
||||
npm install @mapbox/mapbox-gl-style-spec
|
||||
|
||||
## CLI Tools
|
||||
|
||||
If you install this package globally, you will have access to several CLI tools.
|
||||
|
||||
npm install @mapbox/mapbox-gl-style-spec --global
|
||||
|
||||
|
||||
### `gl-style-composite`
|
||||
```bash
|
||||
$ gl-style-composite style.json
|
||||
```
|
||||
|
||||
Will take a non-composited style and produce a [composite style](https://www.mapbox.com/blog/better-label-placement-in-mapbox-studio/).
|
||||
|
||||
### `gl-style-migrate`
|
||||
|
||||
This repo contains scripts for migrating GL styles of any version to the latest version
|
||||
(currently v8). Migrate a style like this:
|
||||
|
||||
```bash
|
||||
$ gl-style-migrate bright-v7.json > bright-v8.json
|
||||
```
|
||||
|
||||
To migrate a file in place, you can use the `sponge` utility from the `moreutils` package:
|
||||
|
||||
```bash
|
||||
$ brew install moreutils
|
||||
$ gl-style-migrate bright.json | sponge bright.json
|
||||
```
|
||||
|
||||
### `gl-style-format`
|
||||
|
||||
```bash
|
||||
$ gl-style-format style.json
|
||||
```
|
||||
|
||||
Will format the given style JSON to use standard indentation and sorted object keys.
|
||||
|
||||
### `gl-style-validate`
|
||||
|
||||
```bash
|
||||
$ gl-style-validate style.json
|
||||
```
|
||||
|
||||
Will validate the given style JSON and print errors to stdout. Provide a
|
||||
`--json` flag to get JSON output.
|
||||
|
||||
To validate that a style can be uploaded to the Mapbox Styles API, use the `--mapbox-api-supported` flag.
|
||||
25
node_modules/@mapbox/mapbox-gl-style-spec/bin/gl-style-composite.js
generated
vendored
Executable file
25
node_modules/@mapbox/mapbox-gl-style-spec/bin/gl-style-composite.js
generated
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// @flow
|
||||
/* eslint-disable no-process-exit */
|
||||
|
||||
import fs from 'fs';
|
||||
import minimist from 'minimist';
|
||||
|
||||
/* eslint import/no-unresolved: [error, { ignore: ['^@mapbox/mapbox-gl-style-spec$'] }] */
|
||||
/* $FlowFixMe[cannot-resolve-module] */
|
||||
import {format, composite} from '@mapbox/mapbox-gl-style-spec';
|
||||
|
||||
const argv = minimist(process.argv.slice(2));
|
||||
|
||||
if (argv.help || argv.h || (!argv._.length && process.stdin.isTTY)) {
|
||||
help();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log(format(composite(JSON.parse(fs.readFileSync(argv._[0]).toString()))));
|
||||
|
||||
function help() {
|
||||
console.log('usage:');
|
||||
console.log(' gl-style-composite style.json');
|
||||
}
|
||||
30
node_modules/@mapbox/mapbox-gl-style-spec/bin/gl-style-format.js
generated
vendored
Executable file
30
node_modules/@mapbox/mapbox-gl-style-spec/bin/gl-style-format.js
generated
vendored
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// @flow
|
||||
/* eslint-disable no-process-exit */
|
||||
|
||||
import fs from 'fs';
|
||||
import minimist from 'minimist';
|
||||
|
||||
/* eslint import/no-unresolved: [error, { ignore: ['^@mapbox/mapbox-gl-style-spec$'] }] */
|
||||
/* $FlowFixMe[cannot-resolve-module] */
|
||||
import {format} from '@mapbox/mapbox-gl-style-spec';
|
||||
|
||||
const argv = minimist(process.argv.slice(2));
|
||||
|
||||
if (argv.help || argv.h || (!argv._.length && process.stdin.isTTY)) {
|
||||
help();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log(format(JSON.parse(fs.readFileSync(argv._[0]).toString()), argv.space));
|
||||
|
||||
function help() {
|
||||
console.log('usage:');
|
||||
console.log(' gl-style-format source.json > destination.json');
|
||||
console.log('');
|
||||
console.log('options:');
|
||||
console.log(' --space <num>');
|
||||
console.log(' Number of spaces in output (default "2")');
|
||||
console.log(' Pass "0" for minified output.');
|
||||
}
|
||||
25
node_modules/@mapbox/mapbox-gl-style-spec/bin/gl-style-migrate.js
generated
vendored
Executable file
25
node_modules/@mapbox/mapbox-gl-style-spec/bin/gl-style-migrate.js
generated
vendored
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// @flow
|
||||
/* eslint-disable no-process-exit */
|
||||
|
||||
import fs from 'fs';
|
||||
import minimist from 'minimist';
|
||||
|
||||
/* eslint import/no-unresolved: [error, { ignore: ['^@mapbox/mapbox-gl-style-spec$'] }] */
|
||||
/* $FlowFixMe[cannot-resolve-module] */
|
||||
import {format, migrate} from '@mapbox/mapbox-gl-style-spec';
|
||||
|
||||
const argv = minimist(process.argv.slice(2));
|
||||
|
||||
if (argv.help || argv.h || (!argv._.length && process.stdin.isTTY)) {
|
||||
help();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log(format(migrate(JSON.parse(fs.readFileSync(argv._[0]).toString()))));
|
||||
|
||||
function help() {
|
||||
console.log('usage:');
|
||||
console.log(' gl-style-migrate source.json > destination.json');
|
||||
}
|
||||
57
node_modules/@mapbox/mapbox-gl-style-spec/bin/gl-style-validate.js
generated
vendored
Executable file
57
node_modules/@mapbox/mapbox-gl-style-spec/bin/gl-style-validate.js
generated
vendored
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// @flow
|
||||
/* eslint-disable no-process-exit */
|
||||
|
||||
import rw from 'rw';
|
||||
import minimist from 'minimist';
|
||||
|
||||
/* eslint import/no-unresolved: [error, { ignore: ['^@mapbox/mapbox-gl-style-spec$'] }] */
|
||||
/* $FlowFixMe[cannot-resolve-module] */
|
||||
import {validate, validateMapboxApiSupported} from '@mapbox/mapbox-gl-style-spec';
|
||||
|
||||
const argv = minimist(process.argv.slice(2), {
|
||||
boolean: ['json', 'mapbox-api-supported'],
|
||||
});
|
||||
|
||||
let status = 0;
|
||||
|
||||
if (argv.help || argv.h || (!argv._.length && process.stdin.isTTY)) {
|
||||
help();
|
||||
process.exit(status);
|
||||
}
|
||||
|
||||
if (!argv._.length) {
|
||||
argv._.push('/dev/stdin');
|
||||
}
|
||||
|
||||
argv._.forEach((file) => {
|
||||
let errors = [];
|
||||
if (argv['mapbox-api-supported']) {
|
||||
errors = validateMapboxApiSupported(rw.readFileSync(file, 'utf8'));
|
||||
} else {
|
||||
errors = validate(rw.readFileSync(file, 'utf8'));
|
||||
}
|
||||
if (errors.length) {
|
||||
if (argv.json) {
|
||||
process.stdout.write(JSON.stringify(errors, null, 2));
|
||||
} else {
|
||||
errors.forEach((e) => {
|
||||
console.log('%s:%d: %s', file, e.line, e.message);
|
||||
});
|
||||
}
|
||||
status = 1;
|
||||
}
|
||||
});
|
||||
|
||||
process.exit(status);
|
||||
|
||||
function help() {
|
||||
console.log('usage:');
|
||||
console.log(' gl-style-validate file.json');
|
||||
console.log(' gl-style-validate < file.json');
|
||||
console.log('');
|
||||
console.log('options:');
|
||||
console.log('--json output errors as json');
|
||||
console.log('--mapbox-api-supported validate compatibility with Mapbox Styles API');
|
||||
}
|
||||
0
node_modules/@mapbox/mapbox-gl-style-spec/build/.gitkeep
generated
vendored
Normal file
0
node_modules/@mapbox/mapbox-gl-style-spec/build/.gitkeep
generated
vendored
Normal file
50
node_modules/@mapbox/mapbox-gl-style-spec/composite.js
generated
vendored
Normal file
50
node_modules/@mapbox/mapbox-gl-style-spec/composite.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
export default function (style) {
|
||||
const styleIDs = [];
|
||||
const sourceIDs = [];
|
||||
const compositedSourceLayers = [];
|
||||
|
||||
for (const id in style.sources) {
|
||||
const source = style.sources[id];
|
||||
|
||||
if (source.type !== "vector")
|
||||
continue;
|
||||
|
||||
const match = /^mapbox:\/\/(.*)/.exec(source.url);
|
||||
if (!match)
|
||||
continue;
|
||||
|
||||
styleIDs.push(id);
|
||||
sourceIDs.push(match[1]);
|
||||
}
|
||||
|
||||
if (styleIDs.length < 2)
|
||||
return style;
|
||||
|
||||
styleIDs.forEach((id) => {
|
||||
delete style.sources[id];
|
||||
});
|
||||
|
||||
const compositeID = sourceIDs.join(",");
|
||||
|
||||
style.sources[compositeID] = {
|
||||
"type": "vector",
|
||||
"url": `mapbox://${compositeID}`
|
||||
};
|
||||
|
||||
style.layers.forEach((layer) => {
|
||||
if (styleIDs.indexOf(layer.source) >= 0) {
|
||||
layer.source = compositeID;
|
||||
|
||||
if ('source-layer' in layer) {
|
||||
if (compositedSourceLayers.indexOf(layer['source-layer']) >= 0) {
|
||||
throw new Error('Conflicting source layer names');
|
||||
} else {
|
||||
compositedSourceLayers.push(layer['source-layer']);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return style;
|
||||
}
|
||||
53
node_modules/@mapbox/mapbox-gl-style-spec/deref.js
generated
vendored
Normal file
53
node_modules/@mapbox/mapbox-gl-style-spec/deref.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// @flow
|
||||
|
||||
import refProperties from './util/ref_properties.js';
|
||||
|
||||
import type {LayerSpecification} from './types.js';
|
||||
|
||||
function deref(layer: LayerSpecification, parent: LayerSpecification): LayerSpecification {
|
||||
const result = {};
|
||||
|
||||
for (const k in layer) {
|
||||
if (k !== 'ref') {
|
||||
result[k] = layer[k];
|
||||
}
|
||||
}
|
||||
|
||||
refProperties.forEach((k) => {
|
||||
if (k in parent) {
|
||||
result[k] = (parent: any)[k];
|
||||
}
|
||||
});
|
||||
|
||||
return ((result: any): LayerSpecification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of layers, some of which may contain `ref` properties
|
||||
* whose value is the `id` of another property, return a new array where
|
||||
* such layers have been augmented with the 'type', 'source', etc. properties
|
||||
* from the parent layer, and the `ref` property has been removed.
|
||||
*
|
||||
* The input is not modified. The output may contain references to portions
|
||||
* of the input.
|
||||
*
|
||||
* @private
|
||||
* @param {Array<Layer>} layers
|
||||
* @returns {Array<Layer>}
|
||||
*/
|
||||
export default function derefLayers(layers: Array<LayerSpecification>): Array<LayerSpecification> {
|
||||
layers = layers.slice();
|
||||
|
||||
const map = Object.create(null);
|
||||
for (let i = 0; i < layers.length; i++) {
|
||||
map[layers[i].id] = layers[i];
|
||||
}
|
||||
|
||||
for (let i = 0; i < layers.length; i++) {
|
||||
if ('ref' in layers[i]) {
|
||||
layers[i] = deref(layers[i], map[(layers[i]: any).ref]);
|
||||
}
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
434
node_modules/@mapbox/mapbox-gl-style-spec/diff.js
generated
vendored
Normal file
434
node_modules/@mapbox/mapbox-gl-style-spec/diff.js
generated
vendored
Normal file
@@ -0,0 +1,434 @@
|
||||
// @flow
|
||||
|
||||
import isEqual from './util/deep_equal.js';
|
||||
|
||||
import type {StyleSpecification} from './types.js';
|
||||
|
||||
type Command = {
|
||||
command: string;
|
||||
args: Array<any>;
|
||||
};
|
||||
|
||||
export const operations: {[_: string]: string} = {
|
||||
|
||||
/*
|
||||
* { command: 'setStyle', args: [stylesheet] }
|
||||
*/
|
||||
setStyle: 'setStyle',
|
||||
|
||||
/*
|
||||
* { command: 'addLayer', args: [layer, 'beforeLayerId'] }
|
||||
*/
|
||||
addLayer: 'addLayer',
|
||||
|
||||
/*
|
||||
* { command: 'removeLayer', args: ['layerId'] }
|
||||
*/
|
||||
removeLayer: 'removeLayer',
|
||||
|
||||
/*
|
||||
* { command: 'setPaintProperty', args: ['layerId', 'prop', value] }
|
||||
*/
|
||||
setPaintProperty: 'setPaintProperty',
|
||||
|
||||
/*
|
||||
* { command: 'setLayoutProperty', args: ['layerId', 'prop', value] }
|
||||
*/
|
||||
setLayoutProperty: 'setLayoutProperty',
|
||||
|
||||
/*
|
||||
* { command: 'setFilter', args: ['layerId', filter] }
|
||||
*/
|
||||
setFilter: 'setFilter',
|
||||
|
||||
/*
|
||||
* { command: 'addSource', args: ['sourceId', source] }
|
||||
*/
|
||||
addSource: 'addSource',
|
||||
|
||||
/*
|
||||
* { command: 'removeSource', args: ['sourceId'] }
|
||||
*/
|
||||
removeSource: 'removeSource',
|
||||
|
||||
/*
|
||||
* { command: 'setGeoJSONSourceData', args: ['sourceId', data] }
|
||||
*/
|
||||
setGeoJSONSourceData: 'setGeoJSONSourceData',
|
||||
|
||||
/*
|
||||
* { command: 'setLayerZoomRange', args: ['layerId', 0, 22] }
|
||||
*/
|
||||
setLayerZoomRange: 'setLayerZoomRange',
|
||||
|
||||
/*
|
||||
* { command: 'setLayerProperty', args: ['layerId', 'prop', value] }
|
||||
*/
|
||||
setLayerProperty: 'setLayerProperty',
|
||||
|
||||
/*
|
||||
* { command: 'setCenter', args: [[lon, lat]] }
|
||||
*/
|
||||
setCenter: 'setCenter',
|
||||
|
||||
/*
|
||||
* { command: 'setZoom', args: [zoom] }
|
||||
*/
|
||||
setZoom: 'setZoom',
|
||||
|
||||
/*
|
||||
* { command: 'setBearing', args: [bearing] }
|
||||
*/
|
||||
setBearing: 'setBearing',
|
||||
|
||||
/*
|
||||
* { command: 'setPitch', args: [pitch] }
|
||||
*/
|
||||
setPitch: 'setPitch',
|
||||
|
||||
/*
|
||||
* { command: 'setSprite', args: ['spriteUrl'] }
|
||||
*/
|
||||
setSprite: 'setSprite',
|
||||
|
||||
/*
|
||||
* { command: 'setGlyphs', args: ['glyphsUrl'] }
|
||||
*/
|
||||
setGlyphs: 'setGlyphs',
|
||||
|
||||
/*
|
||||
* { command: 'setTransition', args: [transition] }
|
||||
*/
|
||||
setTransition: 'setTransition',
|
||||
|
||||
/*
|
||||
* { command: 'setLighting', args: [lightProperties] }
|
||||
*/
|
||||
setLight: 'setLight',
|
||||
|
||||
/*
|
||||
* { command: 'setTerrain', args: [terrainProperties] }
|
||||
*/
|
||||
setTerrain: 'setTerrain',
|
||||
|
||||
/*
|
||||
* { command: 'setFog', args: [fogProperties] }
|
||||
*/
|
||||
setFog: 'setFog',
|
||||
|
||||
/*
|
||||
* { command: 'setProjection', args: [projectionProperties] }
|
||||
*/
|
||||
setProjection: 'setProjection'
|
||||
};
|
||||
|
||||
function addSource(sourceId, after, commands) {
|
||||
commands.push({command: operations.addSource, args: [sourceId, after[sourceId]]});
|
||||
}
|
||||
|
||||
function removeSource(sourceId, commands, sourcesRemoved) {
|
||||
commands.push({command: operations.removeSource, args: [sourceId]});
|
||||
sourcesRemoved[sourceId] = true;
|
||||
}
|
||||
|
||||
function updateSource(sourceId, after, commands, sourcesRemoved) {
|
||||
removeSource(sourceId, commands, sourcesRemoved);
|
||||
addSource(sourceId, after, commands);
|
||||
}
|
||||
|
||||
function canUpdateGeoJSON(before, after, sourceId) {
|
||||
let prop;
|
||||
for (prop in before[sourceId]) {
|
||||
if (!before[sourceId].hasOwnProperty(prop)) continue;
|
||||
if (prop !== 'data' && !isEqual(before[sourceId][prop], after[sourceId][prop])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (prop in after[sourceId]) {
|
||||
if (!after[sourceId].hasOwnProperty(prop)) continue;
|
||||
if (prop !== 'data' && !isEqual(before[sourceId][prop], after[sourceId][prop])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function diffSources(before, after, commands, sourcesRemoved) {
|
||||
before = before || {};
|
||||
after = after || {};
|
||||
|
||||
let sourceId;
|
||||
|
||||
// look for sources to remove
|
||||
for (sourceId in before) {
|
||||
if (!before.hasOwnProperty(sourceId)) continue;
|
||||
if (!after.hasOwnProperty(sourceId)) {
|
||||
removeSource(sourceId, commands, sourcesRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
// look for sources to add/update
|
||||
for (sourceId in after) {
|
||||
if (!after.hasOwnProperty(sourceId)) continue;
|
||||
if (!before.hasOwnProperty(sourceId)) {
|
||||
addSource(sourceId, after, commands);
|
||||
} else if (!isEqual(before[sourceId], after[sourceId])) {
|
||||
if (before[sourceId].type === 'geojson' && after[sourceId].type === 'geojson' && canUpdateGeoJSON(before, after, sourceId)) {
|
||||
commands.push({command: operations.setGeoJSONSourceData, args: [sourceId, after[sourceId].data]});
|
||||
} else {
|
||||
// no update command, must remove then add
|
||||
updateSource(sourceId, after, commands, sourcesRemoved);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function diffLayerPropertyChanges(before, after, commands, layerId, klass, command) {
|
||||
before = before || {};
|
||||
after = after || {};
|
||||
|
||||
let prop;
|
||||
|
||||
for (prop in before) {
|
||||
if (!before.hasOwnProperty(prop)) continue;
|
||||
if (!isEqual(before[prop], after[prop])) {
|
||||
commands.push({command, args: [layerId, prop, after[prop], klass]});
|
||||
}
|
||||
}
|
||||
for (prop in after) {
|
||||
if (!after.hasOwnProperty(prop) || before.hasOwnProperty(prop)) continue;
|
||||
if (!isEqual(before[prop], after[prop])) {
|
||||
commands.push({command, args: [layerId, prop, after[prop], klass]});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pluckId(layer) {
|
||||
return layer.id;
|
||||
}
|
||||
function indexById(group, layer) {
|
||||
group[layer.id] = layer;
|
||||
return group;
|
||||
}
|
||||
|
||||
function diffLayers(before, after, commands) {
|
||||
before = before || [];
|
||||
after = after || [];
|
||||
|
||||
// order of layers by id
|
||||
const beforeOrder = before.map(pluckId);
|
||||
const afterOrder = after.map(pluckId);
|
||||
|
||||
// index of layer by id
|
||||
const beforeIndex = before.reduce(indexById, {});
|
||||
const afterIndex = after.reduce(indexById, {});
|
||||
|
||||
// track order of layers as if they have been mutated
|
||||
const tracker = beforeOrder.slice();
|
||||
|
||||
// layers that have been added do not need to be diffed
|
||||
const clean = Object.create(null);
|
||||
|
||||
let i, d, layerId, beforeLayer, afterLayer, insertBeforeLayerId, prop;
|
||||
|
||||
// remove layers
|
||||
for (i = 0, d = 0; i < beforeOrder.length; i++) {
|
||||
layerId = beforeOrder[i];
|
||||
if (!afterIndex.hasOwnProperty(layerId)) {
|
||||
commands.push({command: operations.removeLayer, args: [layerId]});
|
||||
tracker.splice(tracker.indexOf(layerId, d), 1);
|
||||
} else {
|
||||
// limit where in tracker we need to look for a match
|
||||
d++;
|
||||
}
|
||||
}
|
||||
|
||||
// add/reorder layers
|
||||
for (i = 0, d = 0; i < afterOrder.length; i++) {
|
||||
// work backwards as insert is before an existing layer
|
||||
layerId = afterOrder[afterOrder.length - 1 - i];
|
||||
|
||||
if (tracker[tracker.length - 1 - i] === layerId) continue;
|
||||
|
||||
if (beforeIndex.hasOwnProperty(layerId)) {
|
||||
// remove the layer before we insert at the correct position
|
||||
commands.push({command: operations.removeLayer, args: [layerId]});
|
||||
tracker.splice(tracker.lastIndexOf(layerId, tracker.length - d), 1);
|
||||
} else {
|
||||
// limit where in tracker we need to look for a match
|
||||
d++;
|
||||
}
|
||||
|
||||
// add layer at correct position
|
||||
insertBeforeLayerId = tracker[tracker.length - i];
|
||||
commands.push({command: operations.addLayer, args: [afterIndex[layerId], insertBeforeLayerId]});
|
||||
tracker.splice(tracker.length - i, 0, layerId);
|
||||
clean[layerId] = true;
|
||||
}
|
||||
|
||||
// update layers
|
||||
for (i = 0; i < afterOrder.length; i++) {
|
||||
layerId = afterOrder[i];
|
||||
beforeLayer = beforeIndex[layerId];
|
||||
afterLayer = afterIndex[layerId];
|
||||
|
||||
// no need to update if previously added (new or moved)
|
||||
if (clean[layerId] || isEqual(beforeLayer, afterLayer)) continue;
|
||||
|
||||
// If source, source-layer, or type have changes, then remove the layer
|
||||
// and add it back 'from scratch'.
|
||||
if (!isEqual(beforeLayer.source, afterLayer.source) || !isEqual(beforeLayer['source-layer'], afterLayer['source-layer']) || !isEqual(beforeLayer.type, afterLayer.type)) {
|
||||
commands.push({command: operations.removeLayer, args: [layerId]});
|
||||
// we add the layer back at the same position it was already in, so
|
||||
// there's no need to update the `tracker`
|
||||
insertBeforeLayerId = tracker[tracker.lastIndexOf(layerId) + 1];
|
||||
commands.push({command: operations.addLayer, args: [afterLayer, insertBeforeLayerId]});
|
||||
continue;
|
||||
}
|
||||
|
||||
// layout, paint, filter, minzoom, maxzoom
|
||||
diffLayerPropertyChanges(beforeLayer.layout, afterLayer.layout, commands, layerId, null, operations.setLayoutProperty);
|
||||
diffLayerPropertyChanges(beforeLayer.paint, afterLayer.paint, commands, layerId, null, operations.setPaintProperty);
|
||||
if (!isEqual(beforeLayer.filter, afterLayer.filter)) {
|
||||
commands.push({command: operations.setFilter, args: [layerId, afterLayer.filter]});
|
||||
}
|
||||
if (!isEqual(beforeLayer.minzoom, afterLayer.minzoom) || !isEqual(beforeLayer.maxzoom, afterLayer.maxzoom)) {
|
||||
commands.push({command: operations.setLayerZoomRange, args: [layerId, afterLayer.minzoom, afterLayer.maxzoom]});
|
||||
}
|
||||
|
||||
// handle all other layer props, including paint.*
|
||||
for (prop in beforeLayer) {
|
||||
if (!beforeLayer.hasOwnProperty(prop)) continue;
|
||||
if (prop === 'layout' || prop === 'paint' || prop === 'filter' ||
|
||||
prop === 'metadata' || prop === 'minzoom' || prop === 'maxzoom') continue;
|
||||
if (prop.indexOf('paint.') === 0) {
|
||||
diffLayerPropertyChanges(beforeLayer[prop], afterLayer[prop], commands, layerId, prop.slice(6), operations.setPaintProperty);
|
||||
} else if (!isEqual(beforeLayer[prop], afterLayer[prop])) {
|
||||
commands.push({command: operations.setLayerProperty, args: [layerId, prop, afterLayer[prop]]});
|
||||
}
|
||||
}
|
||||
for (prop in afterLayer) {
|
||||
if (!afterLayer.hasOwnProperty(prop) || beforeLayer.hasOwnProperty(prop)) continue;
|
||||
if (prop === 'layout' || prop === 'paint' || prop === 'filter' ||
|
||||
prop === 'metadata' || prop === 'minzoom' || prop === 'maxzoom') continue;
|
||||
if (prop.indexOf('paint.') === 0) {
|
||||
diffLayerPropertyChanges(beforeLayer[prop], afterLayer[prop], commands, layerId, prop.slice(6), operations.setPaintProperty);
|
||||
} else if (!isEqual(beforeLayer[prop], afterLayer[prop])) {
|
||||
commands.push({command: operations.setLayerProperty, args: [layerId, prop, afterLayer[prop]]});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diff two stylesheet
|
||||
*
|
||||
* Creates semanticly aware diffs that can easily be applied at runtime.
|
||||
* Operations produced by the diff closely resemble the mapbox-gl-js API. Any
|
||||
* error creating the diff will fall back to the 'setStyle' operation.
|
||||
*
|
||||
* Example diff:
|
||||
* [
|
||||
* { command: 'setConstant', args: ['@water', '#0000FF'] },
|
||||
* { command: 'setPaintProperty', args: ['background', 'background-color', 'black'] }
|
||||
* ]
|
||||
*
|
||||
* @private
|
||||
* @param {*} [before] stylesheet to compare from
|
||||
* @param {*} after stylesheet to compare to
|
||||
* @returns Array list of changes
|
||||
*/
|
||||
export default function diffStyles(before: StyleSpecification, after: StyleSpecification): Array<Command> {
|
||||
if (!before) return [{command: operations.setStyle, args: [after]}];
|
||||
|
||||
let commands = [];
|
||||
|
||||
try {
|
||||
// Handle changes to top-level properties
|
||||
if (!isEqual(before.version, after.version)) {
|
||||
return [{command: operations.setStyle, args: [after]}];
|
||||
}
|
||||
if (!isEqual(before.center, after.center)) {
|
||||
commands.push({command: operations.setCenter, args: [after.center]});
|
||||
}
|
||||
if (!isEqual(before.zoom, after.zoom)) {
|
||||
commands.push({command: operations.setZoom, args: [after.zoom]});
|
||||
}
|
||||
if (!isEqual(before.bearing, after.bearing)) {
|
||||
commands.push({command: operations.setBearing, args: [after.bearing]});
|
||||
}
|
||||
if (!isEqual(before.pitch, after.pitch)) {
|
||||
commands.push({command: operations.setPitch, args: [after.pitch]});
|
||||
}
|
||||
if (!isEqual(before.sprite, after.sprite)) {
|
||||
commands.push({command: operations.setSprite, args: [after.sprite]});
|
||||
}
|
||||
if (!isEqual(before.glyphs, after.glyphs)) {
|
||||
commands.push({command: operations.setGlyphs, args: [after.glyphs]});
|
||||
}
|
||||
if (!isEqual(before.transition, after.transition)) {
|
||||
commands.push({command: operations.setTransition, args: [after.transition]});
|
||||
}
|
||||
if (!isEqual(before.light, after.light)) {
|
||||
commands.push({command: operations.setLight, args: [after.light]});
|
||||
}
|
||||
if (!isEqual(before.fog, after.fog)) {
|
||||
commands.push({command: operations.setFog, args: [after.fog]});
|
||||
}
|
||||
if (!isEqual(before.projection, after.projection)) {
|
||||
commands.push({command: operations.setProjection, args: [after.projection]});
|
||||
}
|
||||
|
||||
// Handle changes to `sources`
|
||||
// If a source is to be removed, we also--before the removeSource
|
||||
// command--need to remove all the style layers that depend on it.
|
||||
const sourcesRemoved = {};
|
||||
|
||||
// First collect the {add,remove}Source commands
|
||||
const removeOrAddSourceCommands = [];
|
||||
diffSources(before.sources, after.sources, removeOrAddSourceCommands, sourcesRemoved);
|
||||
|
||||
// Push a removeLayer command for each style layer that depends on a
|
||||
// source that's being removed.
|
||||
// Also, exclude any such layers them from the input to `diffLayers`
|
||||
// below, so that diffLayers produces the appropriate `addLayers`
|
||||
// command
|
||||
const beforeLayers = [];
|
||||
if (before.layers) {
|
||||
before.layers.forEach((layer) => {
|
||||
if (layer.source && sourcesRemoved[layer.source]) {
|
||||
commands.push({command: operations.removeLayer, args: [layer.id]});
|
||||
} else {
|
||||
beforeLayers.push(layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Remove the terrain if the source for that terrain is being removed
|
||||
let beforeTerrain = before.terrain;
|
||||
if (beforeTerrain) {
|
||||
if (sourcesRemoved[beforeTerrain.source]) {
|
||||
commands.push({command: operations.setTerrain, args: [undefined]});
|
||||
beforeTerrain = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
commands = commands.concat(removeOrAddSourceCommands);
|
||||
|
||||
// Even though terrain is a top-level property
|
||||
// Its like a layer in the sense that it depends on a source being present.
|
||||
if (!isEqual(beforeTerrain, after.terrain)) {
|
||||
commands.push({command: operations.setTerrain, args: [after.terrain]});
|
||||
}
|
||||
|
||||
// Handle changes to `layers`
|
||||
diffLayers(beforeLayers, after.layers, commands);
|
||||
|
||||
} catch (e) {
|
||||
// fall back to setStyle
|
||||
console.warn('Unable to compute style diff:', e);
|
||||
commands = [{command: operations.setStyle, args: [after]}];
|
||||
}
|
||||
|
||||
return commands;
|
||||
}
|
||||
0
node_modules/@mapbox/mapbox-gl-style-spec/dist/.gitkeep
generated
vendored
Normal file
0
node_modules/@mapbox/mapbox-gl-style-spec/dist/.gitkeep
generated
vendored
Normal file
17636
node_modules/@mapbox/mapbox-gl-style-spec/dist/index.cjs
generated
vendored
Normal file
17636
node_modules/@mapbox/mapbox-gl-style-spec/dist/index.cjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/@mapbox/mapbox-gl-style-spec/dist/index.cjs.map
generated
vendored
Normal file
1
node_modules/@mapbox/mapbox-gl-style-spec/dist/index.cjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
17610
node_modules/@mapbox/mapbox-gl-style-spec/dist/index.es.js
generated
vendored
Normal file
17610
node_modules/@mapbox/mapbox-gl-style-spec/dist/index.es.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/@mapbox/mapbox-gl-style-spec/dist/index.es.js.map
generated
vendored
Normal file
1
node_modules/@mapbox/mapbox-gl-style-spec/dist/index.es.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
10
node_modules/@mapbox/mapbox-gl-style-spec/empty.js
generated
vendored
Normal file
10
node_modules/@mapbox/mapbox-gl-style-spec/empty.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// @flow
|
||||
import type {StyleSpecification} from './types.js';
|
||||
|
||||
export default function emptyStyle(): StyleSpecification {
|
||||
return {
|
||||
version: 8,
|
||||
layers: [],
|
||||
sources: {}
|
||||
};
|
||||
}
|
||||
16
node_modules/@mapbox/mapbox-gl-style-spec/error/parsing_error.js
generated
vendored
Normal file
16
node_modules/@mapbox/mapbox-gl-style-spec/error/parsing_error.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// @flow
|
||||
|
||||
// Note: Do not inherit from Error. It breaks when transpiling to ES5.
|
||||
|
||||
export default class ParsingError {
|
||||
message: string;
|
||||
error: Error;
|
||||
line: number;
|
||||
|
||||
constructor(error: Error) {
|
||||
this.error = error;
|
||||
this.message = error.message;
|
||||
const match = error.message.match(/line (\d+)/);
|
||||
this.line = match ? parseInt(match[1], 10) : 0;
|
||||
}
|
||||
}
|
||||
18
node_modules/@mapbox/mapbox-gl-style-spec/error/validation_error.js
generated
vendored
Normal file
18
node_modules/@mapbox/mapbox-gl-style-spec/error/validation_error.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// @flow
|
||||
|
||||
// Note: Do not inherit from Error. It breaks when transpiling to ES5.
|
||||
|
||||
export default class ValidationError {
|
||||
message: string;
|
||||
identifier: ?string;
|
||||
line: ?number;
|
||||
|
||||
constructor(key: ?string, value: ?{ __line__: number }, message: string, identifier: ?string) {
|
||||
this.message = (key ? `${key}: ` : '') + message;
|
||||
if (identifier) this.identifier = identifier;
|
||||
|
||||
if (value !== null && value !== undefined && value.__line__) {
|
||||
this.line = value.__line__;
|
||||
}
|
||||
}
|
||||
}
|
||||
162
node_modules/@mapbox/mapbox-gl-style-spec/expression/compound_expression.js
generated
vendored
Normal file
162
node_modules/@mapbox/mapbox-gl-style-spec/expression/compound_expression.js
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// @flow
|
||||
|
||||
import {toString} from './types.js';
|
||||
|
||||
import ParsingContext from './parsing_context.js';
|
||||
import EvaluationContext from './evaluation_context.js';
|
||||
import assert from 'assert';
|
||||
|
||||
import type {Expression, ExpressionRegistry} from './expression.js';
|
||||
import type {Type} from './types.js';
|
||||
import type {Value} from './values.js';
|
||||
|
||||
export type Varargs = {| type: Type |};
|
||||
type Signature = Array<Type> | Varargs;
|
||||
type Evaluate = (EvaluationContext, Array<Expression>) => Value;
|
||||
type Definition = [Type, Signature, Evaluate] |
|
||||
{|type: Type, overloads: Array<[Signature, Evaluate]>|};
|
||||
|
||||
class CompoundExpression implements Expression {
|
||||
name: string;
|
||||
type: Type;
|
||||
_evaluate: Evaluate;
|
||||
args: Array<Expression>;
|
||||
|
||||
static definitions: {[_: string]: Definition };
|
||||
|
||||
constructor(name: string, type: Type, evaluate: Evaluate, args: Array<Expression>) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this._evaluate = evaluate;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): Value {
|
||||
return this._evaluate(ctx, this.args);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
this.args.forEach(fn);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): Array<mixed> {
|
||||
return [this.name].concat(this.args.map(arg => arg.serialize()));
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Expression {
|
||||
const op: string = (args[0]: any);
|
||||
const definition = CompoundExpression.definitions[op];
|
||||
if (!definition) {
|
||||
return context.error(`Unknown expression "${op}". If you wanted a literal array, use ["literal", [...]].`, 0);
|
||||
}
|
||||
|
||||
// Now check argument types against each signature
|
||||
const type = Array.isArray(definition) ?
|
||||
definition[0] : definition.type;
|
||||
|
||||
const availableOverloads = Array.isArray(definition) ?
|
||||
[[definition[1], definition[2]]] :
|
||||
definition.overloads;
|
||||
|
||||
const overloads = availableOverloads.filter(([signature]) => (
|
||||
!Array.isArray(signature) || // varags
|
||||
signature.length === args.length - 1 // correct param count
|
||||
));
|
||||
|
||||
let signatureContext: ParsingContext = (null: any);
|
||||
|
||||
for (const [params, evaluate] of overloads) {
|
||||
// Use a fresh context for each attempted signature so that, if
|
||||
// we eventually succeed, we haven't polluted `context.errors`.
|
||||
signatureContext = new ParsingContext(context.registry, context.path, null, context.scope);
|
||||
|
||||
// First parse all the args, potentially coercing to the
|
||||
// types expected by this overload.
|
||||
const parsedArgs: Array<Expression> = [];
|
||||
let argParseFailed = false;
|
||||
for (let i = 1; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
const expectedType = Array.isArray(params) ?
|
||||
params[i - 1] :
|
||||
params.type;
|
||||
|
||||
const parsed = signatureContext.parse(arg, 1 + parsedArgs.length, expectedType);
|
||||
if (!parsed) {
|
||||
argParseFailed = true;
|
||||
break;
|
||||
}
|
||||
parsedArgs.push(parsed);
|
||||
}
|
||||
if (argParseFailed) {
|
||||
// Couldn't coerce args of this overload to expected type, move
|
||||
// on to next one.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Array.isArray(params)) {
|
||||
if (params.length !== parsedArgs.length) {
|
||||
signatureContext.error(`Expected ${params.length} arguments, but found ${parsedArgs.length} instead.`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < parsedArgs.length; i++) {
|
||||
const expected = Array.isArray(params) ? params[i] : params.type;
|
||||
const arg = parsedArgs[i];
|
||||
signatureContext.concat(i + 1).checkSubtype(expected, arg.type);
|
||||
}
|
||||
|
||||
if (signatureContext.errors.length === 0) {
|
||||
return new CompoundExpression(op, type, evaluate, parsedArgs);
|
||||
}
|
||||
}
|
||||
|
||||
assert(!signatureContext || signatureContext.errors.length > 0);
|
||||
|
||||
if (overloads.length === 1) {
|
||||
context.errors.push(...signatureContext.errors);
|
||||
} else {
|
||||
const expected = overloads.length ? overloads : availableOverloads;
|
||||
const signatures = expected
|
||||
.map(([params]) => stringifySignature(params))
|
||||
.join(' | ');
|
||||
|
||||
const actualTypes = [];
|
||||
// For error message, re-parse arguments without trying to
|
||||
// apply any coercions
|
||||
for (let i = 1; i < args.length; i++) {
|
||||
const parsed = context.parse(args[i], 1 + actualTypes.length);
|
||||
if (!parsed) return null;
|
||||
actualTypes.push(toString(parsed.type));
|
||||
}
|
||||
context.error(`Expected arguments of type ${signatures}, but found (${actualTypes.join(', ')}) instead.`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static register(
|
||||
registry: ExpressionRegistry,
|
||||
definitions: {[_: string]: Definition }
|
||||
) {
|
||||
assert(!CompoundExpression.definitions);
|
||||
CompoundExpression.definitions = definitions;
|
||||
for (const name in definitions) {
|
||||
registry[name] = CompoundExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stringifySignature(signature: Signature): string {
|
||||
if (Array.isArray(signature)) {
|
||||
return `(${signature.map(toString).join(', ')})`;
|
||||
} else {
|
||||
return `(${toString(signature.type)}...)`;
|
||||
}
|
||||
}
|
||||
|
||||
export default CompoundExpression;
|
||||
130
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/assertion.js
generated
vendored
Normal file
130
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/assertion.js
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
// @flow
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import {
|
||||
ObjectType,
|
||||
ValueType,
|
||||
StringType,
|
||||
NumberType,
|
||||
BooleanType,
|
||||
checkSubtype,
|
||||
toString,
|
||||
array
|
||||
} from '../types.js';
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
import {typeOf} from '../values.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
const types = {
|
||||
string: StringType,
|
||||
number: NumberType,
|
||||
boolean: BooleanType,
|
||||
object: ObjectType
|
||||
};
|
||||
|
||||
class Assertion implements Expression {
|
||||
type: Type;
|
||||
args: Array<Expression>;
|
||||
|
||||
constructor(type: Type, args: Array<Expression>) {
|
||||
this.type = type;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Expression {
|
||||
if (args.length < 2)
|
||||
return context.error(`Expected at least one argument.`);
|
||||
|
||||
let i = 1;
|
||||
let type;
|
||||
|
||||
const name: string = (args[0]: any);
|
||||
if (name === 'array') {
|
||||
let itemType;
|
||||
if (args.length > 2) {
|
||||
const type = args[1];
|
||||
if (typeof type !== 'string' || !(type in types) || type === 'object')
|
||||
return context.error('The item type argument of "array" must be one of string, number, boolean', 1);
|
||||
itemType = types[type];
|
||||
i++;
|
||||
} else {
|
||||
itemType = ValueType;
|
||||
}
|
||||
|
||||
let N;
|
||||
if (args.length > 3) {
|
||||
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);
|
||||
}
|
||||
N = args[2];
|
||||
i++;
|
||||
}
|
||||
|
||||
type = array(itemType, N);
|
||||
} else {
|
||||
assert(types[name], name);
|
||||
type = types[name];
|
||||
}
|
||||
|
||||
const parsed = [];
|
||||
for (; i < args.length; i++) {
|
||||
const input = context.parse(args[i], i, ValueType);
|
||||
if (!input) return null;
|
||||
parsed.push(input);
|
||||
}
|
||||
|
||||
return new Assertion(type, parsed);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any | null {
|
||||
for (let i = 0; i < this.args.length; i++) {
|
||||
const value = this.args[i].evaluate(ctx);
|
||||
const error = checkSubtype(this.type, typeOf(value));
|
||||
if (!error) {
|
||||
return value;
|
||||
} else if (i === this.args.length - 1) {
|
||||
throw new RuntimeError(`Expected value to be of type ${toString(this.type)}, but found ${toString(typeOf(value))} instead.`);
|
||||
}
|
||||
}
|
||||
|
||||
assert(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
this.args.forEach(fn);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return this.args.every(arg => arg.outputDefined());
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const type = this.type;
|
||||
const serialized = [type.kind];
|
||||
if (type.kind === 'array') {
|
||||
const itemType = type.itemType;
|
||||
if (itemType.kind === 'string' ||
|
||||
itemType.kind === 'number' ||
|
||||
itemType.kind === 'boolean') {
|
||||
serialized.push(itemType.kind);
|
||||
const N = type.N;
|
||||
if (typeof N === 'number' || this.args.length > 1) {
|
||||
serialized.push(N);
|
||||
}
|
||||
}
|
||||
}
|
||||
return serialized.concat(this.args.map(arg => arg.serialize()));
|
||||
}
|
||||
}
|
||||
|
||||
export default Assertion;
|
||||
70
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/at.js
generated
vendored
Normal file
70
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/at.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
// @flow
|
||||
|
||||
import {array, ValueType, NumberType} from '../types.js';
|
||||
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type, ArrayType} from '../types.js';
|
||||
import type {Value} from '../values.js';
|
||||
|
||||
class At implements Expression {
|
||||
type: Type;
|
||||
index: Expression;
|
||||
input: Expression;
|
||||
|
||||
constructor(type: Type, index: Expression, input: Expression) {
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?At {
|
||||
if (args.length !== 3)
|
||||
return context.error(`Expected 2 arguments, but found ${args.length - 1} instead.`);
|
||||
|
||||
const index = context.parse(args[1], 1, NumberType);
|
||||
const input = context.parse(args[2], 2, array(context.expectedType || ValueType));
|
||||
|
||||
if (!index || !input) return null;
|
||||
|
||||
const t: ArrayType = (input.type: any);
|
||||
return new At(t.itemType, index, input);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): Value {
|
||||
const index = ((this.index.evaluate(ctx): any): number);
|
||||
const array = ((this.input.evaluate(ctx): any): Array<Value>);
|
||||
|
||||
if (index < 0) {
|
||||
throw new RuntimeError(`Array index out of bounds: ${index} < 0.`);
|
||||
}
|
||||
|
||||
if (index >= array.length) {
|
||||
throw new RuntimeError(`Array index out of bounds: ${index} > ${array.length - 1}.`);
|
||||
}
|
||||
|
||||
if (index !== Math.floor(index)) {
|
||||
throw new RuntimeError(`Array index must be an integer, but found ${index} instead.`);
|
||||
}
|
||||
|
||||
return array[index];
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.index);
|
||||
fn(this.input);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
return ["at", this.index.serialize(), this.input.serialize()];
|
||||
}
|
||||
}
|
||||
|
||||
export default At;
|
||||
85
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/case.js
generated
vendored
Normal file
85
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/case.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// @flow
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import {BooleanType} from '../types.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
type Branches = Array<[Expression, Expression]>;
|
||||
|
||||
class Case implements Expression {
|
||||
type: Type;
|
||||
|
||||
branches: Branches;
|
||||
otherwise: Expression;
|
||||
|
||||
constructor(type: Type, branches: Branches, otherwise: Expression) {
|
||||
this.type = type;
|
||||
this.branches = branches;
|
||||
this.otherwise = otherwise;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Case {
|
||||
if (args.length < 4)
|
||||
return context.error(`Expected at least 3 arguments, but found only ${args.length - 1}.`);
|
||||
if (args.length % 2 !== 0)
|
||||
return context.error(`Expected an odd number of arguments.`);
|
||||
|
||||
let outputType: ?Type;
|
||||
if (context.expectedType && context.expectedType.kind !== 'value') {
|
||||
outputType = context.expectedType;
|
||||
}
|
||||
|
||||
const branches = [];
|
||||
for (let i = 1; i < args.length - 1; i += 2) {
|
||||
const test = context.parse(args[i], i, BooleanType);
|
||||
if (!test) return null;
|
||||
|
||||
const result = context.parse(args[i + 1], i + 1, outputType);
|
||||
if (!result) return null;
|
||||
|
||||
branches.push([test, result]);
|
||||
|
||||
outputType = outputType || result.type;
|
||||
}
|
||||
|
||||
const otherwise = context.parse(args[args.length - 1], args.length - 1, outputType);
|
||||
if (!otherwise) return null;
|
||||
|
||||
assert(outputType);
|
||||
return new Case((outputType: any), branches, otherwise);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any {
|
||||
for (const [test, expression] of this.branches) {
|
||||
if (test.evaluate(ctx)) {
|
||||
return expression.evaluate(ctx);
|
||||
}
|
||||
}
|
||||
return this.otherwise.evaluate(ctx);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
for (const [test, expression] of this.branches) {
|
||||
fn(test);
|
||||
fn(expression);
|
||||
}
|
||||
fn(this.otherwise);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return this.branches.every(([_, out]) => out.outputDefined()) && this.otherwise.outputDefined();
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const serialized = ["case"];
|
||||
this.eachChild(child => { serialized.push(child.serialize()); });
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
export default Case;
|
||||
95
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/coalesce.js
generated
vendored
Normal file
95
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/coalesce.js
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
// @flow
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import {checkSubtype, ValueType} from '../types.js';
|
||||
import ResolvedImage from '../types/resolved_image.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
class Coalesce implements Expression {
|
||||
type: Type;
|
||||
args: Array<Expression>;
|
||||
|
||||
constructor(type: Type, args: Array<Expression>) {
|
||||
this.type = type;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Coalesce {
|
||||
if (args.length < 2) {
|
||||
return context.error("Expectected at least one argument.");
|
||||
}
|
||||
let outputType: Type = (null: any);
|
||||
const expectedType = context.expectedType;
|
||||
if (expectedType && expectedType.kind !== 'value') {
|
||||
outputType = expectedType;
|
||||
}
|
||||
const parsedArgs = [];
|
||||
|
||||
for (const arg of args.slice(1)) {
|
||||
const parsed = context.parse(arg, 1 + parsedArgs.length, outputType, undefined, {typeAnnotation: 'omit'});
|
||||
if (!parsed) return null;
|
||||
outputType = outputType || parsed.type;
|
||||
parsedArgs.push(parsed);
|
||||
}
|
||||
assert(outputType);
|
||||
|
||||
// Above, we parse arguments without inferred type annotation so that
|
||||
// they don't produce a runtime error for `null` input, which would
|
||||
// preempt the desired null-coalescing behavior.
|
||||
// Thus, if any of our arguments would have needed an annotation, we
|
||||
// need to wrap the enclosing coalesce expression with it instead.
|
||||
const needsAnnotation = expectedType &&
|
||||
parsedArgs.some(arg => checkSubtype(expectedType, arg.type));
|
||||
|
||||
return needsAnnotation ?
|
||||
new Coalesce(ValueType, parsedArgs) :
|
||||
new Coalesce((outputType: any), parsedArgs);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any | null {
|
||||
let result = null;
|
||||
let argCount = 0;
|
||||
let firstImage;
|
||||
for (const arg of this.args) {
|
||||
argCount++;
|
||||
result = arg.evaluate(ctx);
|
||||
// we need to keep track of the first requested image in a coalesce statement
|
||||
// if coalesce can't find a valid image, we return the first image so styleimagemissing can fire
|
||||
if (result && result instanceof ResolvedImage && !result.available) {
|
||||
// set to first image
|
||||
if (!firstImage) {
|
||||
firstImage = result;
|
||||
}
|
||||
result = null;
|
||||
// if we reach the end, return the first image
|
||||
if (argCount === this.args.length) {
|
||||
return firstImage;
|
||||
}
|
||||
}
|
||||
|
||||
if (result !== null) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
this.args.forEach(fn);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return this.args.every(arg => arg.outputDefined());
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const serialized = ["coalesce"];
|
||||
this.eachChild(child => { serialized.push(child.serialize()); });
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
export default Coalesce;
|
||||
133
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/coercion.js
generated
vendored
Normal file
133
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/coercion.js
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
// @flow
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import {BooleanType, ColorType, NumberType, StringType, ValueType} from '../types.js';
|
||||
import {Color, toString as valueToString, validateRGBA} from '../values.js';
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
import Formatted from '../types/formatted.js';
|
||||
import FormatExpression from '../definitions/format.js';
|
||||
import ImageExpression from '../definitions/image.js';
|
||||
import ResolvedImage from '../types/resolved_image.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
const types = {
|
||||
'to-boolean': BooleanType,
|
||||
'to-color': ColorType,
|
||||
'to-number': NumberType,
|
||||
'to-string': StringType
|
||||
};
|
||||
|
||||
/**
|
||||
* Special form for error-coalescing coercion expressions "to-number",
|
||||
* "to-color". Since these coercions can fail at runtime, they accept multiple
|
||||
* arguments, only evaluating one at a time until one succeeds.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
class Coercion implements Expression {
|
||||
type: Type;
|
||||
args: Array<Expression>;
|
||||
|
||||
constructor(type: Type, args: Array<Expression>) {
|
||||
this.type = type;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Expression {
|
||||
if (args.length < 2)
|
||||
return context.error(`Expected at least one argument.`);
|
||||
|
||||
const name: string = (args[0]: any);
|
||||
assert(types[name], name);
|
||||
|
||||
if ((name === 'to-boolean' || name === 'to-string') && args.length !== 2)
|
||||
return context.error(`Expected one argument.`);
|
||||
|
||||
const type = types[name];
|
||||
|
||||
const parsed = [];
|
||||
for (let i = 1; i < args.length; i++) {
|
||||
const input = context.parse(args[i], i, ValueType);
|
||||
if (!input) return null;
|
||||
parsed.push(input);
|
||||
}
|
||||
|
||||
return new Coercion(type, parsed);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): null | boolean | number | string | Color | Formatted | ResolvedImage {
|
||||
if (this.type.kind === 'boolean') {
|
||||
return Boolean(this.args[0].evaluate(ctx));
|
||||
} else if (this.type.kind === 'color') {
|
||||
let input;
|
||||
let error;
|
||||
for (const arg of this.args) {
|
||||
input = arg.evaluate(ctx);
|
||||
error = null;
|
||||
if (input instanceof Color) {
|
||||
return input;
|
||||
} else if (typeof input === 'string') {
|
||||
const c = ctx.parseColor(input);
|
||||
if (c) return c;
|
||||
} else if (Array.isArray(input)) {
|
||||
if (input.length < 3 || input.length > 4) {
|
||||
error = `Invalid rbga value ${JSON.stringify(input)}: expected an array containing either three or four numeric values.`;
|
||||
} else {
|
||||
error = validateRGBA(input[0], input[1], input[2], input[3]);
|
||||
}
|
||||
if (!error) {
|
||||
return new Color((input[0]: any) / 255, (input[1]: any) / 255, (input[2]: any) / 255, (input[3]: any));
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new RuntimeError(error || `Could not parse color from value '${typeof input === 'string' ? input : String(JSON.stringify(input))}'`);
|
||||
} else if (this.type.kind === 'number') {
|
||||
let value = null;
|
||||
for (const arg of this.args) {
|
||||
value = arg.evaluate(ctx);
|
||||
if (value === null) return 0;
|
||||
const num = Number(value);
|
||||
if (isNaN(num)) continue;
|
||||
return num;
|
||||
}
|
||||
throw new RuntimeError(`Could not convert ${JSON.stringify(value)} to number.`);
|
||||
} else if (this.type.kind === 'formatted') {
|
||||
// There is no explicit 'to-formatted' but this coercion can be implicitly
|
||||
// created by properties that expect the 'formatted' type.
|
||||
return Formatted.fromString(valueToString(this.args[0].evaluate(ctx)));
|
||||
} else if (this.type.kind === 'resolvedImage') {
|
||||
return ResolvedImage.fromString(valueToString(this.args[0].evaluate(ctx)));
|
||||
} else {
|
||||
return valueToString(this.args[0].evaluate(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
this.args.forEach(fn);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return this.args.every(arg => arg.outputDefined());
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
if (this.type.kind === 'formatted') {
|
||||
return new FormatExpression([{content: this.args[0], scale: null, font: null, textColor: null}]).serialize();
|
||||
}
|
||||
|
||||
if (this.type.kind === 'resolvedImage') {
|
||||
return new ImageExpression(this.args[0]).serialize();
|
||||
}
|
||||
|
||||
const serialized = [`to-${this.type.kind}`];
|
||||
this.eachChild(child => { serialized.push(child.serialize()); });
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
export default Coercion;
|
||||
78
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/collator.js
generated
vendored
Normal file
78
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/collator.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
// @flow
|
||||
|
||||
import {StringType, BooleanType, CollatorType} from '../types.js';
|
||||
import Collator from '../types/collator.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
export default class CollatorExpression implements Expression {
|
||||
type: Type;
|
||||
caseSensitive: Expression;
|
||||
diacriticSensitive: Expression;
|
||||
locale: Expression | null;
|
||||
|
||||
constructor(caseSensitive: Expression, diacriticSensitive: Expression, locale: Expression | null) {
|
||||
this.type = CollatorType;
|
||||
this.locale = locale;
|
||||
this.caseSensitive = caseSensitive;
|
||||
this.diacriticSensitive = diacriticSensitive;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Expression {
|
||||
if (args.length !== 2)
|
||||
return context.error(`Expected one argument.`);
|
||||
|
||||
const options = (args[1]: any);
|
||||
if (typeof options !== "object" || Array.isArray(options))
|
||||
return context.error(`Collator options argument must be an object.`);
|
||||
|
||||
const caseSensitive = context.parse(
|
||||
options['case-sensitive'] === undefined ? false : options['case-sensitive'], 1, BooleanType);
|
||||
if (!caseSensitive) return null;
|
||||
|
||||
const diacriticSensitive = context.parse(
|
||||
options['diacritic-sensitive'] === undefined ? false : options['diacritic-sensitive'], 1, BooleanType);
|
||||
if (!diacriticSensitive) return null;
|
||||
|
||||
let locale = null;
|
||||
if (options['locale']) {
|
||||
locale = context.parse(options['locale'], 1, StringType);
|
||||
if (!locale) return null;
|
||||
}
|
||||
|
||||
return new CollatorExpression(caseSensitive, diacriticSensitive, locale);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): Collator {
|
||||
return new Collator(this.caseSensitive.evaluate(ctx), this.diacriticSensitive.evaluate(ctx), this.locale ? this.locale.evaluate(ctx) : null);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.caseSensitive);
|
||||
fn(this.diacriticSensitive);
|
||||
if (this.locale) {
|
||||
fn(this.locale);
|
||||
}
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
// Technically the set of possible outputs is the combinatoric set of Collators produced
|
||||
// by all possible outputs of locale/caseSensitive/diacriticSensitive
|
||||
// But for the primary use of Collators in comparison operators, we ignore the Collator's
|
||||
// possible outputs anyway, so we can get away with leaving this false for now.
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const options = {};
|
||||
options['case-sensitive'] = this.caseSensitive.serialize();
|
||||
options['diacritic-sensitive'] = this.diacriticSensitive.serialize();
|
||||
if (this.locale) {
|
||||
options['locale'] = this.locale.serialize();
|
||||
}
|
||||
return ["collator", options];
|
||||
}
|
||||
}
|
||||
184
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/comparison.js
generated
vendored
Normal file
184
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/comparison.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
// @flow
|
||||
|
||||
import {toString, ValueType, BooleanType, CollatorType} from '../types.js';
|
||||
import Assertion from './assertion.js';
|
||||
import {typeOf} from '../values.js';
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
|
||||
import type {Expression, SerializedExpression, ExpressionRegistration} from '../expression.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
type ComparisonOperator = '==' | '!=' | '<' | '>' | '<=' | '>=' ;
|
||||
|
||||
function isComparableType(op: ComparisonOperator, type: Type) {
|
||||
if (op === '==' || op === '!=') {
|
||||
// equality operator
|
||||
return type.kind === 'boolean' ||
|
||||
type.kind === 'string' ||
|
||||
type.kind === 'number' ||
|
||||
type.kind === 'null' ||
|
||||
type.kind === 'value';
|
||||
} else {
|
||||
// ordering operator
|
||||
return type.kind === 'string' ||
|
||||
type.kind === 'number' ||
|
||||
type.kind === 'value';
|
||||
}
|
||||
}
|
||||
|
||||
function eq(ctx: EvaluationContext, a: any, b: any): boolean { return a === b; }
|
||||
function neq(ctx: EvaluationContext, a: any, b: any): boolean { return a !== b; }
|
||||
function lt(ctx: EvaluationContext, a: any, b: any): boolean { return a < b; }
|
||||
function gt(ctx: EvaluationContext, a: any, b: any): boolean { return a > b; }
|
||||
function lteq(ctx: EvaluationContext, a: any, b: any): boolean { return a <= b; }
|
||||
function gteq(ctx: EvaluationContext, a: any, b: any): boolean { return a >= b; }
|
||||
|
||||
function eqCollate(ctx: EvaluationContext, a: any, b: any, c: any): boolean { return c.compare(a, b) === 0; }
|
||||
function neqCollate(ctx: EvaluationContext, a: any, b: any, c: any): boolean { return !eqCollate(ctx, a, b, c); }
|
||||
function ltCollate(ctx: EvaluationContext, a: any, b: any, c: any): boolean { return c.compare(a, b) < 0; }
|
||||
function gtCollate(ctx: EvaluationContext, a: any, b: any, c: any): boolean { return c.compare(a, b) > 0; }
|
||||
function lteqCollate(ctx: EvaluationContext, a: any, b: any, c: any): boolean { return c.compare(a, b) <= 0; }
|
||||
function gteqCollate(ctx: EvaluationContext, a: any, b: any, c: any): boolean { return c.compare(a, b) >= 0; }
|
||||
|
||||
/**
|
||||
* Special form for comparison operators, implementing the signatures:
|
||||
* - (T, T, ?Collator) => boolean
|
||||
* - (T, value, ?Collator) => boolean
|
||||
* - (value, T, ?Collator) => boolean
|
||||
*
|
||||
* For inequalities, T must be either value, string, or number. For ==/!=, it
|
||||
* can also be boolean or null.
|
||||
*
|
||||
* Equality semantics are equivalent to Javascript's strict equality (===/!==)
|
||||
* -- i.e., when the arguments' types don't match, == evaluates to false, != to
|
||||
* true.
|
||||
*
|
||||
* When types don't match in an ordering comparison, a runtime error is thrown.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function makeComparison(op: ComparisonOperator, compareBasic: (EvaluationContext, any, any) => boolean, compareWithCollator: (EvaluationContext, any, any, any) => boolean): ExpressionRegistration {
|
||||
const isOrderComparison = op !== '==' && op !== '!=';
|
||||
|
||||
return class Comparison implements Expression {
|
||||
type: Type;
|
||||
lhs: Expression;
|
||||
rhs: Expression;
|
||||
collator: ?Expression;
|
||||
hasUntypedArgument: boolean;
|
||||
|
||||
constructor(lhs: Expression, rhs: Expression, collator: ?Expression) {
|
||||
this.type = BooleanType;
|
||||
this.lhs = lhs;
|
||||
this.rhs = rhs;
|
||||
this.collator = collator;
|
||||
this.hasUntypedArgument = lhs.type.kind === 'value' || rhs.type.kind === 'value';
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Expression {
|
||||
if (args.length !== 3 && args.length !== 4)
|
||||
return context.error(`Expected two or three arguments.`);
|
||||
|
||||
const op: ComparisonOperator = (args[0]: any);
|
||||
|
||||
let lhs = context.parse(args[1], 1, ValueType);
|
||||
if (!lhs) return null;
|
||||
if (!isComparableType(op, lhs.type)) {
|
||||
return context.concat(1).error(`"${op}" comparisons are not supported for type '${toString(lhs.type)}'.`);
|
||||
}
|
||||
let rhs = context.parse(args[2], 2, ValueType);
|
||||
if (!rhs) return null;
|
||||
if (!isComparableType(op, rhs.type)) {
|
||||
return context.concat(2).error(`"${op}" comparisons are not supported for type '${toString(rhs.type)}'.`);
|
||||
}
|
||||
|
||||
if (
|
||||
lhs.type.kind !== rhs.type.kind &&
|
||||
lhs.type.kind !== 'value' &&
|
||||
rhs.type.kind !== 'value'
|
||||
) {
|
||||
return context.error(`Cannot compare types '${toString(lhs.type)}' and '${toString(rhs.type)}'.`);
|
||||
}
|
||||
|
||||
if (isOrderComparison) {
|
||||
// typing rules specific to less/greater than operators
|
||||
if (lhs.type.kind === 'value' && rhs.type.kind !== 'value') {
|
||||
// (value, T)
|
||||
lhs = new Assertion(rhs.type, [lhs]);
|
||||
} else if (lhs.type.kind !== 'value' && rhs.type.kind === 'value') {
|
||||
// (T, value)
|
||||
rhs = new Assertion(lhs.type, [rhs]);
|
||||
}
|
||||
}
|
||||
|
||||
let collator = null;
|
||||
if (args.length === 4) {
|
||||
if (
|
||||
lhs.type.kind !== 'string' &&
|
||||
rhs.type.kind !== 'string' &&
|
||||
lhs.type.kind !== 'value' &&
|
||||
rhs.type.kind !== 'value'
|
||||
) {
|
||||
return context.error(`Cannot use collator to compare non-string types.`);
|
||||
}
|
||||
collator = context.parse(args[3], 3, CollatorType);
|
||||
if (!collator) return null;
|
||||
}
|
||||
|
||||
return new Comparison(lhs, rhs, collator);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): boolean {
|
||||
const lhs = this.lhs.evaluate(ctx);
|
||||
const rhs = this.rhs.evaluate(ctx);
|
||||
|
||||
if (isOrderComparison && this.hasUntypedArgument) {
|
||||
const lt = typeOf(lhs);
|
||||
const rt = typeOf(rhs);
|
||||
// check that type is string or number, and equal
|
||||
if (lt.kind !== rt.kind || !(lt.kind === 'string' || lt.kind === 'number')) {
|
||||
throw new RuntimeError(`Expected arguments for "${op}" to be (string, string) or (number, number), but found (${lt.kind}, ${rt.kind}) instead.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.collator && !isOrderComparison && this.hasUntypedArgument) {
|
||||
const lt = typeOf(lhs);
|
||||
const rt = typeOf(rhs);
|
||||
if (lt.kind !== 'string' || rt.kind !== 'string') {
|
||||
return compareBasic(ctx, lhs, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
return this.collator ?
|
||||
compareWithCollator(ctx, lhs, rhs, this.collator.evaluate(ctx)) :
|
||||
compareBasic(ctx, lhs, rhs);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.lhs);
|
||||
fn(this.rhs);
|
||||
if (this.collator) {
|
||||
fn(this.collator);
|
||||
}
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const serialized = [op];
|
||||
this.eachChild(child => { serialized.push(child.serialize()); });
|
||||
return serialized;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const Equals: $Call<typeof makeComparison, '==', typeof eq, typeof eqCollate> = makeComparison('==', eq, eqCollate);
|
||||
export const NotEquals: $Call<typeof makeComparison, '!=', typeof neq, typeof neqCollate> = makeComparison('!=', neq, neqCollate);
|
||||
export const LessThan: $Call<typeof makeComparison, '<', typeof lt, typeof ltCollate> = makeComparison('<', lt, ltCollate);
|
||||
export const GreaterThan: $Call<typeof makeComparison, '>', typeof gt, typeof gtCollate> = makeComparison('>', gt, gtCollate);
|
||||
export const LessThanOrEqual: $Call<typeof makeComparison, '<=', typeof lteq, typeof lteqCollate> = makeComparison('<=', lteq, lteqCollate);
|
||||
export const GreaterThanOrEqual: $Call<typeof makeComparison, '>=', typeof gteq, typeof gteqCollate> = makeComparison('>=', gteq, gteqCollate);
|
||||
144
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/format.js
generated
vendored
Normal file
144
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/format.js
generated
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
// @flow
|
||||
|
||||
import {NumberType, ValueType, FormattedType, array, StringType, ColorType, ResolvedImageType} from '../types.js';
|
||||
import Formatted, {FormattedSection} from '../types/formatted.js';
|
||||
import {toString, typeOf} from '../values.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
type FormattedSectionExpression = {
|
||||
// Content of a section may be Image expression or other
|
||||
// type of expression that is coercable to 'string'.
|
||||
content: Expression,
|
||||
scale: Expression | null;
|
||||
font: Expression | null;
|
||||
textColor: Expression | null;
|
||||
}
|
||||
|
||||
export default class FormatExpression implements Expression {
|
||||
type: Type;
|
||||
sections: Array<FormattedSectionExpression>;
|
||||
|
||||
constructor(sections: Array<FormattedSectionExpression>) {
|
||||
this.type = FormattedType;
|
||||
this.sections = sections;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Expression {
|
||||
if (args.length < 2) {
|
||||
return context.error(`Expected at least one argument.`);
|
||||
}
|
||||
|
||||
const firstArg = args[1];
|
||||
if (!Array.isArray(firstArg) && typeof firstArg === 'object') {
|
||||
return context.error(`First argument must be an image or text section.`);
|
||||
}
|
||||
|
||||
const sections: Array<FormattedSectionExpression> = [];
|
||||
let nextTokenMayBeObject = false;
|
||||
for (let i = 1; i <= args.length - 1; ++i) {
|
||||
const arg = (args[i]: any);
|
||||
|
||||
if (nextTokenMayBeObject && typeof arg === "object" && !Array.isArray(arg)) {
|
||||
nextTokenMayBeObject = false;
|
||||
|
||||
let scale = null;
|
||||
if (arg['font-scale']) {
|
||||
scale = context.parse(arg['font-scale'], 1, NumberType);
|
||||
if (!scale) return null;
|
||||
}
|
||||
|
||||
let font = null;
|
||||
if (arg['text-font']) {
|
||||
font = context.parse(arg['text-font'], 1, array(StringType));
|
||||
if (!font) return null;
|
||||
}
|
||||
|
||||
let textColor = null;
|
||||
if (arg['text-color']) {
|
||||
textColor = context.parse(arg['text-color'], 1, ColorType);
|
||||
if (!textColor) return null;
|
||||
}
|
||||
|
||||
const lastExpression = sections[sections.length - 1];
|
||||
lastExpression.scale = scale;
|
||||
lastExpression.font = font;
|
||||
lastExpression.textColor = textColor;
|
||||
} else {
|
||||
const content = context.parse(args[i], 1, ValueType);
|
||||
if (!content) return null;
|
||||
|
||||
const kind = content.type.kind;
|
||||
if (kind !== 'string' && kind !== 'value' && kind !== 'null' && kind !== 'resolvedImage')
|
||||
return context.error(`Formatted text type must be 'string', 'value', 'image' or 'null'.`);
|
||||
|
||||
nextTokenMayBeObject = true;
|
||||
sections.push({content, scale: null, font: null, textColor: null});
|
||||
}
|
||||
}
|
||||
|
||||
return new FormatExpression(sections);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): Formatted {
|
||||
const evaluateSection = section => {
|
||||
const evaluatedContent = section.content.evaluate(ctx);
|
||||
if (typeOf(evaluatedContent) === ResolvedImageType) {
|
||||
return new FormattedSection('', evaluatedContent, null, null, null);
|
||||
}
|
||||
|
||||
return new FormattedSection(
|
||||
toString(evaluatedContent),
|
||||
null,
|
||||
section.scale ? section.scale.evaluate(ctx) : null,
|
||||
section.font ? section.font.evaluate(ctx).join(',') : null,
|
||||
section.textColor ? section.textColor.evaluate(ctx) : null
|
||||
);
|
||||
};
|
||||
|
||||
return new Formatted(this.sections.map(evaluateSection));
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
for (const section of this.sections) {
|
||||
fn(section.content);
|
||||
if (section.scale) {
|
||||
fn(section.scale);
|
||||
}
|
||||
if (section.font) {
|
||||
fn(section.font);
|
||||
}
|
||||
if (section.textColor) {
|
||||
fn(section.textColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
// Technically the combinatoric set of all children
|
||||
// Usually, this.text will be undefined anyway
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const serialized = ["format"];
|
||||
for (const section of this.sections) {
|
||||
serialized.push(section.content.serialize());
|
||||
const options = {};
|
||||
if (section.scale) {
|
||||
options['font-scale'] = section.scale.serialize();
|
||||
}
|
||||
if (section.font) {
|
||||
options['text-font'] = section.font.serialize();
|
||||
}
|
||||
if (section.textColor) {
|
||||
options['text-color'] = section.textColor.serialize();
|
||||
}
|
||||
serialized.push(options);
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
52
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/image.js
generated
vendored
Normal file
52
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/image.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// @flow
|
||||
|
||||
import {ResolvedImageType, StringType} from '../types.js';
|
||||
import ResolvedImage from '../types/resolved_image.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
export default class ImageExpression implements Expression {
|
||||
type: Type;
|
||||
input: Expression;
|
||||
|
||||
constructor(input: Expression) {
|
||||
this.type = ResolvedImageType;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Expression {
|
||||
if (args.length !== 2) {
|
||||
return context.error(`Expected two arguments.`);
|
||||
}
|
||||
|
||||
const name = context.parse(args[1], 1, StringType);
|
||||
if (!name) return context.error(`No image name provided.`);
|
||||
|
||||
return new ImageExpression(name);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): null | ResolvedImage {
|
||||
const evaluatedImageName = this.input.evaluate(ctx);
|
||||
|
||||
const value = ResolvedImage.fromString(evaluatedImageName);
|
||||
if (value && ctx.availableImages) value.available = ctx.availableImages.indexOf(evaluatedImageName) > -1;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.input);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
// The output of image is determined by the list of available images in the evaluation context
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
return ["image", this.input.serialize()];
|
||||
}
|
||||
}
|
||||
72
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/in.js
generated
vendored
Normal file
72
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/in.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// @flow
|
||||
|
||||
import {BooleanType, StringType, ValueType, NullType, toString, NumberType, isValidType, isValidNativeType} from '../types.js';
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
import {typeOf} from '../values.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
class In implements Expression {
|
||||
type: Type;
|
||||
needle: Expression;
|
||||
haystack: Expression;
|
||||
|
||||
constructor(needle: Expression, haystack: Expression) {
|
||||
this.type = BooleanType;
|
||||
this.needle = needle;
|
||||
this.haystack = haystack;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?In {
|
||||
if (args.length !== 3) {
|
||||
return context.error(`Expected 2 arguments, but found ${args.length - 1} instead.`);
|
||||
}
|
||||
|
||||
const needle = context.parse(args[1], 1, ValueType);
|
||||
|
||||
const haystack = context.parse(args[2], 2, ValueType);
|
||||
|
||||
if (!needle || !haystack) return null;
|
||||
|
||||
if (!isValidType(needle.type, [BooleanType, StringType, NumberType, NullType, ValueType])) {
|
||||
return context.error(`Expected first argument to be of type boolean, string, number or null, but found ${toString(needle.type)} instead`);
|
||||
}
|
||||
|
||||
return new In(needle, haystack);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): boolean {
|
||||
const needle = (this.needle.evaluate(ctx): any);
|
||||
const haystack = (this.haystack.evaluate(ctx): any);
|
||||
|
||||
if (haystack == null) return false;
|
||||
|
||||
if (!isValidNativeType(needle, ['boolean', 'string', 'number', 'null'])) {
|
||||
throw new RuntimeError(`Expected first argument to be of type boolean, string, number or null, but found ${toString(typeOf(needle))} instead.`);
|
||||
}
|
||||
|
||||
if (!isValidNativeType(haystack, ['string', 'array'])) {
|
||||
throw new RuntimeError(`Expected second argument to be of type array or string, but found ${toString(typeOf(haystack))} instead.`);
|
||||
}
|
||||
|
||||
return haystack.indexOf(needle) >= 0;
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.needle);
|
||||
fn(this.haystack);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
return ["in", this.needle.serialize(), this.haystack.serialize()];
|
||||
}
|
||||
}
|
||||
|
||||
export default In;
|
||||
580
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/index.js
generated
vendored
Normal file
580
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/index.js
generated
vendored
Normal file
@@ -0,0 +1,580 @@
|
||||
// @flow
|
||||
|
||||
import {
|
||||
type Type,
|
||||
NumberType,
|
||||
StringType,
|
||||
BooleanType,
|
||||
ColorType,
|
||||
ObjectType,
|
||||
ValueType,
|
||||
ErrorType,
|
||||
CollatorType,
|
||||
array,
|
||||
toString as typeToString
|
||||
} from '../types.js';
|
||||
|
||||
import {typeOf, Color, validateRGBA, toString as valueToString} from '../values.js';
|
||||
import CompoundExpression from '../compound_expression.js';
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
import Let from './let.js';
|
||||
import Var from './var.js';
|
||||
import Literal from './literal.js';
|
||||
import Assertion from './assertion.js';
|
||||
import Coercion from './coercion.js';
|
||||
import At from './at.js';
|
||||
import In from './in.js';
|
||||
import IndexOf from './index_of.js';
|
||||
import Match from './match.js';
|
||||
import Case from './case.js';
|
||||
import Slice from './slice.js';
|
||||
import Step from './step.js';
|
||||
import Interpolate from './interpolate.js';
|
||||
import Coalesce from './coalesce.js';
|
||||
import {
|
||||
Equals,
|
||||
NotEquals,
|
||||
LessThan,
|
||||
GreaterThan,
|
||||
LessThanOrEqual,
|
||||
GreaterThanOrEqual
|
||||
} from './comparison.js';
|
||||
import CollatorExpression from './collator.js';
|
||||
import NumberFormat from './number_format.js';
|
||||
import FormatExpression from './format.js';
|
||||
import ImageExpression from './image.js';
|
||||
import Length from './length.js';
|
||||
import Within from './within.js';
|
||||
|
||||
import type {Varargs} from '../compound_expression.js';
|
||||
import type {ExpressionRegistry} from '../expression.js';
|
||||
|
||||
const expressions: ExpressionRegistry = {
|
||||
// special forms
|
||||
'==': Equals,
|
||||
'!=': NotEquals,
|
||||
'>': GreaterThan,
|
||||
'<': LessThan,
|
||||
'>=': GreaterThanOrEqual,
|
||||
'<=': LessThanOrEqual,
|
||||
'array': Assertion,
|
||||
'at': At,
|
||||
'boolean': Assertion,
|
||||
'case': Case,
|
||||
'coalesce': Coalesce,
|
||||
'collator': CollatorExpression,
|
||||
'format': FormatExpression,
|
||||
'image': ImageExpression,
|
||||
'in': In,
|
||||
'index-of': IndexOf,
|
||||
'interpolate': Interpolate,
|
||||
'interpolate-hcl': Interpolate,
|
||||
'interpolate-lab': Interpolate,
|
||||
'length': Length,
|
||||
'let': Let,
|
||||
'literal': Literal,
|
||||
'match': Match,
|
||||
'number': Assertion,
|
||||
'number-format': NumberFormat,
|
||||
'object': Assertion,
|
||||
'slice': Slice,
|
||||
'step': Step,
|
||||
'string': Assertion,
|
||||
'to-boolean': Coercion,
|
||||
'to-color': Coercion,
|
||||
'to-number': Coercion,
|
||||
'to-string': Coercion,
|
||||
'var': Var,
|
||||
'within': Within
|
||||
};
|
||||
|
||||
function rgba(ctx, [r, g, b, a]) {
|
||||
r = r.evaluate(ctx);
|
||||
g = g.evaluate(ctx);
|
||||
b = b.evaluate(ctx);
|
||||
const alpha = a ? a.evaluate(ctx) : 1;
|
||||
const error = validateRGBA(r, g, b, alpha);
|
||||
if (error) throw new RuntimeError(error);
|
||||
return new Color(r / 255 * alpha, g / 255 * alpha, b / 255 * alpha, alpha);
|
||||
}
|
||||
|
||||
function has(key, obj) {
|
||||
return key in obj;
|
||||
}
|
||||
|
||||
function get(key, obj) {
|
||||
const v = obj[key];
|
||||
return typeof v === 'undefined' ? null : v;
|
||||
}
|
||||
|
||||
function binarySearch(v, a, i, j) {
|
||||
while (i <= j) {
|
||||
const m = (i + j) >> 1;
|
||||
if (a[m] === v)
|
||||
return true;
|
||||
if (a[m] > v)
|
||||
j = m - 1;
|
||||
else
|
||||
i = m + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function varargs(type: Type): Varargs {
|
||||
return {type};
|
||||
}
|
||||
|
||||
CompoundExpression.register(expressions, {
|
||||
'error': [
|
||||
ErrorType,
|
||||
[StringType],
|
||||
(ctx, [v]) => { throw new RuntimeError(v.evaluate(ctx)); }
|
||||
],
|
||||
'typeof': [
|
||||
StringType,
|
||||
[ValueType],
|
||||
(ctx, [v]) => typeToString(typeOf(v.evaluate(ctx)))
|
||||
],
|
||||
'to-rgba': [
|
||||
array(NumberType, 4),
|
||||
[ColorType],
|
||||
(ctx, [v]) => {
|
||||
return v.evaluate(ctx).toArray();
|
||||
}
|
||||
],
|
||||
'rgb': [
|
||||
ColorType,
|
||||
[NumberType, NumberType, NumberType],
|
||||
rgba
|
||||
],
|
||||
'rgba': [
|
||||
ColorType,
|
||||
[NumberType, NumberType, NumberType, NumberType],
|
||||
rgba
|
||||
],
|
||||
'has': {
|
||||
type: BooleanType,
|
||||
overloads: [
|
||||
[
|
||||
[StringType],
|
||||
(ctx, [key]) => has(key.evaluate(ctx), ctx.properties())
|
||||
], [
|
||||
[StringType, ObjectType],
|
||||
(ctx, [key, obj]) => has(key.evaluate(ctx), obj.evaluate(ctx))
|
||||
]
|
||||
]
|
||||
},
|
||||
'get': {
|
||||
type: ValueType,
|
||||
overloads: [
|
||||
[
|
||||
[StringType],
|
||||
(ctx, [key]) => get(key.evaluate(ctx), ctx.properties())
|
||||
], [
|
||||
[StringType, ObjectType],
|
||||
(ctx, [key, obj]) => get(key.evaluate(ctx), obj.evaluate(ctx))
|
||||
]
|
||||
]
|
||||
},
|
||||
'feature-state': [
|
||||
ValueType,
|
||||
[StringType],
|
||||
(ctx, [key]) => get(key.evaluate(ctx), ctx.featureState || {})
|
||||
],
|
||||
'properties': [
|
||||
ObjectType,
|
||||
[],
|
||||
(ctx) => ctx.properties()
|
||||
],
|
||||
'geometry-type': [
|
||||
StringType,
|
||||
[],
|
||||
(ctx) => ctx.geometryType()
|
||||
],
|
||||
'id': [
|
||||
ValueType,
|
||||
[],
|
||||
(ctx) => ctx.id()
|
||||
],
|
||||
'zoom': [
|
||||
NumberType,
|
||||
[],
|
||||
(ctx) => ctx.globals.zoom
|
||||
],
|
||||
'pitch': [
|
||||
NumberType,
|
||||
[],
|
||||
(ctx) => ctx.globals.pitch || 0
|
||||
],
|
||||
'distance-from-center': [
|
||||
NumberType,
|
||||
[],
|
||||
(ctx) => ctx.distanceFromCenter()
|
||||
],
|
||||
'heatmap-density': [
|
||||
NumberType,
|
||||
[],
|
||||
(ctx) => ctx.globals.heatmapDensity || 0
|
||||
],
|
||||
'line-progress': [
|
||||
NumberType,
|
||||
[],
|
||||
(ctx) => ctx.globals.lineProgress || 0
|
||||
],
|
||||
'sky-radial-progress': [
|
||||
NumberType,
|
||||
[],
|
||||
(ctx) => ctx.globals.skyRadialProgress || 0
|
||||
],
|
||||
'accumulated': [
|
||||
ValueType,
|
||||
[],
|
||||
(ctx) => ctx.globals.accumulated === undefined ? null : ctx.globals.accumulated
|
||||
],
|
||||
'+': [
|
||||
NumberType,
|
||||
varargs(NumberType),
|
||||
(ctx, args) => {
|
||||
let result = 0;
|
||||
for (const arg of args) {
|
||||
result += arg.evaluate(ctx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
],
|
||||
'*': [
|
||||
NumberType,
|
||||
varargs(NumberType),
|
||||
(ctx, args) => {
|
||||
let result = 1;
|
||||
for (const arg of args) {
|
||||
result *= arg.evaluate(ctx);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
],
|
||||
'-': {
|
||||
type: NumberType,
|
||||
overloads: [
|
||||
[
|
||||
[NumberType, NumberType],
|
||||
(ctx, [a, b]) => a.evaluate(ctx) - b.evaluate(ctx)
|
||||
], [
|
||||
[NumberType],
|
||||
(ctx, [a]) => -a.evaluate(ctx)
|
||||
]
|
||||
]
|
||||
},
|
||||
'/': [
|
||||
NumberType,
|
||||
[NumberType, NumberType],
|
||||
(ctx, [a, b]) => a.evaluate(ctx) / b.evaluate(ctx)
|
||||
],
|
||||
'%': [
|
||||
NumberType,
|
||||
[NumberType, NumberType],
|
||||
(ctx, [a, b]) => a.evaluate(ctx) % b.evaluate(ctx)
|
||||
],
|
||||
'ln2': [
|
||||
NumberType,
|
||||
[],
|
||||
() => Math.LN2
|
||||
],
|
||||
'pi': [
|
||||
NumberType,
|
||||
[],
|
||||
() => Math.PI
|
||||
],
|
||||
'e': [
|
||||
NumberType,
|
||||
[],
|
||||
() => Math.E
|
||||
],
|
||||
'^': [
|
||||
NumberType,
|
||||
[NumberType, NumberType],
|
||||
(ctx, [b, e]) => Math.pow(b.evaluate(ctx), e.evaluate(ctx))
|
||||
],
|
||||
'sqrt': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [x]) => Math.sqrt(x.evaluate(ctx))
|
||||
],
|
||||
'log10': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.log(n.evaluate(ctx)) / Math.LN10
|
||||
],
|
||||
'ln': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.log(n.evaluate(ctx))
|
||||
],
|
||||
'log2': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.log(n.evaluate(ctx)) / Math.LN2
|
||||
],
|
||||
'sin': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.sin(n.evaluate(ctx))
|
||||
],
|
||||
'cos': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.cos(n.evaluate(ctx))
|
||||
],
|
||||
'tan': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.tan(n.evaluate(ctx))
|
||||
],
|
||||
'asin': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.asin(n.evaluate(ctx))
|
||||
],
|
||||
'acos': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.acos(n.evaluate(ctx))
|
||||
],
|
||||
'atan': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.atan(n.evaluate(ctx))
|
||||
],
|
||||
'min': [
|
||||
NumberType,
|
||||
varargs(NumberType),
|
||||
(ctx, args) => Math.min(...args.map(arg => arg.evaluate(ctx)))
|
||||
],
|
||||
'max': [
|
||||
NumberType,
|
||||
varargs(NumberType),
|
||||
(ctx, args) => Math.max(...args.map(arg => arg.evaluate(ctx)))
|
||||
],
|
||||
'abs': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.abs(n.evaluate(ctx))
|
||||
],
|
||||
'round': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => {
|
||||
const v = n.evaluate(ctx);
|
||||
// Javascript's Math.round() rounds towards +Infinity for halfway
|
||||
// values, even when they're negative. It's more common to round
|
||||
// away from 0 (e.g., this is what python and C++ do)
|
||||
return v < 0 ? -Math.round(-v) : Math.round(v);
|
||||
}
|
||||
],
|
||||
'floor': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.floor(n.evaluate(ctx))
|
||||
],
|
||||
'ceil': [
|
||||
NumberType,
|
||||
[NumberType],
|
||||
(ctx, [n]) => Math.ceil(n.evaluate(ctx))
|
||||
],
|
||||
'filter-==': [
|
||||
BooleanType,
|
||||
[StringType, ValueType],
|
||||
(ctx, [k, v]) => ctx.properties()[(k: any).value] === (v: any).value
|
||||
],
|
||||
'filter-id-==': [
|
||||
BooleanType,
|
||||
[ValueType],
|
||||
(ctx, [v]) => ctx.id() === (v: any).value
|
||||
],
|
||||
'filter-type-==': [
|
||||
BooleanType,
|
||||
[StringType],
|
||||
(ctx, [v]) => ctx.geometryType() === (v: any).value
|
||||
],
|
||||
'filter-<': [
|
||||
BooleanType,
|
||||
[StringType, ValueType],
|
||||
(ctx, [k, v]) => {
|
||||
const a = ctx.properties()[(k: any).value];
|
||||
const b = (v: any).value;
|
||||
return typeof a === typeof b && a < b;
|
||||
}
|
||||
],
|
||||
'filter-id-<': [
|
||||
BooleanType,
|
||||
[ValueType],
|
||||
(ctx, [v]) => {
|
||||
const a = ctx.id();
|
||||
const b = (v: any).value;
|
||||
return typeof a === typeof b && a < b;
|
||||
}
|
||||
],
|
||||
'filter->': [
|
||||
BooleanType,
|
||||
[StringType, ValueType],
|
||||
(ctx, [k, v]) => {
|
||||
const a = ctx.properties()[(k: any).value];
|
||||
const b = (v: any).value;
|
||||
return typeof a === typeof b && a > b;
|
||||
}
|
||||
],
|
||||
'filter-id->': [
|
||||
BooleanType,
|
||||
[ValueType],
|
||||
(ctx, [v]) => {
|
||||
const a = ctx.id();
|
||||
const b = (v: any).value;
|
||||
return typeof a === typeof b && a > b;
|
||||
}
|
||||
],
|
||||
'filter-<=': [
|
||||
BooleanType,
|
||||
[StringType, ValueType],
|
||||
(ctx, [k, v]) => {
|
||||
const a = ctx.properties()[(k: any).value];
|
||||
const b = (v: any).value;
|
||||
return typeof a === typeof b && a <= b;
|
||||
}
|
||||
],
|
||||
'filter-id-<=': [
|
||||
BooleanType,
|
||||
[ValueType],
|
||||
(ctx, [v]) => {
|
||||
const a = ctx.id();
|
||||
const b = (v: any).value;
|
||||
return typeof a === typeof b && a <= b;
|
||||
}
|
||||
],
|
||||
'filter->=': [
|
||||
BooleanType,
|
||||
[StringType, ValueType],
|
||||
(ctx, [k, v]) => {
|
||||
const a = ctx.properties()[(k: any).value];
|
||||
const b = (v: any).value;
|
||||
return typeof a === typeof b && a >= b;
|
||||
}
|
||||
],
|
||||
'filter-id->=': [
|
||||
BooleanType,
|
||||
[ValueType],
|
||||
(ctx, [v]) => {
|
||||
const a = ctx.id();
|
||||
const b = (v: any).value;
|
||||
return typeof a === typeof b && a >= b;
|
||||
}
|
||||
],
|
||||
'filter-has': [
|
||||
BooleanType,
|
||||
[ValueType],
|
||||
(ctx, [k]) => (k: any).value in ctx.properties()
|
||||
],
|
||||
'filter-has-id': [
|
||||
BooleanType,
|
||||
[],
|
||||
(ctx) => (ctx.id() !== null && ctx.id() !== undefined)
|
||||
],
|
||||
'filter-type-in': [
|
||||
BooleanType,
|
||||
[array(StringType)],
|
||||
(ctx, [v]) => (v: any).value.indexOf(ctx.geometryType()) >= 0
|
||||
],
|
||||
'filter-id-in': [
|
||||
BooleanType,
|
||||
[array(ValueType)],
|
||||
(ctx, [v]) => (v: any).value.indexOf(ctx.id()) >= 0
|
||||
],
|
||||
'filter-in-small': [
|
||||
BooleanType,
|
||||
[StringType, array(ValueType)],
|
||||
// assumes v is an array literal
|
||||
(ctx, [k, v]) => (v: any).value.indexOf(ctx.properties()[(k: any).value]) >= 0
|
||||
],
|
||||
'filter-in-large': [
|
||||
BooleanType,
|
||||
[StringType, array(ValueType)],
|
||||
// assumes v is a array literal with values sorted in ascending order and of a single type
|
||||
(ctx, [k, v]) => binarySearch(ctx.properties()[(k: any).value], (v: any).value, 0, (v: any).value.length - 1)
|
||||
],
|
||||
'all': {
|
||||
type: BooleanType,
|
||||
overloads: [
|
||||
[
|
||||
[BooleanType, BooleanType],
|
||||
(ctx, [a, b]) => a.evaluate(ctx) && b.evaluate(ctx)
|
||||
],
|
||||
[
|
||||
varargs(BooleanType),
|
||||
(ctx, args) => {
|
||||
for (const arg of args) {
|
||||
if (!arg.evaluate(ctx))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
'any': {
|
||||
type: BooleanType,
|
||||
overloads: [
|
||||
[
|
||||
[BooleanType, BooleanType],
|
||||
(ctx, [a, b]) => a.evaluate(ctx) || b.evaluate(ctx)
|
||||
],
|
||||
[
|
||||
varargs(BooleanType),
|
||||
(ctx, args) => {
|
||||
for (const arg of args) {
|
||||
if (arg.evaluate(ctx))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
'!': [
|
||||
BooleanType,
|
||||
[BooleanType],
|
||||
(ctx, [b]) => !b.evaluate(ctx)
|
||||
],
|
||||
'is-supported-script': [
|
||||
BooleanType,
|
||||
[StringType],
|
||||
// At parse time this will always return true, so we need to exclude this expression with isGlobalPropertyConstant
|
||||
(ctx, [s]) => {
|
||||
const isSupportedScript = ctx.globals && ctx.globals.isSupportedScript;
|
||||
if (isSupportedScript) {
|
||||
return isSupportedScript(s.evaluate(ctx));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
],
|
||||
'upcase': [
|
||||
StringType,
|
||||
[StringType],
|
||||
(ctx, [s]) => s.evaluate(ctx).toUpperCase()
|
||||
],
|
||||
'downcase': [
|
||||
StringType,
|
||||
[StringType],
|
||||
(ctx, [s]) => s.evaluate(ctx).toLowerCase()
|
||||
],
|
||||
'concat': [
|
||||
StringType,
|
||||
varargs(ValueType),
|
||||
(ctx, args) => args.map(arg => valueToString(arg.evaluate(ctx))).join('')
|
||||
],
|
||||
'resolved-locale': [
|
||||
StringType,
|
||||
[CollatorType],
|
||||
(ctx, [collator]) => collator.evaluate(ctx).resolvedLocale()
|
||||
]
|
||||
});
|
||||
|
||||
export default expressions;
|
||||
89
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/index_of.js
generated
vendored
Normal file
89
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/index_of.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// @flow
|
||||
|
||||
import {BooleanType, StringType, ValueType, NullType, toString, NumberType, isValidType, isValidNativeType} from '../types.js';
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
import {typeOf} from '../values.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
class IndexOf implements Expression {
|
||||
type: Type;
|
||||
needle: Expression;
|
||||
haystack: Expression;
|
||||
fromIndex: ?Expression;
|
||||
|
||||
constructor(needle: Expression, haystack: Expression, fromIndex?: Expression) {
|
||||
this.type = NumberType;
|
||||
this.needle = needle;
|
||||
this.haystack = haystack;
|
||||
this.fromIndex = fromIndex;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?IndexOf {
|
||||
if (args.length <= 2 || args.length >= 5) {
|
||||
return context.error(`Expected 3 or 4 arguments, but found ${args.length - 1} instead.`);
|
||||
}
|
||||
|
||||
const needle = context.parse(args[1], 1, ValueType);
|
||||
|
||||
const haystack = context.parse(args[2], 2, ValueType);
|
||||
|
||||
if (!needle || !haystack) return null;
|
||||
if (!isValidType(needle.type, [BooleanType, StringType, NumberType, NullType, ValueType])) {
|
||||
return context.error(`Expected first argument to be of type boolean, string, number or null, but found ${toString(needle.type)} instead`);
|
||||
}
|
||||
|
||||
if (args.length === 4) {
|
||||
const fromIndex = context.parse(args[3], 3, NumberType);
|
||||
if (!fromIndex) return null;
|
||||
return new IndexOf(needle, haystack, fromIndex);
|
||||
} else {
|
||||
return new IndexOf(needle, haystack);
|
||||
}
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any {
|
||||
const needle = (this.needle.evaluate(ctx): any);
|
||||
const haystack = (this.haystack.evaluate(ctx): any);
|
||||
|
||||
if (!isValidNativeType(needle, ['boolean', 'string', 'number', 'null'])) {
|
||||
throw new RuntimeError(`Expected first argument to be of type boolean, string, number or null, but found ${toString(typeOf(needle))} instead.`);
|
||||
}
|
||||
|
||||
if (!isValidNativeType(haystack, ['string', 'array'])) {
|
||||
throw new RuntimeError(`Expected second argument to be of type array or string, but found ${toString(typeOf(haystack))} instead.`);
|
||||
}
|
||||
|
||||
if (this.fromIndex) {
|
||||
const fromIndex = (this.fromIndex.evaluate(ctx): number);
|
||||
return haystack.indexOf(needle, fromIndex);
|
||||
}
|
||||
|
||||
return haystack.indexOf(needle);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.needle);
|
||||
fn(this.haystack);
|
||||
if (this.fromIndex) {
|
||||
fn(this.fromIndex);
|
||||
}
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
if (this.fromIndex != null && this.fromIndex !== undefined) {
|
||||
const fromIndex = this.fromIndex.serialize();
|
||||
return ["index-of", this.needle.serialize(), this.haystack.serialize(), fromIndex];
|
||||
}
|
||||
return ["index-of", this.needle.serialize(), this.haystack.serialize()];
|
||||
}
|
||||
}
|
||||
|
||||
export default IndexOf;
|
||||
268
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/interpolate.js
generated
vendored
Normal file
268
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/interpolate.js
generated
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
// @flow
|
||||
|
||||
import UnitBezier from '@mapbox/unitbezier';
|
||||
|
||||
import * as interpolate from '../../util/interpolate.js';
|
||||
import {toString, NumberType, ColorType} from '../types.js';
|
||||
import {findStopLessThanOrEqualTo} from '../stops.js';
|
||||
import {hcl, lab} from '../../util/color_spaces.js';
|
||||
import Color from '../../util/color.js';
|
||||
|
||||
import type {Stops} from '../stops.js';
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
export type InterpolationType =
|
||||
{ name: 'linear' } |
|
||||
{ name: 'exponential', base: number } |
|
||||
{ name: 'cubic-bezier', controlPoints: [number, number, number, number] };
|
||||
|
||||
class Interpolate implements Expression {
|
||||
type: Type;
|
||||
|
||||
operator: 'interpolate' | 'interpolate-hcl' | 'interpolate-lab';
|
||||
interpolation: InterpolationType;
|
||||
input: Expression;
|
||||
labels: Array<number>;
|
||||
outputs: Array<Expression>;
|
||||
|
||||
constructor(type: Type, operator: 'interpolate' | 'interpolate-hcl' | 'interpolate-lab', interpolation: InterpolationType, input: Expression, stops: Stops) {
|
||||
this.type = type;
|
||||
this.operator = operator;
|
||||
this.interpolation = interpolation;
|
||||
this.input = input;
|
||||
|
||||
this.labels = [];
|
||||
this.outputs = [];
|
||||
for (const [label, expression] of stops) {
|
||||
this.labels.push(label);
|
||||
this.outputs.push(expression);
|
||||
}
|
||||
}
|
||||
|
||||
static interpolationFactor(interpolation: InterpolationType, input: number, lower: number, upper: number): number {
|
||||
let t = 0;
|
||||
if (interpolation.name === 'exponential') {
|
||||
t = exponentialInterpolation(input, interpolation.base, lower, upper);
|
||||
} else if (interpolation.name === 'linear') {
|
||||
t = exponentialInterpolation(input, 1, lower, upper);
|
||||
} else if (interpolation.name === 'cubic-bezier') {
|
||||
const c = interpolation.controlPoints;
|
||||
const ub = new UnitBezier(c[0], c[1], c[2], c[3]);
|
||||
t = ub.solve(exponentialInterpolation(input, 1, lower, upper));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Interpolate {
|
||||
let [operator, interpolation, input, ...rest] = args;
|
||||
|
||||
if (!Array.isArray(interpolation) || interpolation.length === 0) {
|
||||
return context.error(`Expected an interpolation type expression.`, 1);
|
||||
}
|
||||
|
||||
if (interpolation[0] === 'linear') {
|
||||
interpolation = {name: 'linear'};
|
||||
} else if (interpolation[0] === 'exponential') {
|
||||
const base = interpolation[1];
|
||||
if (typeof base !== 'number')
|
||||
return context.error(`Exponential interpolation requires a numeric base.`, 1, 1);
|
||||
interpolation = {
|
||||
name: 'exponential',
|
||||
base
|
||||
};
|
||||
} else if (interpolation[0] === 'cubic-bezier') {
|
||||
const controlPoints = interpolation.slice(1);
|
||||
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);
|
||||
}
|
||||
|
||||
interpolation = {
|
||||
name: 'cubic-bezier',
|
||||
controlPoints: (controlPoints: any)
|
||||
};
|
||||
} else {
|
||||
return context.error(`Unknown interpolation type ${String(interpolation[0])}`, 1, 0);
|
||||
}
|
||||
|
||||
if (args.length - 1 < 4) {
|
||||
return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
||||
}
|
||||
|
||||
if ((args.length - 1) % 2 !== 0) {
|
||||
return context.error(`Expected an even number of arguments.`);
|
||||
}
|
||||
|
||||
input = context.parse(input, 2, NumberType);
|
||||
if (!input) return null;
|
||||
|
||||
const stops: Stops = [];
|
||||
|
||||
let outputType: Type = (null: any);
|
||||
if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') {
|
||||
outputType = ColorType;
|
||||
} else if (context.expectedType && context.expectedType.kind !== 'value') {
|
||||
outputType = context.expectedType;
|
||||
}
|
||||
|
||||
for (let i = 0; i < rest.length; i += 2) {
|
||||
const label = rest[i];
|
||||
const value = rest[i + 1];
|
||||
|
||||
const labelKey = i + 3;
|
||||
const valueKey = i + 4;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
const parsed = context.parse(value, valueKey, outputType);
|
||||
if (!parsed) return null;
|
||||
outputType = outputType || parsed.type;
|
||||
stops.push([label, parsed]);
|
||||
}
|
||||
|
||||
if (outputType.kind !== 'number' &&
|
||||
outputType.kind !== 'color' &&
|
||||
!(
|
||||
outputType.kind === 'array' &&
|
||||
outputType.itemType.kind === 'number' &&
|
||||
typeof outputType.N === 'number'
|
||||
)
|
||||
) {
|
||||
return context.error(`Type ${toString(outputType)} is not interpolatable.`);
|
||||
}
|
||||
|
||||
return new Interpolate(outputType, (operator: any), interpolation, input, stops);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): Color {
|
||||
const labels = this.labels;
|
||||
const outputs = this.outputs;
|
||||
|
||||
if (labels.length === 1) {
|
||||
return outputs[0].evaluate(ctx);
|
||||
}
|
||||
|
||||
const value = ((this.input.evaluate(ctx): any): number);
|
||||
if (value <= labels[0]) {
|
||||
return outputs[0].evaluate(ctx);
|
||||
}
|
||||
|
||||
const stopCount = labels.length;
|
||||
if (value >= labels[stopCount - 1]) {
|
||||
return outputs[stopCount - 1].evaluate(ctx);
|
||||
}
|
||||
|
||||
const index = findStopLessThanOrEqualTo(labels, value);
|
||||
const lower = labels[index];
|
||||
const upper = labels[index + 1];
|
||||
const t = Interpolate.interpolationFactor(this.interpolation, value, lower, upper);
|
||||
|
||||
const outputLower = outputs[index].evaluate(ctx);
|
||||
const outputUpper = outputs[index + 1].evaluate(ctx);
|
||||
|
||||
if (this.operator === 'interpolate') {
|
||||
return (interpolate[this.type.kind.toLowerCase()]: any)(outputLower, outputUpper, t); // eslint-disable-line import/namespace
|
||||
} else if (this.operator === 'interpolate-hcl') {
|
||||
return hcl.reverse(hcl.interpolate(hcl.forward(outputLower), hcl.forward(outputUpper), t));
|
||||
} else {
|
||||
return lab.reverse(lab.interpolate(lab.forward(outputLower), lab.forward(outputUpper), t));
|
||||
}
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.input);
|
||||
for (const expression of this.outputs) {
|
||||
fn(expression);
|
||||
}
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return this.outputs.every(out => out.outputDefined());
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
let interpolation;
|
||||
if (this.interpolation.name === 'linear') {
|
||||
interpolation = ["linear"];
|
||||
} else if (this.interpolation.name === 'exponential') {
|
||||
if (this.interpolation.base === 1) {
|
||||
interpolation = ["linear"];
|
||||
} else {
|
||||
interpolation = ["exponential", this.interpolation.base];
|
||||
}
|
||||
} else {
|
||||
interpolation = ["cubic-bezier" ].concat(this.interpolation.controlPoints);
|
||||
}
|
||||
|
||||
const serialized = [this.operator, interpolation, this.input.serialize()];
|
||||
|
||||
for (let i = 0; i < this.labels.length; i++) {
|
||||
serialized.push(
|
||||
this.labels[i],
|
||||
this.outputs[i].serialize()
|
||||
);
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a ratio that can be used to interpolate between exponential function
|
||||
* stops.
|
||||
* 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,
|
||||
* and `a` and `b` are constants affording sufficient degrees of freedom to fit
|
||||
* the function to the given stops.
|
||||
*
|
||||
* Here's a bit of algebra that lets us compute `f(x)` directly from the stop
|
||||
* values without explicitly solving for `a` and `b`:
|
||||
*
|
||||
* First stop value: `f(x0) = y0 = a * base^x0 + b`
|
||||
* Second stop value: `f(x1) = y1 = a * base^x1 + b`
|
||||
* => `y1 - y0 = a(base^x1 - base^x0)`
|
||||
* => `a = (y1 - y0)/(base^x1 - base^x0)`
|
||||
*
|
||||
* Desired value: `f(x) = y = a * base^x + b`
|
||||
* => `f(x) = y0 + a * (base^x - base^x0)`
|
||||
*
|
||||
* From the above, we can replace the `a` in `a * (base^x - base^x0)` and do a
|
||||
* little algebra:
|
||||
* ```
|
||||
* a * (base^x - base^x0) = (y1 - y0)/(base^x1 - base^x0) * (base^x - base^x0)
|
||||
* = (y1 - y0) * (base^x - base^x0) / (base^x1 - base^x0)
|
||||
* ```
|
||||
*
|
||||
* If we let `(base^x - base^x0) / (base^x1 base^x0)`, then we have
|
||||
* `f(x) = y0 + (y1 - y0) * ratio`. In other words, `ratio` may be treated as
|
||||
* an interpolation factor between the two stops' output values.
|
||||
*
|
||||
* (Note: a slightly different form for `ratio`,
|
||||
* `(base^(x-x0) - 1) / (base^(x1-x0) - 1) `, is equivalent, but requires fewer
|
||||
* expensive `Math.pow()` operations.)
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function exponentialInterpolation(input, base, lowerValue, upperValue) {
|
||||
const difference = upperValue - lowerValue;
|
||||
const progress = input - lowerValue;
|
||||
|
||||
if (difference === 0) {
|
||||
return 0;
|
||||
} else if (base === 1) {
|
||||
return progress / difference;
|
||||
} else {
|
||||
return (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
export default Interpolate;
|
||||
61
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/length.js
generated
vendored
Normal file
61
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/length.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// @flow
|
||||
|
||||
import {NumberType, toString} from '../types.js';
|
||||
|
||||
import {typeOf} from '../values.js';
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
class Length implements Expression {
|
||||
type: Type;
|
||||
input: Expression;
|
||||
|
||||
constructor(input: Expression) {
|
||||
this.type = NumberType;
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Length {
|
||||
if (args.length !== 2)
|
||||
return context.error(`Expected 1 argument, but found ${args.length - 1} instead.`);
|
||||
|
||||
const input = context.parse(args[1], 1);
|
||||
if (!input) return null;
|
||||
|
||||
if (input.type.kind !== 'array' && input.type.kind !== 'string' && input.type.kind !== 'value')
|
||||
return context.error(`Expected argument of type string or array, but found ${toString(input.type)} instead.`);
|
||||
|
||||
return new Length(input);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any | number {
|
||||
const input = this.input.evaluate(ctx);
|
||||
if (typeof input === 'string') {
|
||||
return input.length;
|
||||
} else if (Array.isArray(input)) {
|
||||
return input.length;
|
||||
} else {
|
||||
throw new RuntimeError(`Expected value to be of type string or array, but found ${toString(typeOf(input))} instead.`);
|
||||
}
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.input);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const serialized = ["length"];
|
||||
this.eachChild(child => { serialized.push(child.serialize()); });
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
export default Length;
|
||||
72
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/let.js
generated
vendored
Normal file
72
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/let.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// @flow
|
||||
|
||||
import type {Type} from '../types.js';
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
|
||||
class Let implements Expression {
|
||||
type: Type;
|
||||
bindings: Array<[string, Expression]>;
|
||||
result: Expression;
|
||||
|
||||
constructor(bindings: Array<[string, Expression]>, result: Expression) {
|
||||
this.type = result.type;
|
||||
this.bindings = [].concat(bindings);
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any {
|
||||
return this.result.evaluate(ctx);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
for (const binding of this.bindings) {
|
||||
fn(binding[1]);
|
||||
}
|
||||
fn(this.result);
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Let {
|
||||
if (args.length < 4)
|
||||
return context.error(`Expected at least 3 arguments, but found ${args.length - 1} instead.`);
|
||||
|
||||
const bindings: Array<[string, Expression]> = [];
|
||||
for (let i = 1; i < args.length - 1; i += 2) {
|
||||
const name = args[i];
|
||||
|
||||
if (typeof name !== 'string') {
|
||||
return context.error(`Expected string, but found ${typeof name} instead.`, i);
|
||||
}
|
||||
|
||||
if (/[^a-zA-Z0-9_]/.test(name)) {
|
||||
return context.error(`Variable names must contain only alphanumeric characters or '_'.`, i);
|
||||
}
|
||||
|
||||
const value = context.parse(args[i + 1], i + 1);
|
||||
if (!value) return null;
|
||||
|
||||
bindings.push([name, value]);
|
||||
}
|
||||
|
||||
const result = context.parse(args[args.length - 1], args.length - 1, context.expectedType, bindings);
|
||||
if (!result) return null;
|
||||
|
||||
return new Let(bindings, result);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return this.result.outputDefined();
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const serialized = ["let"];
|
||||
for (const [name, expr] of this.bindings) {
|
||||
serialized.push(name, expr.serialize());
|
||||
}
|
||||
serialized.push(this.result.serialize());
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
export default Let;
|
||||
77
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/literal.js
generated
vendored
Normal file
77
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/literal.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
// @flow
|
||||
|
||||
import assert from 'assert';
|
||||
import {isValue, typeOf, Color} from '../values.js';
|
||||
import Formatted from '../types/formatted.js';
|
||||
|
||||
import type {Type} from '../types.js';
|
||||
import type {Value} from '../values.js';
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
|
||||
class Literal implements Expression {
|
||||
type: Type;
|
||||
value: Value;
|
||||
|
||||
constructor(type: Type, value: Value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): void | Literal {
|
||||
if (args.length !== 2)
|
||||
return context.error(`'literal' expression requires exactly one argument, but found ${args.length - 1} instead.`);
|
||||
|
||||
if (!isValue(args[1]))
|
||||
return context.error(`invalid value`);
|
||||
|
||||
const value = (args[1]: any);
|
||||
let type = typeOf(value);
|
||||
|
||||
// special case: infer the item type if possible for zero-length arrays
|
||||
const expected = context.expectedType;
|
||||
if (
|
||||
type.kind === 'array' &&
|
||||
type.N === 0 &&
|
||||
expected &&
|
||||
expected.kind === 'array' &&
|
||||
(typeof expected.N !== 'number' || expected.N === 0)
|
||||
) {
|
||||
type = expected;
|
||||
}
|
||||
|
||||
return new Literal(type, value);
|
||||
}
|
||||
|
||||
evaluate(): Value {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
eachChild() {}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
if (this.type.kind === 'array' || this.type.kind === 'object') {
|
||||
return ["literal", this.value];
|
||||
} else if (this.value instanceof Color) {
|
||||
// Constant-folding can generate Literal expressions that you
|
||||
// couldn't actually generate with a "literal" expression,
|
||||
// so we have to implement an equivalent serialization here
|
||||
return ["rgba"].concat(this.value.toArray());
|
||||
} else if (this.value instanceof Formatted) {
|
||||
// Same as Color
|
||||
return this.value.serialize();
|
||||
} else {
|
||||
assert(this.value === null ||
|
||||
typeof this.value === 'string' ||
|
||||
typeof this.value === 'number' ||
|
||||
typeof this.value === 'boolean');
|
||||
return (this.value: any);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Literal;
|
||||
158
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/match.js
generated
vendored
Normal file
158
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/match.js
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
// @flow
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import {typeOf} from '../values.js';
|
||||
import {ValueType, type Type} from '../types.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
|
||||
// Map input label values to output expression index
|
||||
type Cases = {[number | string]: number};
|
||||
|
||||
class Match implements Expression {
|
||||
type: Type;
|
||||
inputType: Type;
|
||||
|
||||
input: Expression;
|
||||
cases: Cases;
|
||||
outputs: Array<Expression>;
|
||||
otherwise: Expression;
|
||||
|
||||
constructor(inputType: Type, outputType: Type, input: Expression, cases: Cases, outputs: Array<Expression>, otherwise: Expression) {
|
||||
this.inputType = inputType;
|
||||
this.type = outputType;
|
||||
this.input = input;
|
||||
this.cases = cases;
|
||||
this.outputs = outputs;
|
||||
this.otherwise = otherwise;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Match {
|
||||
if (args.length < 5)
|
||||
return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
||||
if (args.length % 2 !== 1)
|
||||
return context.error(`Expected an even number of arguments.`);
|
||||
|
||||
let inputType;
|
||||
let outputType;
|
||||
if (context.expectedType && context.expectedType.kind !== 'value') {
|
||||
outputType = context.expectedType;
|
||||
}
|
||||
const cases = {};
|
||||
const outputs = [];
|
||||
for (let i = 2; i < args.length - 1; i += 2) {
|
||||
let labels = args[i];
|
||||
const value = args[i + 1];
|
||||
|
||||
if (!Array.isArray(labels)) {
|
||||
labels = [labels];
|
||||
}
|
||||
|
||||
const labelContext = context.concat(i);
|
||||
if (labels.length === 0) {
|
||||
return labelContext.error('Expected at least one branch label.');
|
||||
}
|
||||
|
||||
for (const label of labels) {
|
||||
if (typeof label !== 'number' && typeof label !== 'string') {
|
||||
return labelContext.error(`Branch labels must be numbers or strings.`);
|
||||
} else if (typeof label === 'number' && Math.abs(label) > Number.MAX_SAFE_INTEGER) {
|
||||
return labelContext.error(`Branch labels must be integers no larger than ${Number.MAX_SAFE_INTEGER}.`);
|
||||
|
||||
} else if (typeof label === 'number' && Math.floor(label) !== label) {
|
||||
return labelContext.error(`Numeric branch labels must be integer values.`);
|
||||
|
||||
} else if (!inputType) {
|
||||
inputType = typeOf(label);
|
||||
} else if (labelContext.checkSubtype(inputType, typeOf(label))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof cases[String(label)] !== 'undefined') {
|
||||
return labelContext.error('Branch labels must be unique.');
|
||||
}
|
||||
|
||||
cases[String(label)] = outputs.length;
|
||||
}
|
||||
|
||||
const result = context.parse(value, i, outputType);
|
||||
if (!result) return null;
|
||||
outputType = outputType || result.type;
|
||||
outputs.push(result);
|
||||
}
|
||||
|
||||
const input = context.parse(args[1], 1, ValueType);
|
||||
if (!input) return null;
|
||||
|
||||
const otherwise = context.parse(args[args.length - 1], args.length - 1, outputType);
|
||||
if (!otherwise) return null;
|
||||
|
||||
assert(inputType && outputType);
|
||||
|
||||
if (input.type.kind !== 'value' && context.concat(1).checkSubtype((inputType: any), input.type)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Match((inputType: any), (outputType: any), input, cases, outputs, otherwise);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any {
|
||||
const input = (this.input.evaluate(ctx): any);
|
||||
const output = (typeOf(input) === this.inputType && this.outputs[this.cases[input]]) || this.otherwise;
|
||||
return output.evaluate(ctx);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.input);
|
||||
this.outputs.forEach(fn);
|
||||
fn(this.otherwise);
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return this.outputs.every(out => out.outputDefined()) && this.otherwise.outputDefined();
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const serialized = ["match", this.input.serialize()];
|
||||
|
||||
// Sort so serialization has an arbitrary defined order, even though
|
||||
// branch order doesn't affect evaluation
|
||||
const sortedLabels = Object.keys(this.cases).sort();
|
||||
|
||||
// Group branches by unique match expression to support condensed
|
||||
// serializations of the form [case1, case2, ...] -> matchExpression
|
||||
const groupedByOutput: Array<[number, Array<number | string>]> = [];
|
||||
const outputLookup: {[index: number]: number} = {}; // lookup index into groupedByOutput for a given output expression
|
||||
for (const label of sortedLabels) {
|
||||
const outputIndex = outputLookup[this.cases[label]];
|
||||
if (outputIndex === undefined) {
|
||||
// First time seeing this output, add it to the end of the grouped list
|
||||
outputLookup[this.cases[label]] = groupedByOutput.length;
|
||||
groupedByOutput.push([this.cases[label], [label]]);
|
||||
} else {
|
||||
// We've seen this expression before, add the label to that output's group
|
||||
groupedByOutput[outputIndex][1].push(label);
|
||||
}
|
||||
}
|
||||
|
||||
const coerceLabel = (label) => this.inputType.kind === 'number' ? Number(label) : label;
|
||||
|
||||
for (const [outputIndex, labels] of groupedByOutput) {
|
||||
if (labels.length === 1) {
|
||||
// Only a single label matches this output expression
|
||||
serialized.push(coerceLabel(labels[0]));
|
||||
} else {
|
||||
// Array of literal labels pointing to this output expression
|
||||
serialized.push(labels.map(coerceLabel));
|
||||
}
|
||||
serialized.push(this.outputs[outputIndex].serialize());
|
||||
}
|
||||
serialized.push(this.otherwise.serialize());
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
export default Match;
|
||||
162
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/number_format.js
generated
vendored
Normal file
162
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/number_format.js
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// @flow
|
||||
|
||||
import {StringType, NumberType} from '../types.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
declare var Intl: {
|
||||
NumberFormat: Class<Intl$NumberFormat>
|
||||
};
|
||||
|
||||
declare class Intl$NumberFormat {
|
||||
constructor (
|
||||
locales?: string | string[],
|
||||
options?: NumberFormatOptions
|
||||
): Intl$NumberFormat;
|
||||
|
||||
static (
|
||||
locales?: string | string[],
|
||||
options?: NumberFormatOptions
|
||||
): Intl$NumberFormat;
|
||||
|
||||
format(a: number): string;
|
||||
|
||||
resolvedOptions(): any;
|
||||
}
|
||||
|
||||
type NumberFormatOptions = {
|
||||
style?: 'decimal' | 'currency' | 'percent' | 'unit';
|
||||
currency?: null | string;
|
||||
unit?: null | string;
|
||||
minimumFractionDigits?: null | string;
|
||||
maximumFractionDigits?: null | string;
|
||||
};
|
||||
|
||||
export default class NumberFormat implements Expression {
|
||||
type: Type;
|
||||
number: Expression;
|
||||
locale: Expression | null; // BCP 47 language tag
|
||||
currency: Expression | null; // ISO 4217 currency code, required if style=currency
|
||||
unit: Expression | null; // Simple units sanctioned for use in ECMAScript, required if style=unit. https://tc39.es/proposal-unified-intl-numberformat/section6/locales-currencies-tz_proposed_out.html#sec-issanctionedsimpleunitidentifier
|
||||
minFractionDigits: Expression | null; // Default 0
|
||||
maxFractionDigits: Expression | null; // Default 3
|
||||
|
||||
constructor(number: Expression,
|
||||
locale: Expression | null,
|
||||
currency: Expression | null,
|
||||
unit: Expression | null,
|
||||
minFractionDigits: Expression | null,
|
||||
maxFractionDigits: Expression | null) {
|
||||
this.type = StringType;
|
||||
this.number = number;
|
||||
this.locale = locale;
|
||||
this.currency = currency;
|
||||
this.unit = unit;
|
||||
this.minFractionDigits = minFractionDigits;
|
||||
this.maxFractionDigits = maxFractionDigits;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Expression {
|
||||
if (args.length !== 3)
|
||||
return context.error(`Expected two arguments.`);
|
||||
|
||||
const number = context.parse(args[1], 1, NumberType);
|
||||
if (!number) return null;
|
||||
|
||||
const options = (args[2]: any);
|
||||
if (typeof options !== "object" || Array.isArray(options))
|
||||
return context.error(`NumberFormat options argument must be an object.`);
|
||||
|
||||
let locale = null;
|
||||
if (options['locale']) {
|
||||
locale = context.parse(options['locale'], 1, StringType);
|
||||
if (!locale) return null;
|
||||
}
|
||||
|
||||
let currency = null;
|
||||
if (options['currency']) {
|
||||
currency = context.parse(options['currency'], 1, StringType);
|
||||
if (!currency) return null;
|
||||
}
|
||||
|
||||
let unit = null;
|
||||
if (options['unit']) {
|
||||
unit = context.parse(options['unit'], 1, StringType);
|
||||
if (!unit) return null;
|
||||
}
|
||||
|
||||
let minFractionDigits = null;
|
||||
if (options['min-fraction-digits']) {
|
||||
minFractionDigits = context.parse(options['min-fraction-digits'], 1, NumberType);
|
||||
if (!minFractionDigits) return null;
|
||||
}
|
||||
|
||||
let maxFractionDigits = null;
|
||||
if (options['max-fraction-digits']) {
|
||||
maxFractionDigits = context.parse(options['max-fraction-digits'], 1, NumberType);
|
||||
if (!maxFractionDigits) return null;
|
||||
}
|
||||
|
||||
return new NumberFormat(number, locale, currency, unit, minFractionDigits, maxFractionDigits);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): string {
|
||||
return new Intl.NumberFormat(this.locale ? this.locale.evaluate(ctx) : [],
|
||||
{
|
||||
style:
|
||||
(this.currency && "currency") ||
|
||||
(this.unit && "unit") ||
|
||||
"decimal",
|
||||
currency: this.currency ? this.currency.evaluate(ctx) : undefined,
|
||||
unit: this.unit ? this.unit.evaluate(ctx) : undefined,
|
||||
minimumFractionDigits: this.minFractionDigits ? this.minFractionDigits.evaluate(ctx) : undefined,
|
||||
maximumFractionDigits: this.maxFractionDigits ? this.maxFractionDigits.evaluate(ctx) : undefined,
|
||||
}).format(this.number.evaluate(ctx));
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.number);
|
||||
if (this.locale) {
|
||||
fn(this.locale);
|
||||
}
|
||||
if (this.currency) {
|
||||
fn(this.currency);
|
||||
}
|
||||
if (this.unit) {
|
||||
fn(this.unit);
|
||||
}
|
||||
if (this.minFractionDigits) {
|
||||
fn(this.minFractionDigits);
|
||||
}
|
||||
if (this.maxFractionDigits) {
|
||||
fn(this.maxFractionDigits);
|
||||
}
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const options = {};
|
||||
if (this.locale) {
|
||||
options['locale'] = this.locale.serialize();
|
||||
}
|
||||
if (this.currency) {
|
||||
options['currency'] = this.currency.serialize();
|
||||
}
|
||||
if (this.unit) {
|
||||
options['unit'] = this.unit.serialize();
|
||||
}
|
||||
if (this.minFractionDigits) {
|
||||
options['min-fraction-digits'] = this.minFractionDigits.serialize();
|
||||
}
|
||||
if (this.maxFractionDigits) {
|
||||
options['max-fraction-digits'] = this.maxFractionDigits.serialize();
|
||||
}
|
||||
return ["number-format", this.number.serialize(), options];
|
||||
}
|
||||
}
|
||||
86
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/slice.js
generated
vendored
Normal file
86
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/slice.js
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
// @flow
|
||||
|
||||
import {ValueType, NumberType, StringType, array, toString, isValidType, isValidNativeType} from '../types.js';
|
||||
import RuntimeError from '../runtime_error.js';
|
||||
import {typeOf} from '../values.js';
|
||||
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
class Slice implements Expression {
|
||||
type: Type;
|
||||
input: Expression;
|
||||
beginIndex: Expression;
|
||||
endIndex: ?Expression;
|
||||
|
||||
constructor(type: Type, input: Expression, beginIndex: Expression, endIndex?: Expression) {
|
||||
this.type = type;
|
||||
this.input = input;
|
||||
this.beginIndex = beginIndex;
|
||||
this.endIndex = endIndex;
|
||||
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Slice {
|
||||
if (args.length <= 2 || args.length >= 5) {
|
||||
return context.error(`Expected 3 or 4 arguments, but found ${args.length - 1} instead.`);
|
||||
}
|
||||
|
||||
const input = context.parse(args[1], 1, ValueType);
|
||||
const beginIndex = context.parse(args[2], 2, NumberType);
|
||||
|
||||
if (!input || !beginIndex) return null;
|
||||
|
||||
if (!isValidType(input.type, [array(ValueType), StringType, ValueType])) {
|
||||
return context.error(`Expected first argument to be of type array or string, but found ${toString(input.type)} instead`);
|
||||
}
|
||||
|
||||
if (args.length === 4) {
|
||||
const endIndex = context.parse(args[3], 3, NumberType);
|
||||
if (!endIndex) return null;
|
||||
return new Slice(input.type, input, beginIndex, endIndex);
|
||||
} else {
|
||||
return new Slice(input.type, input, beginIndex);
|
||||
}
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any {
|
||||
const input = (this.input.evaluate(ctx): any);
|
||||
const beginIndex = (this.beginIndex.evaluate(ctx): number);
|
||||
|
||||
if (!isValidNativeType(input, ['string', 'array'])) {
|
||||
throw new RuntimeError(`Expected first argument to be of type array or string, but found ${toString(typeOf(input))} instead.`);
|
||||
}
|
||||
|
||||
if (this.endIndex) {
|
||||
const endIndex = (this.endIndex.evaluate(ctx): number);
|
||||
return input.slice(beginIndex, endIndex);
|
||||
}
|
||||
|
||||
return input.slice(beginIndex);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.input);
|
||||
fn(this.beginIndex);
|
||||
if (this.endIndex) {
|
||||
fn(this.endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
if (this.endIndex != null && this.endIndex !== undefined) {
|
||||
const endIndex = this.endIndex.serialize();
|
||||
return ["slice", this.input.serialize(), this.beginIndex.serialize(), endIndex];
|
||||
}
|
||||
return ["slice", this.input.serialize(), this.beginIndex.serialize()];
|
||||
}
|
||||
}
|
||||
|
||||
export default Slice;
|
||||
120
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/step.js
generated
vendored
Normal file
120
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/step.js
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// @flow
|
||||
|
||||
import {NumberType} from '../types.js';
|
||||
|
||||
import {findStopLessThanOrEqualTo} from '../stops.js';
|
||||
|
||||
import type {Stops} from '../stops.js';
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {Type} from '../types.js';
|
||||
|
||||
class Step implements Expression {
|
||||
type: Type;
|
||||
|
||||
input: Expression;
|
||||
labels: Array<number>;
|
||||
outputs: Array<Expression>;
|
||||
|
||||
constructor(type: Type, input: Expression, stops: Stops) {
|
||||
this.type = type;
|
||||
this.input = input;
|
||||
|
||||
this.labels = [];
|
||||
this.outputs = [];
|
||||
for (const [label, expression] of stops) {
|
||||
this.labels.push(label);
|
||||
this.outputs.push(expression);
|
||||
}
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Step {
|
||||
if (args.length - 1 < 4) {
|
||||
return context.error(`Expected at least 4 arguments, but found only ${args.length - 1}.`);
|
||||
}
|
||||
|
||||
if ((args.length - 1) % 2 !== 0) {
|
||||
return context.error(`Expected an even number of arguments.`);
|
||||
}
|
||||
|
||||
const input = context.parse(args[1], 1, NumberType);
|
||||
if (!input) return null;
|
||||
|
||||
const stops: Stops = [];
|
||||
|
||||
let outputType: Type = (null: any);
|
||||
if (context.expectedType && context.expectedType.kind !== 'value') {
|
||||
outputType = context.expectedType;
|
||||
}
|
||||
|
||||
for (let i = 1; i < args.length; i += 2) {
|
||||
const label = i === 1 ? -Infinity : args[i];
|
||||
const value = args[i + 1];
|
||||
|
||||
const labelKey = i;
|
||||
const valueKey = i + 1;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
const parsed = context.parse(value, valueKey, outputType);
|
||||
if (!parsed) return null;
|
||||
outputType = outputType || parsed.type;
|
||||
stops.push([label, parsed]);
|
||||
}
|
||||
|
||||
return new Step(outputType, input, stops);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any {
|
||||
const labels = this.labels;
|
||||
const outputs = this.outputs;
|
||||
|
||||
if (labels.length === 1) {
|
||||
return outputs[0].evaluate(ctx);
|
||||
}
|
||||
|
||||
const value = ((this.input.evaluate(ctx): any): number);
|
||||
if (value <= labels[0]) {
|
||||
return outputs[0].evaluate(ctx);
|
||||
}
|
||||
|
||||
const stopCount = labels.length;
|
||||
if (value >= labels[stopCount - 1]) {
|
||||
return outputs[stopCount - 1].evaluate(ctx);
|
||||
}
|
||||
|
||||
const index = findStopLessThanOrEqualTo(labels, value);
|
||||
return outputs[index].evaluate(ctx);
|
||||
}
|
||||
|
||||
eachChild(fn: (_: Expression) => void) {
|
||||
fn(this.input);
|
||||
for (const expression of this.outputs) {
|
||||
fn(expression);
|
||||
}
|
||||
}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return this.outputs.every(out => out.outputDefined());
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
const serialized = ["step", this.input.serialize()];
|
||||
for (let i = 0; i < this.labels.length; i++) {
|
||||
if (i > 0) {
|
||||
serialized.push(this.labels[i]);
|
||||
}
|
||||
serialized.push(this.outputs[i].serialize());
|
||||
}
|
||||
return serialized;
|
||||
}
|
||||
}
|
||||
|
||||
export default Step;
|
||||
46
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/var.js
generated
vendored
Normal file
46
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/var.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// @flow
|
||||
|
||||
import type {Type} from '../types.js';
|
||||
import type {Expression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
|
||||
class Var implements Expression {
|
||||
type: Type;
|
||||
name: string;
|
||||
boundExpression: Expression;
|
||||
|
||||
constructor(name: string, boundExpression: Expression) {
|
||||
this.type = boundExpression.type;
|
||||
this.name = name;
|
||||
this.boundExpression = boundExpression;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): void | Var {
|
||||
if (args.length !== 2 || typeof args[1] !== 'string')
|
||||
return context.error(`'var' expression requires exactly one string literal argument.`);
|
||||
|
||||
const name = args[1];
|
||||
if (!context.scope.has(name)) {
|
||||
return context.error(`Unknown variable "${name}". Make sure "${name}" has been bound in an enclosing "let" expression before using it.`, 1);
|
||||
}
|
||||
|
||||
return new Var(name, context.scope.get(name));
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): any {
|
||||
return this.boundExpression.evaluate(ctx);
|
||||
}
|
||||
|
||||
eachChild() {}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
serialize(): Array<string> {
|
||||
return ["var", this.name];
|
||||
}
|
||||
}
|
||||
|
||||
export default Var;
|
||||
349
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/within.js
generated
vendored
Normal file
349
node_modules/@mapbox/mapbox-gl-style-spec/expression/definitions/within.js
generated
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
// @flow
|
||||
|
||||
import {isValue} from '../values.js';
|
||||
import type {Type} from '../types.js';
|
||||
import {BooleanType} from '../types.js';
|
||||
import type {Expression, SerializedExpression} from '../expression.js';
|
||||
import type ParsingContext from '../parsing_context.js';
|
||||
import type EvaluationContext from '../evaluation_context.js';
|
||||
import type {GeoJSON, GeoJSONPolygon, GeoJSONMultiPolygon} from '@mapbox/geojson-types';
|
||||
import type {CanonicalTileID} from '../../../source/tile_id.js';
|
||||
|
||||
type GeoJSONPolygons =| GeoJSONPolygon | GeoJSONMultiPolygon;
|
||||
|
||||
// minX, minY, maxX, maxY
|
||||
type BBox = [number, number, number, number];
|
||||
const EXTENT = 8192;
|
||||
|
||||
function updateBBox(bbox: BBox, coord: [number, number]) {
|
||||
bbox[0] = Math.min(bbox[0], coord[0]);
|
||||
bbox[1] = Math.min(bbox[1], coord[1]);
|
||||
bbox[2] = Math.max(bbox[2], coord[0]);
|
||||
bbox[3] = Math.max(bbox[3], coord[1]);
|
||||
}
|
||||
|
||||
function mercatorXfromLng(lng: number) {
|
||||
return (180 + lng) / 360;
|
||||
}
|
||||
|
||||
function mercatorYfromLat(lat: number) {
|
||||
return (180 - (180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360)))) / 360;
|
||||
}
|
||||
|
||||
function boxWithinBox(bbox1: BBox, bbox2: BBox) {
|
||||
if (bbox1[0] <= bbox2[0]) return false;
|
||||
if (bbox1[2] >= bbox2[2]) return false;
|
||||
if (bbox1[1] <= bbox2[1]) return false;
|
||||
if (bbox1[3] >= bbox2[3]) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function getTileCoordinates(p, canonical: CanonicalTileID) {
|
||||
const x = mercatorXfromLng(p[0]);
|
||||
const y = mercatorYfromLat(p[1]);
|
||||
const tilesAtZoom = Math.pow(2, canonical.z);
|
||||
return [Math.round(x * tilesAtZoom * EXTENT), Math.round(y * tilesAtZoom * EXTENT)];
|
||||
}
|
||||
|
||||
function onBoundary(p, p1, p2) {
|
||||
const x1 = p[0] - p1[0];
|
||||
const y1 = p[1] - p1[1];
|
||||
const x2 = p[0] - p2[0];
|
||||
const y2 = p[1] - p2[1];
|
||||
return (x1 * y2 - x2 * y1 === 0) && (x1 * x2 <= 0) && (y1 * y2 <= 0);
|
||||
}
|
||||
|
||||
function rayIntersect(p, p1, p2) {
|
||||
return ((p1[1] > p[1]) !== (p2[1] > p[1])) && (p[0] < (p2[0] - p1[0]) * (p[1] - p1[1]) / (p2[1] - p1[1]) + p1[0]);
|
||||
}
|
||||
|
||||
// ray casting algorithm for detecting if point is in polygon
|
||||
function pointWithinPolygon(point, rings) {
|
||||
let inside = false;
|
||||
for (let i = 0, len = rings.length; i < len; i++) {
|
||||
const ring = rings[i];
|
||||
for (let j = 0, len2 = ring.length; j < len2 - 1; j++) {
|
||||
if (onBoundary(point, ring[j], ring[j + 1])) return false;
|
||||
if (rayIntersect(point, ring[j], ring[j + 1])) inside = !inside;
|
||||
}
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
function pointWithinPolygons(point, polygons) {
|
||||
for (let i = 0; i < polygons.length; i++) {
|
||||
if (pointWithinPolygon(point, polygons[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function perp(v1, v2) {
|
||||
return (v1[0] * v2[1] - v1[1] * v2[0]);
|
||||
}
|
||||
|
||||
// check if p1 and p2 are in different sides of line segment q1->q2
|
||||
function twoSided(p1, p2, q1, q2) {
|
||||
// q1->p1 (x1, y1), q1->p2 (x2, y2), q1->q2 (x3, y3)
|
||||
const x1 = p1[0] - q1[0];
|
||||
const y1 = p1[1] - q1[1];
|
||||
const x2 = p2[0] - q1[0];
|
||||
const y2 = p2[1] - q1[1];
|
||||
const x3 = q2[0] - q1[0];
|
||||
const y3 = q2[1] - q1[1];
|
||||
const det1 = (x1 * y3 - x3 * y1);
|
||||
const det2 = (x2 * y3 - x3 * y2);
|
||||
if ((det1 > 0 && det2 < 0) || (det1 < 0 && det2 > 0)) return true;
|
||||
return false;
|
||||
}
|
||||
// a, b are end points for line segment1, c and d are end points for line segment2
|
||||
function lineIntersectLine(a, b, c, d) {
|
||||
// check if two segments are parallel or not
|
||||
// precondition is end point a, b is inside polygon, if line a->b is
|
||||
// parallel to polygon edge c->d, then a->b won't intersect with c->d
|
||||
const vectorP = [b[0] - a[0], b[1] - a[1]];
|
||||
const vectorQ = [d[0] - c[0], d[1] - c[1]];
|
||||
if (perp(vectorQ, vectorP) === 0) return false;
|
||||
|
||||
// If lines are intersecting with each other, the relative location should be:
|
||||
// a and b lie in different sides of segment c->d
|
||||
// c and d lie in different sides of segment a->b
|
||||
if (twoSided(a, b, c, d) && twoSided(c, d, a, b)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function lineIntersectPolygon(p1, p2, polygon) {
|
||||
for (const ring of polygon) {
|
||||
// loop through every edge of the ring
|
||||
for (let j = 0; j < ring.length - 1; ++j) {
|
||||
if (lineIntersectLine(p1, p2, ring[j], ring[j + 1])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function lineStringWithinPolygon(line, polygon) {
|
||||
// First, check if geometry points of line segments are all inside polygon
|
||||
for (let i = 0; i < line.length; ++i) {
|
||||
if (!pointWithinPolygon(line[i], polygon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Second, check if there is line segment intersecting polygon edge
|
||||
for (let i = 0; i < line.length - 1; ++i) {
|
||||
if (lineIntersectPolygon(line[i], line[i + 1], polygon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function lineStringWithinPolygons(line, polygons) {
|
||||
for (let i = 0; i < polygons.length; i++) {
|
||||
if (lineStringWithinPolygon(line, polygons[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getTilePolygon(coordinates, bbox: BBox, canonical: CanonicalTileID) {
|
||||
const polygon = [];
|
||||
for (let i = 0; i < coordinates.length; i++) {
|
||||
const ring = [];
|
||||
for (let j = 0; j < coordinates[i].length; j++) {
|
||||
const coord = getTileCoordinates(coordinates[i][j], canonical);
|
||||
updateBBox(bbox, coord);
|
||||
ring.push(coord);
|
||||
}
|
||||
polygon.push(ring);
|
||||
}
|
||||
return polygon;
|
||||
}
|
||||
|
||||
function getTilePolygons(coordinates, bbox, canonical: CanonicalTileID) {
|
||||
const polygons = [];
|
||||
for (let i = 0; i < coordinates.length; i++) {
|
||||
const polygon = getTilePolygon(coordinates[i], bbox, canonical);
|
||||
polygons.push(polygon);
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
|
||||
function updatePoint(p, bbox, polyBBox, worldSize) {
|
||||
if (p[0] < polyBBox[0] || p[0] > polyBBox[2]) {
|
||||
const halfWorldSize = worldSize * 0.5;
|
||||
let shift = (p[0] - polyBBox[0] > halfWorldSize) ? -worldSize : (polyBBox[0] - p[0] > halfWorldSize) ? worldSize : 0;
|
||||
if (shift === 0) {
|
||||
shift = (p[0] - polyBBox[2] > halfWorldSize) ? -worldSize : (polyBBox[2] - p[0] > halfWorldSize) ? worldSize : 0;
|
||||
}
|
||||
p[0] += shift;
|
||||
}
|
||||
updateBBox(bbox, p);
|
||||
}
|
||||
|
||||
function resetBBox(bbox) {
|
||||
bbox[0] = bbox[1] = Infinity;
|
||||
bbox[2] = bbox[3] = -Infinity;
|
||||
}
|
||||
|
||||
function getTilePoints(geometry, pointBBox, polyBBox, canonical: CanonicalTileID) {
|
||||
const worldSize = Math.pow(2, canonical.z) * EXTENT;
|
||||
const shifts = [canonical.x * EXTENT, canonical.y * EXTENT];
|
||||
const tilePoints = [];
|
||||
if (!geometry) return tilePoints;
|
||||
for (const points of geometry) {
|
||||
for (const point of points) {
|
||||
const p = [point.x + shifts[0], point.y + shifts[1]];
|
||||
updatePoint(p, pointBBox, polyBBox, worldSize);
|
||||
tilePoints.push(p);
|
||||
}
|
||||
}
|
||||
return tilePoints;
|
||||
}
|
||||
|
||||
function getTileLines(geometry, lineBBox, polyBBox, canonical: CanonicalTileID) {
|
||||
const worldSize = Math.pow(2, canonical.z) * EXTENT;
|
||||
const shifts = [canonical.x * EXTENT, canonical.y * EXTENT];
|
||||
const tileLines = [];
|
||||
if (!geometry) return tileLines;
|
||||
for (const line of geometry) {
|
||||
const tileLine = [];
|
||||
for (const point of line) {
|
||||
const p = [point.x + shifts[0], point.y + shifts[1]];
|
||||
updateBBox(lineBBox, p);
|
||||
tileLine.push(p);
|
||||
}
|
||||
tileLines.push(tileLine);
|
||||
}
|
||||
if (lineBBox[2] - lineBBox[0] <= worldSize / 2) {
|
||||
resetBBox(lineBBox);
|
||||
for (const line of tileLines) {
|
||||
for (const p of line) {
|
||||
updatePoint(p, lineBBox, polyBBox, worldSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tileLines;
|
||||
}
|
||||
|
||||
function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPolygons) {
|
||||
const pointBBox = [Infinity, Infinity, -Infinity, -Infinity];
|
||||
const polyBBox = [Infinity, Infinity, -Infinity, -Infinity];
|
||||
|
||||
const canonical = ctx.canonicalID();
|
||||
if (!canonical) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (polygonGeometry.type === 'Polygon') {
|
||||
const tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical);
|
||||
const tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical);
|
||||
if (!boxWithinBox(pointBBox, polyBBox)) return false;
|
||||
|
||||
for (const point of tilePoints) {
|
||||
if (!pointWithinPolygon(point, tilePolygon)) return false;
|
||||
}
|
||||
}
|
||||
if (polygonGeometry.type === 'MultiPolygon') {
|
||||
const tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical);
|
||||
const tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical);
|
||||
if (!boxWithinBox(pointBBox, polyBBox)) return false;
|
||||
|
||||
for (const point of tilePoints) {
|
||||
if (!pointWithinPolygons(point, tilePolygons)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function linesWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPolygons) {
|
||||
const lineBBox = [Infinity, Infinity, -Infinity, -Infinity];
|
||||
const polyBBox = [Infinity, Infinity, -Infinity, -Infinity];
|
||||
|
||||
const canonical = ctx.canonicalID();
|
||||
if (!canonical) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (polygonGeometry.type === 'Polygon') {
|
||||
const tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical);
|
||||
const tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical);
|
||||
if (!boxWithinBox(lineBBox, polyBBox)) return false;
|
||||
|
||||
for (const line of tileLines) {
|
||||
if (!lineStringWithinPolygon(line, tilePolygon)) return false;
|
||||
}
|
||||
}
|
||||
if (polygonGeometry.type === 'MultiPolygon') {
|
||||
const tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical);
|
||||
const tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical);
|
||||
if (!boxWithinBox(lineBBox, polyBBox)) return false;
|
||||
|
||||
for (const line of tileLines) {
|
||||
if (!lineStringWithinPolygons(line, tilePolygons)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class Within implements Expression {
|
||||
type: Type;
|
||||
geojson: GeoJSON
|
||||
geometries: GeoJSONPolygons;
|
||||
|
||||
constructor(geojson: GeoJSON, geometries: GeoJSONPolygons) {
|
||||
this.type = BooleanType;
|
||||
this.geojson = geojson;
|
||||
this.geometries = geometries;
|
||||
}
|
||||
|
||||
static parse(args: $ReadOnlyArray<mixed>, context: ParsingContext): ?Within {
|
||||
if (args.length !== 2)
|
||||
return context.error(`'within' expression requires exactly one argument, but found ${args.length - 1} instead.`);
|
||||
if (isValue(args[1])) {
|
||||
const geojson = (args[1]: Object);
|
||||
if (geojson.type === 'FeatureCollection') {
|
||||
for (let i = 0; i < geojson.features.length; ++i) {
|
||||
const type = geojson.features[i].geometry.type;
|
||||
if (type === 'Polygon' || type === 'MultiPolygon') {
|
||||
return new Within(geojson, geojson.features[i].geometry);
|
||||
}
|
||||
}
|
||||
} else if (geojson.type === 'Feature') {
|
||||
const type = geojson.geometry.type;
|
||||
if (type === 'Polygon' || type === 'MultiPolygon') {
|
||||
return new Within(geojson, geojson.geometry);
|
||||
}
|
||||
} else if (geojson.type === 'Polygon' || geojson.type === 'MultiPolygon') {
|
||||
return new Within(geojson, geojson);
|
||||
}
|
||||
}
|
||||
return context.error(`'within' expression requires valid geojson object that contains polygon geometry type.`);
|
||||
}
|
||||
|
||||
evaluate(ctx: EvaluationContext): boolean {
|
||||
if (ctx.geometry() != null && ctx.canonicalID() != null) {
|
||||
if (ctx.geometryType() === 'Point') {
|
||||
return pointsWithinPolygons(ctx, this.geometries);
|
||||
} else if (ctx.geometryType() === 'LineString') {
|
||||
return linesWithinPolygons(ctx, this.geometries);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
eachChild() {}
|
||||
|
||||
outputDefined(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
serialize(): SerializedExpression {
|
||||
return ["within", this.geojson];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Within;
|
||||
89
node_modules/@mapbox/mapbox-gl-style-spec/expression/evaluation_context.js
generated
vendored
Normal file
89
node_modules/@mapbox/mapbox-gl-style-spec/expression/evaluation_context.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// @flow
|
||||
|
||||
import {Color} from './values.js';
|
||||
|
||||
import type Point from '@mapbox/point-geometry';
|
||||
import type {FormattedSection} from './types/formatted.js';
|
||||
import type {GlobalProperties, Feature, FeatureState} from './index.js';
|
||||
import type {CanonicalTileID} from '../../source/tile_id.js';
|
||||
import type {FeatureDistanceData} from '../feature_filter/index.js';
|
||||
|
||||
const geometryTypes = ['Unknown', 'Point', 'LineString', 'Polygon'];
|
||||
|
||||
class EvaluationContext {
|
||||
globals: GlobalProperties;
|
||||
feature: ?Feature;
|
||||
featureState: ?FeatureState;
|
||||
formattedSection: ?FormattedSection;
|
||||
availableImages: ?Array<string>;
|
||||
canonical: null | CanonicalTileID;
|
||||
featureTileCoord: ?Point;
|
||||
featureDistanceData: ?FeatureDistanceData;
|
||||
|
||||
_parseColorCache: {[_: string]: ?Color};
|
||||
|
||||
constructor() {
|
||||
this.globals = (null: any);
|
||||
this.feature = null;
|
||||
this.featureState = null;
|
||||
this.formattedSection = null;
|
||||
this._parseColorCache = {};
|
||||
this.availableImages = null;
|
||||
this.canonical = null;
|
||||
this.featureTileCoord = null;
|
||||
this.featureDistanceData = null;
|
||||
}
|
||||
|
||||
id(): number | null {
|
||||
return this.feature && this.feature.id !== undefined ? this.feature.id : null;
|
||||
}
|
||||
|
||||
geometryType(): null | string {
|
||||
return this.feature ? typeof this.feature.type === 'number' ? geometryTypes[this.feature.type] : this.feature.type : null;
|
||||
}
|
||||
|
||||
geometry(): ?Array<Array<Point>> {
|
||||
return this.feature && 'geometry' in this.feature ? this.feature.geometry : null;
|
||||
}
|
||||
|
||||
canonicalID(): null | CanonicalTileID {
|
||||
return this.canonical;
|
||||
}
|
||||
|
||||
properties(): {[string]: any} {
|
||||
return (this.feature && this.feature.properties) || {};
|
||||
}
|
||||
|
||||
distanceFromCenter(): number {
|
||||
if (this.featureTileCoord && this.featureDistanceData) {
|
||||
|
||||
const c = this.featureDistanceData.center;
|
||||
const scale = this.featureDistanceData.scale;
|
||||
const {x, y} = this.featureTileCoord;
|
||||
|
||||
// Calculate the distance vector `d` (left handed)
|
||||
const dX = x * scale - c[0];
|
||||
const dY = y * scale - c[1];
|
||||
|
||||
// The bearing vector `b` (left handed)
|
||||
const bX = this.featureDistanceData.bearing[0];
|
||||
const bY = this.featureDistanceData.bearing[1];
|
||||
|
||||
// Distance is calculated as `dot(d, v)`
|
||||
const dist = (bX * dX + bY * dY);
|
||||
return dist;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
parseColor(input: string): ?Color {
|
||||
let cached = this._parseColorCache[input];
|
||||
if (!cached) {
|
||||
cached = this._parseColorCache[input] = Color.parse(input);
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
export default EvaluationContext;
|
||||
27
node_modules/@mapbox/mapbox-gl-style-spec/expression/expression.js
generated
vendored
Normal file
27
node_modules/@mapbox/mapbox-gl-style-spec/expression/expression.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// @flow
|
||||
|
||||
import type {Type} from './types.js';
|
||||
import type ParsingContext from './parsing_context.js';
|
||||
import type EvaluationContext from './evaluation_context.js';
|
||||
|
||||
export type SerializedExpression = Array<mixed> | Array<string> | string | number | boolean | null;
|
||||
|
||||
export interface Expression {
|
||||
+type: Type;
|
||||
|
||||
evaluate(ctx: EvaluationContext): any;
|
||||
|
||||
eachChild(fn: Expression => void): void;
|
||||
|
||||
/**
|
||||
* Statically analyze the expression, attempting to enumerate possible outputs. Returns
|
||||
* false if the complete set of outputs is statically undecidable, otherwise true.
|
||||
*/
|
||||
outputDefined(): boolean;
|
||||
|
||||
serialize(): SerializedExpression;
|
||||
}
|
||||
|
||||
export type ExpressionParser = (args: $ReadOnlyArray<mixed>, context: ParsingContext) => ?Expression;
|
||||
export type ExpressionRegistration = Class<Expression> & { +parse: ExpressionParser };
|
||||
export type ExpressionRegistry = {[_: string]: ExpressionRegistration};
|
||||
399
node_modules/@mapbox/mapbox-gl-style-spec/expression/index.js
generated
vendored
Normal file
399
node_modules/@mapbox/mapbox-gl-style-spec/expression/index.js
generated
vendored
Normal file
@@ -0,0 +1,399 @@
|
||||
// @flow
|
||||
|
||||
import assert from 'assert';
|
||||
|
||||
import extend from '../util/extend.js';
|
||||
import ParsingError from './parsing_error.js';
|
||||
import ParsingContext from './parsing_context.js';
|
||||
import EvaluationContext from './evaluation_context.js';
|
||||
import CompoundExpression from './compound_expression.js';
|
||||
import Step from './definitions/step.js';
|
||||
import Interpolate from './definitions/interpolate.js';
|
||||
import Coalesce from './definitions/coalesce.js';
|
||||
import Let from './definitions/let.js';
|
||||
import definitions from './definitions/index.js';
|
||||
import * as isConstant from './is_constant.js';
|
||||
import RuntimeError from './runtime_error.js';
|
||||
import {success, error} from '../util/result.js';
|
||||
import {supportsPropertyExpression, supportsZoomExpression, supportsInterpolation} from '../util/properties.js';
|
||||
|
||||
import type {Type, EvaluationKind} from './types.js';
|
||||
import type {Value} from './values.js';
|
||||
import type {Expression} from './expression.js';
|
||||
import type {StylePropertySpecification} from '../style-spec.js';
|
||||
import type {Result} from '../util/result.js';
|
||||
import type {InterpolationType} from './definitions/interpolate.js';
|
||||
import type {PropertyValueSpecification} from '../types.js';
|
||||
import type {FormattedSection} from './types/formatted.js';
|
||||
import type Point from '@mapbox/point-geometry';
|
||||
import type {CanonicalTileID} from '../../source/tile_id.js';
|
||||
import type {FeatureDistanceData} from '../feature_filter/index.js';
|
||||
|
||||
export type Feature = {
|
||||
+type: 1 | 2 | 3 | 'Unknown' | 'Point' | 'LineString' | 'Polygon',
|
||||
+id?: number | null,
|
||||
+properties: {[_: string]: any},
|
||||
+patterns?: {[_: string]: string},
|
||||
+geometry?: Array<Array<Point>>
|
||||
};
|
||||
|
||||
export type FeatureState = {[_: string]: any};
|
||||
|
||||
export type GlobalProperties = $ReadOnly<{
|
||||
zoom: number,
|
||||
pitch?: number,
|
||||
heatmapDensity?: number,
|
||||
lineProgress?: number,
|
||||
skyRadialProgress?: number,
|
||||
isSupportedScript?: (_: string) => boolean,
|
||||
accumulated?: Value
|
||||
}>;
|
||||
|
||||
export class StyleExpression {
|
||||
expression: Expression;
|
||||
|
||||
_evaluator: EvaluationContext;
|
||||
_defaultValue: Value;
|
||||
_warningHistory: {[key: string]: boolean};
|
||||
_enumValues: ?{[_: string]: any};
|
||||
|
||||
constructor(expression: Expression, propertySpec: ?StylePropertySpecification) {
|
||||
this.expression = expression;
|
||||
this._warningHistory = {};
|
||||
this._evaluator = new EvaluationContext();
|
||||
this._defaultValue = propertySpec ? getDefaultValue(propertySpec) : null;
|
||||
this._enumValues = propertySpec && propertySpec.type === 'enum' ? propertySpec.values : null;
|
||||
}
|
||||
|
||||
evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection, featureTileCoord?: Point, featureDistanceData?: FeatureDistanceData): any {
|
||||
this._evaluator.globals = globals;
|
||||
this._evaluator.feature = feature;
|
||||
this._evaluator.featureState = featureState;
|
||||
this._evaluator.canonical = canonical || null;
|
||||
this._evaluator.availableImages = availableImages || null;
|
||||
this._evaluator.formattedSection = formattedSection;
|
||||
this._evaluator.featureTileCoord = featureTileCoord || null;
|
||||
this._evaluator.featureDistanceData = featureDistanceData || null;
|
||||
|
||||
return this.expression.evaluate(this._evaluator);
|
||||
}
|
||||
|
||||
evaluate(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection, featureTileCoord?: Point, featureDistanceData?: FeatureDistanceData): any {
|
||||
this._evaluator.globals = globals;
|
||||
this._evaluator.feature = feature || null;
|
||||
this._evaluator.featureState = featureState || null;
|
||||
this._evaluator.canonical = canonical || null;
|
||||
this._evaluator.availableImages = availableImages || null;
|
||||
this._evaluator.formattedSection = formattedSection || null;
|
||||
this._evaluator.featureTileCoord = featureTileCoord || null;
|
||||
this._evaluator.featureDistanceData = featureDistanceData || null;
|
||||
|
||||
try {
|
||||
const val = this.expression.evaluate(this._evaluator);
|
||||
// eslint-disable-next-line no-self-compare
|
||||
if (val === null || val === undefined || (typeof val === 'number' && val !== val)) {
|
||||
return this._defaultValue;
|
||||
}
|
||||
if (this._enumValues && !(val in this._enumValues)) {
|
||||
throw new RuntimeError(`Expected value to be one of ${Object.keys(this._enumValues).map(v => JSON.stringify(v)).join(', ')}, but found ${JSON.stringify(val)} instead.`);
|
||||
}
|
||||
return val;
|
||||
} catch (e) {
|
||||
if (!this._warningHistory[e.message]) {
|
||||
this._warningHistory[e.message] = true;
|
||||
if (typeof console !== 'undefined') {
|
||||
console.warn(e.message);
|
||||
}
|
||||
}
|
||||
return this._defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isExpression(expression: mixed): boolean {
|
||||
return Array.isArray(expression) && expression.length > 0 &&
|
||||
typeof expression[0] === 'string' && expression[0] in definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and typecheck the given style spec JSON expression. If
|
||||
* options.defaultValue is provided, then the resulting StyleExpression's
|
||||
* `evaluate()` method will handle errors by logging a warning (once per
|
||||
* message) and returning the default value. Otherwise, it will throw
|
||||
* evaluation errors.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
export function createExpression(expression: mixed, propertySpec: ?StylePropertySpecification): Result<StyleExpression, Array<ParsingError>> {
|
||||
const parser = new ParsingContext(definitions, [], propertySpec ? getExpectedType(propertySpec) : undefined);
|
||||
|
||||
// For string-valued properties, coerce to string at the top level rather than asserting.
|
||||
const parsed = parser.parse(expression, undefined, undefined, undefined,
|
||||
propertySpec && propertySpec.type === 'string' ? {typeAnnotation: 'coerce'} : undefined);
|
||||
|
||||
if (!parsed) {
|
||||
assert(parser.errors.length > 0);
|
||||
return error(parser.errors);
|
||||
}
|
||||
|
||||
return success(new StyleExpression(parsed, propertySpec));
|
||||
}
|
||||
|
||||
export class ZoomConstantExpression<Kind: EvaluationKind> {
|
||||
kind: Kind;
|
||||
isStateDependent: boolean;
|
||||
_styleExpression: StyleExpression;
|
||||
|
||||
constructor(kind: Kind, expression: StyleExpression) {
|
||||
this.kind = kind;
|
||||
this._styleExpression = expression;
|
||||
this.isStateDependent = kind !== ('constant': EvaluationKind) && !isConstant.isStateConstant(expression.expression);
|
||||
}
|
||||
|
||||
evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection): any {
|
||||
return this._styleExpression.evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection);
|
||||
}
|
||||
|
||||
evaluate(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection): any {
|
||||
return this._styleExpression.evaluate(globals, feature, featureState, canonical, availableImages, formattedSection);
|
||||
}
|
||||
}
|
||||
|
||||
export class ZoomDependentExpression<Kind: EvaluationKind> {
|
||||
kind: Kind;
|
||||
zoomStops: Array<number>;
|
||||
isStateDependent: boolean;
|
||||
|
||||
_styleExpression: StyleExpression;
|
||||
interpolationType: ?InterpolationType;
|
||||
|
||||
constructor(kind: Kind, expression: StyleExpression, zoomStops: Array<number>, interpolationType?: InterpolationType) {
|
||||
this.kind = kind;
|
||||
this.zoomStops = zoomStops;
|
||||
this._styleExpression = expression;
|
||||
this.isStateDependent = kind !== ('camera': EvaluationKind) && !isConstant.isStateConstant(expression.expression);
|
||||
this.interpolationType = interpolationType;
|
||||
}
|
||||
|
||||
evaluateWithoutErrorHandling(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection): any {
|
||||
return this._styleExpression.evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection);
|
||||
}
|
||||
|
||||
evaluate(globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection): any {
|
||||
return this._styleExpression.evaluate(globals, feature, featureState, canonical, availableImages, formattedSection);
|
||||
}
|
||||
|
||||
interpolationFactor(input: number, lower: number, upper: number): number {
|
||||
if (this.interpolationType) {
|
||||
return Interpolate.interpolationFactor(this.interpolationType, input, lower, upper);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type ConstantExpression = {
|
||||
kind: 'constant',
|
||||
+evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>) => any,
|
||||
}
|
||||
|
||||
export type SourceExpression = {
|
||||
kind: 'source',
|
||||
isStateDependent: boolean,
|
||||
+evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection) => any,
|
||||
};
|
||||
|
||||
export type CameraExpression = {
|
||||
kind: 'camera',
|
||||
+evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>) => any,
|
||||
+interpolationFactor: (input: number, lower: number, upper: number) => number,
|
||||
zoomStops: Array<number>,
|
||||
interpolationType: ?InterpolationType
|
||||
};
|
||||
|
||||
export type CompositeExpression = {
|
||||
kind: 'composite',
|
||||
isStateDependent: boolean,
|
||||
+evaluate: (globals: GlobalProperties, feature?: Feature, featureState?: FeatureState, canonical?: CanonicalTileID, availableImages?: Array<string>, formattedSection?: FormattedSection) => any,
|
||||
+interpolationFactor: (input: number, lower: number, upper: number) => number,
|
||||
zoomStops: Array<number>,
|
||||
interpolationType: ?InterpolationType
|
||||
};
|
||||
|
||||
export type StylePropertyExpression =
|
||||
| ConstantExpression
|
||||
| SourceExpression
|
||||
| CameraExpression
|
||||
| CompositeExpression;
|
||||
|
||||
export function createPropertyExpression(expression: mixed, propertySpec: StylePropertySpecification): Result<StylePropertyExpression, Array<ParsingError>> {
|
||||
expression = createExpression(expression, propertySpec);
|
||||
if (expression.result === 'error') {
|
||||
return expression;
|
||||
}
|
||||
|
||||
const parsed = expression.value.expression;
|
||||
|
||||
const isFeatureConstant = isConstant.isFeatureConstant(parsed);
|
||||
if (!isFeatureConstant && !supportsPropertyExpression(propertySpec)) {
|
||||
return error([new ParsingError('', 'data expressions not supported')]);
|
||||
}
|
||||
|
||||
const isZoomConstant = isConstant.isGlobalPropertyConstant(parsed, ['zoom', 'pitch', 'distance-from-center']);
|
||||
if (!isZoomConstant && !supportsZoomExpression(propertySpec)) {
|
||||
return error([new ParsingError('', 'zoom expressions not supported')]);
|
||||
}
|
||||
|
||||
const zoomCurve = findZoomCurve(parsed);
|
||||
if (!zoomCurve && !isZoomConstant) {
|
||||
return error([new ParsingError('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.')]);
|
||||
} else if (zoomCurve instanceof ParsingError) {
|
||||
return error([zoomCurve]);
|
||||
} else if (zoomCurve instanceof Interpolate && !supportsInterpolation(propertySpec)) {
|
||||
return error([new ParsingError('', '"interpolate" expressions cannot be used with this property')]);
|
||||
}
|
||||
|
||||
if (!zoomCurve) {
|
||||
return success(isFeatureConstant ?
|
||||
(new ZoomConstantExpression('constant', expression.value): ConstantExpression) :
|
||||
(new ZoomConstantExpression('source', expression.value): SourceExpression));
|
||||
}
|
||||
|
||||
const interpolationType = zoomCurve instanceof Interpolate ? zoomCurve.interpolation : undefined;
|
||||
|
||||
return success(isFeatureConstant ?
|
||||
(new ZoomDependentExpression('camera', expression.value, zoomCurve.labels, interpolationType): CameraExpression) :
|
||||
(new ZoomDependentExpression('composite', expression.value, zoomCurve.labels, interpolationType): CompositeExpression));
|
||||
}
|
||||
|
||||
import {isFunction, createFunction} from '../function/index.js';
|
||||
import {Color} from './values.js';
|
||||
|
||||
// serialization wrapper for old-style stop functions normalized to the
|
||||
// expression interface
|
||||
export class StylePropertyFunction<T> {
|
||||
_parameters: PropertyValueSpecification<T>;
|
||||
_specification: StylePropertySpecification;
|
||||
|
||||
kind: EvaluationKind;
|
||||
evaluate: (globals: GlobalProperties, feature?: Feature) => any;
|
||||
interpolationFactor: ?(input: number, lower: number, upper: number) => number;
|
||||
zoomStops: ?Array<number>;
|
||||
|
||||
constructor(parameters: PropertyValueSpecification<T>, specification: StylePropertySpecification) {
|
||||
this._parameters = parameters;
|
||||
this._specification = specification;
|
||||
extend(this, createFunction(this._parameters, this._specification));
|
||||
}
|
||||
|
||||
static deserialize(serialized: {_parameters: PropertyValueSpecification<T>, _specification: StylePropertySpecification}): StylePropertyFunction<T> {
|
||||
return new StylePropertyFunction(serialized._parameters, serialized._specification);
|
||||
}
|
||||
|
||||
static serialize(input: StylePropertyFunction<T>): {_parameters: PropertyValueSpecification<T>, _specification: StylePropertySpecification} {
|
||||
return {
|
||||
_parameters: input._parameters,
|
||||
_specification: input._specification
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizePropertyExpression<T>(value: PropertyValueSpecification<T>, specification: StylePropertySpecification): StylePropertyExpression {
|
||||
if (isFunction(value)) {
|
||||
return (new StylePropertyFunction(value, specification): any);
|
||||
|
||||
} else if (isExpression(value)) {
|
||||
const expression = createPropertyExpression(value, specification);
|
||||
if (expression.result === 'error') {
|
||||
// this should have been caught in validation
|
||||
throw new Error(expression.value.map(err => `${err.key}: ${err.message}`).join(', '));
|
||||
}
|
||||
return expression.value;
|
||||
|
||||
} else {
|
||||
let constant: any = value;
|
||||
if (typeof value === 'string' && specification.type === 'color') {
|
||||
constant = Color.parse(value);
|
||||
}
|
||||
return {
|
||||
kind: 'constant',
|
||||
evaluate: () => constant
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Zoom-dependent expressions may only use ["zoom"] as the input to a top-level "step" or "interpolate"
|
||||
// expression (collectively referred to as a "curve"). The curve may be wrapped in one or more "let" or
|
||||
// "coalesce" expressions.
|
||||
function findZoomCurve(expression: Expression): Step | Interpolate | ParsingError | null {
|
||||
let result = null;
|
||||
if (expression instanceof Let) {
|
||||
result = findZoomCurve(expression.result);
|
||||
|
||||
} else if (expression instanceof Coalesce) {
|
||||
for (const arg of expression.args) {
|
||||
result = findZoomCurve(arg);
|
||||
if (result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else if ((expression instanceof Step || expression instanceof Interpolate) &&
|
||||
expression.input instanceof CompoundExpression &&
|
||||
expression.input.name === 'zoom') {
|
||||
|
||||
result = expression;
|
||||
}
|
||||
|
||||
if (result instanceof ParsingError) {
|
||||
return result;
|
||||
}
|
||||
|
||||
expression.eachChild((child) => {
|
||||
const childResult = findZoomCurve(child);
|
||||
if (childResult instanceof ParsingError) {
|
||||
result = childResult;
|
||||
} else if (!result && childResult) {
|
||||
result = new ParsingError('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.');
|
||||
} else if (result && childResult && result !== childResult) {
|
||||
result = new ParsingError('', 'Only one zoom-based "step" or "interpolate" subexpression may be used in an expression.');
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
import {ColorType, StringType, NumberType, BooleanType, ValueType, FormattedType, ResolvedImageType, array} from './types.js';
|
||||
|
||||
function getExpectedType(spec: StylePropertySpecification): Type {
|
||||
const types = {
|
||||
color: ColorType,
|
||||
string: StringType,
|
||||
number: NumberType,
|
||||
enum: StringType,
|
||||
boolean: BooleanType,
|
||||
formatted: FormattedType,
|
||||
resolvedImage: ResolvedImageType
|
||||
};
|
||||
|
||||
if (spec.type === 'array') {
|
||||
return array(types[spec.value] || ValueType, spec.length);
|
||||
}
|
||||
|
||||
return types[spec.type];
|
||||
}
|
||||
|
||||
function getDefaultValue(spec: StylePropertySpecification): Value {
|
||||
if (spec.type === 'color' && (isFunction(spec.default) || Array.isArray(spec.default))) {
|
||||
// Special case for heatmap-color: it uses the 'default:' to define a
|
||||
// default color ramp, but createExpression expects a simple value to fall
|
||||
// back to in case of runtime errors
|
||||
return new Color(0, 0, 0, 0);
|
||||
} else if (spec.type === 'color') {
|
||||
return Color.parse(spec.default) || null;
|
||||
} else if (spec.default === undefined) {
|
||||
return null;
|
||||
} else {
|
||||
return spec.default;
|
||||
}
|
||||
}
|
||||
59
node_modules/@mapbox/mapbox-gl-style-spec/expression/is_constant.js
generated
vendored
Normal file
59
node_modules/@mapbox/mapbox-gl-style-spec/expression/is_constant.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// @flow
|
||||
|
||||
import CompoundExpression from './compound_expression.js';
|
||||
import Within from './definitions/within.js';
|
||||
import type {Expression} from './expression.js';
|
||||
|
||||
function isFeatureConstant(e: Expression): boolean {
|
||||
if (e instanceof CompoundExpression) {
|
||||
if (e.name === 'get' && e.args.length === 1) {
|
||||
return false;
|
||||
} else if (e.name === 'feature-state') {
|
||||
return false;
|
||||
} else if (e.name === 'has' && e.args.length === 1) {
|
||||
return false;
|
||||
} else if (
|
||||
e.name === 'properties' ||
|
||||
e.name === 'geometry-type' ||
|
||||
e.name === 'id'
|
||||
) {
|
||||
return false;
|
||||
} else if (/^filter-/.test(e.name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (e instanceof Within) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let result = true;
|
||||
e.eachChild(arg => {
|
||||
if (result && !isFeatureConstant(arg)) { result = false; }
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function isStateConstant(e: Expression): boolean {
|
||||
if (e instanceof CompoundExpression) {
|
||||
if (e.name === 'feature-state') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let result = true;
|
||||
e.eachChild(arg => {
|
||||
if (result && !isStateConstant(arg)) { result = false; }
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function isGlobalPropertyConstant(e: Expression, properties: Array<string>): boolean {
|
||||
if (e instanceof CompoundExpression && properties.indexOf(e.name) >= 0) { return false; }
|
||||
let result = true;
|
||||
e.eachChild((arg) => {
|
||||
if (result && !isGlobalPropertyConstant(arg, properties)) { result = false; }
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
export {isFeatureConstant, isGlobalPropertyConstant, isStateConstant};
|
||||
233
node_modules/@mapbox/mapbox-gl-style-spec/expression/parsing_context.js
generated
vendored
Normal file
233
node_modules/@mapbox/mapbox-gl-style-spec/expression/parsing_context.js
generated
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
// @flow
|
||||
|
||||
import Scope from './scope.js';
|
||||
import {checkSubtype} from './types.js';
|
||||
import ParsingError from './parsing_error.js';
|
||||
import Literal from './definitions/literal.js';
|
||||
import Assertion from './definitions/assertion.js';
|
||||
import Coercion from './definitions/coercion.js';
|
||||
import EvaluationContext from './evaluation_context.js';
|
||||
import CompoundExpression from './compound_expression.js';
|
||||
import CollatorExpression from './definitions/collator.js';
|
||||
import Within from './definitions/within.js';
|
||||
import {isGlobalPropertyConstant, isFeatureConstant} from './is_constant.js';
|
||||
import Var from './definitions/var.js';
|
||||
|
||||
import type {Expression, ExpressionRegistry} from './expression.js';
|
||||
import type {Type} from './types.js';
|
||||
|
||||
/**
|
||||
* State associated parsing at a given point in an expression tree.
|
||||
* @private
|
||||
*/
|
||||
class ParsingContext {
|
||||
registry: ExpressionRegistry;
|
||||
path: Array<number>;
|
||||
key: string;
|
||||
scope: Scope;
|
||||
errors: Array<ParsingError>;
|
||||
|
||||
// The expected type of this expression. Provided only to allow Expression
|
||||
// implementations to infer argument types: Expression#parse() need not
|
||||
// check that the output type of the parsed expression matches
|
||||
// `expectedType`.
|
||||
expectedType: ?Type;
|
||||
|
||||
constructor(
|
||||
registry: ExpressionRegistry,
|
||||
path: Array<number> = [],
|
||||
expectedType: ?Type,
|
||||
scope: Scope = new Scope(),
|
||||
errors: Array<ParsingError> = []
|
||||
) {
|
||||
this.registry = registry;
|
||||
this.path = path;
|
||||
this.key = path.map(part => `[${part}]`).join('');
|
||||
this.scope = scope;
|
||||
this.errors = errors;
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param expr the JSON expression to parse
|
||||
* @param index the optional argument index if this expression is an argument of a parent expression that's being parsed
|
||||
* @param options
|
||||
* @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.
|
||||
* @private
|
||||
*/
|
||||
parse(
|
||||
expr: mixed,
|
||||
index?: number,
|
||||
expectedType?: ?Type,
|
||||
bindings?: Array<[string, Expression]>,
|
||||
options: {typeAnnotation?: 'assert' | 'coerce' | 'omit'} = {}
|
||||
): ?Expression {
|
||||
if (index) {
|
||||
return this.concat(index, expectedType, bindings)._parse(expr, options);
|
||||
}
|
||||
return this._parse(expr, options);
|
||||
}
|
||||
|
||||
_parse(expr: mixed, options: {typeAnnotation?: 'assert' | 'coerce' | 'omit'}): ?Expression {
|
||||
if (expr === null || typeof expr === 'string' || typeof expr === 'boolean' || typeof expr === 'number') {
|
||||
expr = ['literal', expr];
|
||||
}
|
||||
|
||||
function annotate(parsed, type, typeAnnotation: 'assert' | 'coerce' | 'omit') {
|
||||
if (typeAnnotation === 'assert') {
|
||||
return new Assertion(type, [parsed]);
|
||||
} else if (typeAnnotation === 'coerce') {
|
||||
return new Coercion(type, [parsed]);
|
||||
} else {
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(expr)) {
|
||||
if (expr.length === 0) {
|
||||
return this.error(`Expected an array with at least one element. If you wanted a literal array, use ["literal", []].`);
|
||||
}
|
||||
|
||||
const op = expr[0];
|
||||
if (typeof op !== 'string') {
|
||||
this.error(`Expression name must be a string, but found ${typeof op} instead. If you wanted a literal array, use ["literal", [...]].`, 0);
|
||||
return null;
|
||||
}
|
||||
|
||||
const Expr = this.registry[op];
|
||||
if (Expr) {
|
||||
let parsed = Expr.parse(expr, this);
|
||||
if (!parsed) return null;
|
||||
|
||||
if (this.expectedType) {
|
||||
const expected = this.expectedType;
|
||||
const actual = parsed.type;
|
||||
|
||||
// When we expect a number, string, boolean, or array but have a value, wrap it in an assertion.
|
||||
// When we expect a color or formatted string, but have a string or value, wrap it in a coercion.
|
||||
// Otherwise, we do static type-checking.
|
||||
//
|
||||
// These behaviors are overridable for:
|
||||
// * The "coalesce" operator, which needs to omit type annotations.
|
||||
// * String-valued properties (e.g. `text-field`), where coercion is more convenient than assertion.
|
||||
//
|
||||
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');
|
||||
} else if ((expected.kind === 'color' || expected.kind === 'formatted' || expected.kind === 'resolvedImage') && (actual.kind === 'value' || actual.kind === 'string')) {
|
||||
parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce');
|
||||
} else if (this.checkSubtype(expected, actual)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// If an expression's arguments are all literals, we can evaluate
|
||||
// it immediately and replace it with a literal value in the
|
||||
// parsed/compiled result. Expressions that expect an image should
|
||||
// not be resolved here so we can later get the available images.
|
||||
if (!(parsed instanceof Literal) && (parsed.type.kind !== 'resolvedImage') && isConstant(parsed)) {
|
||||
const ec = new EvaluationContext();
|
||||
try {
|
||||
parsed = new Literal(parsed.type, parsed.evaluate(ec));
|
||||
} catch (e) {
|
||||
this.error(e.message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
return this.error(`Unknown expression "${op}". If you wanted a literal array, use ["literal", [...]].`, 0);
|
||||
} else if (typeof expr === 'undefined') {
|
||||
return this.error(`'undefined' value invalid. Use null instead.`);
|
||||
} else if (typeof expr === 'object') {
|
||||
return this.error(`Bare objects invalid. Use ["literal", {...}] instead.`);
|
||||
} else {
|
||||
return this.error(`Expected an array, but found ${typeof expr} instead.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this context suitable for parsing the subexpression at
|
||||
* index `index`, optionally appending to 'let' binding map.
|
||||
*
|
||||
* Note that `errors` property, intended for collecting errors while
|
||||
* parsing, is copied by reference rather than cloned.
|
||||
* @private
|
||||
*/
|
||||
concat(index: number, expectedType?: ?Type, bindings?: Array<[string, Expression]>): ParsingContext {
|
||||
const path = typeof index === 'number' ? this.path.concat(index) : this.path;
|
||||
const scope = bindings ? this.scope.concat(bindings) : this.scope;
|
||||
return new ParsingContext(
|
||||
this.registry,
|
||||
path,
|
||||
expectedType || null,
|
||||
scope,
|
||||
this.errors
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a parsing (or type checking) error into the `this.errors`
|
||||
* @param error The message
|
||||
* @param keys Optionally specify the source of the error at a child
|
||||
* of the current expression at `this.key`.
|
||||
* @private
|
||||
*/
|
||||
error(error: string, ...keys: Array<number>) {
|
||||
const key = `${this.key}${keys.map(k => `[${k}]`).join('')}`;
|
||||
this.errors.push(new ParsingError(key, error));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns null if `t` is a subtype of `expected`; otherwise returns an
|
||||
* error message and also pushes it to `this.errors`.
|
||||
*/
|
||||
checkSubtype(expected: Type, t: Type): ?string {
|
||||
const error = checkSubtype(expected, t);
|
||||
if (error) this.error(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
export default ParsingContext;
|
||||
|
||||
function isConstant(expression: Expression) {
|
||||
if (expression instanceof Var) {
|
||||
return isConstant(expression.boundExpression);
|
||||
} else if (expression instanceof CompoundExpression && expression.name === 'error') {
|
||||
return false;
|
||||
} else if (expression instanceof CollatorExpression) {
|
||||
// Although the results of a Collator expression with fixed arguments
|
||||
// generally shouldn't change between executions, we can't serialize them
|
||||
// as constant expressions because results change based on environment.
|
||||
return false;
|
||||
} else if (expression instanceof Within) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const isTypeAnnotation = expression instanceof Coercion ||
|
||||
expression instanceof Assertion;
|
||||
|
||||
let childrenConstant = true;
|
||||
expression.eachChild(child => {
|
||||
// We can _almost_ assume that if `expressions` children are constant,
|
||||
// they would already have been evaluated to Literal values when they
|
||||
// were parsed. Type annotations are the exception, because they might
|
||||
// have been inferred and added after a child was parsed.
|
||||
|
||||
// So we recurse into isConstant() for the children of type annotations,
|
||||
// but otherwise simply check whether they are Literals.
|
||||
if (isTypeAnnotation) {
|
||||
childrenConstant = childrenConstant && isConstant(child);
|
||||
} else {
|
||||
childrenConstant = childrenConstant && child instanceof Literal;
|
||||
}
|
||||
});
|
||||
if (!childrenConstant) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isFeatureConstant(expression) &&
|
||||
isGlobalPropertyConstant(expression, ['zoom', 'heatmap-density', 'line-progress', 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch', 'distance-from-center']);
|
||||
}
|
||||
13
node_modules/@mapbox/mapbox-gl-style-spec/expression/parsing_error.js
generated
vendored
Normal file
13
node_modules/@mapbox/mapbox-gl-style-spec/expression/parsing_error.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// @flow
|
||||
|
||||
class ParsingError extends Error {
|
||||
key: string;
|
||||
message: string;
|
||||
constructor(key: string, message: string) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
export default ParsingError;
|
||||
17
node_modules/@mapbox/mapbox-gl-style-spec/expression/runtime_error.js
generated
vendored
Normal file
17
node_modules/@mapbox/mapbox-gl-style-spec/expression/runtime_error.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// @flow
|
||||
|
||||
class RuntimeError {
|
||||
name: string;
|
||||
message: string;
|
||||
|
||||
constructor(message: string) {
|
||||
this.name = 'ExpressionEvaluationError';
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
toJSON(): string {
|
||||
return this.message;
|
||||
}
|
||||
}
|
||||
|
||||
export default RuntimeError;
|
||||
36
node_modules/@mapbox/mapbox-gl-style-spec/expression/scope.js
generated
vendored
Normal file
36
node_modules/@mapbox/mapbox-gl-style-spec/expression/scope.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// @flow
|
||||
|
||||
import type {Expression} from './expression.js';
|
||||
|
||||
/**
|
||||
* Tracks `let` bindings during expression parsing.
|
||||
* @private
|
||||
*/
|
||||
class Scope {
|
||||
parent: ?Scope;
|
||||
bindings: {[_: string]: Expression};
|
||||
constructor(parent?: Scope, bindings: Array<[string, Expression]> = []) {
|
||||
this.parent = parent;
|
||||
this.bindings = {};
|
||||
for (const [name, expression] of bindings) {
|
||||
this.bindings[name] = expression;
|
||||
}
|
||||
}
|
||||
|
||||
concat(bindings: Array<[string, Expression]>): Scope {
|
||||
return new Scope(this, bindings);
|
||||
}
|
||||
|
||||
get(name: string): Expression {
|
||||
if (this.bindings[name]) { return this.bindings[name]; }
|
||||
if (this.parent) { return this.parent.get(name); }
|
||||
throw new Error(`${name} not found in scope.`);
|
||||
}
|
||||
|
||||
has(name: string): boolean {
|
||||
if (this.bindings[name]) return true;
|
||||
return this.parent ? this.parent.has(name) : false;
|
||||
}
|
||||
}
|
||||
|
||||
export default Scope;
|
||||
39
node_modules/@mapbox/mapbox-gl-style-spec/expression/stops.js
generated
vendored
Normal file
39
node_modules/@mapbox/mapbox-gl-style-spec/expression/stops.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// @flow
|
||||
|
||||
import RuntimeError from './runtime_error.js';
|
||||
|
||||
import type {Expression} from './expression.js';
|
||||
|
||||
export type Stops = Array<[number, Expression]>;
|
||||
|
||||
/**
|
||||
* Returns the index of the last stop <= input, or 0 if it doesn't exist.
|
||||
* @private
|
||||
*/
|
||||
export function findStopLessThanOrEqualTo(stops: Array<number>, input: number): number {
|
||||
const lastIndex = stops.length - 1;
|
||||
let lowerIndex = 0;
|
||||
let upperIndex = lastIndex;
|
||||
let currentIndex = 0;
|
||||
let currentValue, nextValue;
|
||||
|
||||
while (lowerIndex <= upperIndex) {
|
||||
currentIndex = Math.floor((lowerIndex + upperIndex) / 2);
|
||||
currentValue = stops[currentIndex];
|
||||
nextValue = stops[currentIndex + 1];
|
||||
|
||||
if (currentValue <= input) {
|
||||
if (currentIndex === lastIndex || input < nextValue) { // Search complete
|
||||
return currentIndex;
|
||||
}
|
||||
|
||||
lowerIndex = currentIndex + 1;
|
||||
} else if (currentValue > input) {
|
||||
upperIndex = currentIndex - 1;
|
||||
} else {
|
||||
throw new RuntimeError('Input is not a number.');
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
126
node_modules/@mapbox/mapbox-gl-style-spec/expression/types.js
generated
vendored
Normal file
126
node_modules/@mapbox/mapbox-gl-style-spec/expression/types.js
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
// @flow
|
||||
|
||||
export type NullTypeT = { kind: 'null' };
|
||||
export type NumberTypeT = { kind: 'number' };
|
||||
export type StringTypeT = { kind: 'string' };
|
||||
export type BooleanTypeT = { kind: 'boolean' };
|
||||
export type ColorTypeT = { kind: 'color' };
|
||||
export type ObjectTypeT = { kind: 'object' };
|
||||
export type ValueTypeT = { kind: 'value' };
|
||||
export type ErrorTypeT = { kind: 'error' };
|
||||
export type CollatorTypeT = { kind: 'collator' };
|
||||
export type FormattedTypeT = { kind: 'formatted' };
|
||||
export type ResolvedImageTypeT = { kind: 'resolvedImage' };
|
||||
|
||||
export type EvaluationKind = 'constant' | 'source' | 'camera' | 'composite';
|
||||
|
||||
export type Type =
|
||||
NullTypeT |
|
||||
NumberTypeT |
|
||||
StringTypeT |
|
||||
BooleanTypeT |
|
||||
ColorTypeT |
|
||||
ObjectTypeT |
|
||||
ValueTypeT |
|
||||
ArrayType | // eslint-disable-line no-use-before-define
|
||||
ErrorTypeT |
|
||||
CollatorTypeT |
|
||||
FormattedTypeT |
|
||||
ResolvedImageTypeT
|
||||
|
||||
export type ArrayType = {
|
||||
kind: 'array',
|
||||
itemType: Type,
|
||||
N: ?number
|
||||
}
|
||||
|
||||
export type NativeType = 'number' | 'string' | 'boolean' | 'null' | 'array' | 'object'
|
||||
|
||||
export const NullType = {kind: 'null'};
|
||||
export const NumberType = {kind: 'number'};
|
||||
export const StringType = {kind: 'string'};
|
||||
export const BooleanType = {kind: 'boolean'};
|
||||
export const ColorType = {kind: 'color'};
|
||||
export const ObjectType = {kind: 'object'};
|
||||
export const ValueType = {kind: 'value'};
|
||||
export const ErrorType = {kind: 'error'};
|
||||
export const CollatorType = {kind: 'collator'};
|
||||
export const FormattedType = {kind: 'formatted'};
|
||||
export const ResolvedImageType = {kind: 'resolvedImage'};
|
||||
|
||||
export function array(itemType: Type, N: ?number): ArrayType {
|
||||
return {
|
||||
kind: 'array',
|
||||
itemType,
|
||||
N
|
||||
};
|
||||
}
|
||||
|
||||
export function toString(type: Type): string {
|
||||
if (type.kind === 'array') {
|
||||
const itemType = toString(type.itemType);
|
||||
return typeof type.N === 'number' ?
|
||||
`array<${itemType}, ${type.N}>` :
|
||||
type.itemType.kind === 'value' ? 'array' : `array<${itemType}>`;
|
||||
} else {
|
||||
return type.kind;
|
||||
}
|
||||
}
|
||||
|
||||
const valueMemberTypes = [
|
||||
NullType,
|
||||
NumberType,
|
||||
StringType,
|
||||
BooleanType,
|
||||
ColorType,
|
||||
FormattedType,
|
||||
ObjectType,
|
||||
array(ValueType),
|
||||
ResolvedImageType
|
||||
];
|
||||
|
||||
/**
|
||||
* Returns null if `t` is a subtype of `expected`; otherwise returns an
|
||||
* error message.
|
||||
* @private
|
||||
*/
|
||||
export function checkSubtype(expected: Type, t: Type): ?string {
|
||||
if (t.kind === 'error') {
|
||||
// Error is a subtype of every type
|
||||
return null;
|
||||
} else if (expected.kind === 'array') {
|
||||
if (t.kind === 'array' &&
|
||||
((t.N === 0 && t.itemType.kind === 'value') || !checkSubtype(expected.itemType, t.itemType)) &&
|
||||
(typeof expected.N !== 'number' || expected.N === t.N)) {
|
||||
return null;
|
||||
}
|
||||
} else if (expected.kind === t.kind) {
|
||||
return null;
|
||||
} else if (expected.kind === 'value') {
|
||||
for (const memberType of valueMemberTypes) {
|
||||
if (!checkSubtype(memberType, t)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return `Expected ${toString(expected)} but found ${toString(t)} instead.`;
|
||||
}
|
||||
|
||||
export function isValidType(provided: Type, allowedTypes: Array<Type>): boolean {
|
||||
return allowedTypes.some(t => t.kind === provided.kind);
|
||||
}
|
||||
|
||||
export function isValidNativeType(provided: any, allowedTypes: Array<NativeType>): boolean {
|
||||
return allowedTypes.some(t => {
|
||||
if (t === 'null') {
|
||||
return provided === null;
|
||||
} else if (t === 'array') {
|
||||
return Array.isArray(provided);
|
||||
} else if (t === 'object') {
|
||||
return provided && !Array.isArray(provided) && typeof provided === 'object';
|
||||
} else {
|
||||
return t === typeof provided;
|
||||
}
|
||||
});
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user