Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

@mapbox/mapbox-gl-style-spec

Package Overview
Dependencies
Maintainers
178
Versions
101
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mapbox/mapbox-gl-style-spec - npm Package Compare versions

Comparing version 9.0.1 to 10.0.0

expression/compound_expression.js

4

CHANGELOG.md

@@ -0,1 +1,5 @@

## 10.0.0
* Add expression and heatmap layer support. See Mapbox GL JS v0.40.1 changelog entry for details.
## 9.0.1

@@ -2,0 +6,0 @@

18

diff.js

@@ -47,2 +47,7 @@

/*
* { command: 'setGeoJSONSourceData', args: ['sourceId', data] }
*/
setGeoJSONSourceData: 'setGeoJSONSourceData',
/*
* { command: 'setLayerZoomRange', args: ['layerId', 0, 22] }

@@ -121,6 +126,11 @@ */

} else if (!isEqual(before[sourceId], after[sourceId])) {
// no update command, must remove then add
commands.push({ command: operations.removeSource, args: [sourceId] });
commands.push({ command: operations.addSource, args: [sourceId, after[sourceId]] });
sourcesRemoved[sourceId] = true;
if (before[sourceId].type === 'geojson' && after[sourceId].type === 'geojson') {
// geojson sources use setGeoJSONSourceData command to update
commands.push({ command: operations.setGeoJSONSourceData, args: [sourceId, after[sourceId].data] });
} else {
// no update command, must remove then add
commands.push({ command: operations.removeSource, args: [sourceId] });
commands.push({ command: operations.addSource, args: [sourceId, after[sourceId]] });
sourcesRemoved[sourceId] = true;
}
}

@@ -127,0 +137,0 @@ }

@@ -0,5 +1,56 @@

// @flow
const {createExpression} = require('../expression');
import type {GlobalProperties} from '../expression';
export type FeatureFilter = (globalProperties: GlobalProperties, feature: VectorTileFeature) => boolean;
module.exports = createFilter;
module.exports.isExpressionFilter = isExpressionFilter;
function isExpressionFilter(filter) {
if (!Array.isArray(filter) || filter.length === 0) {
return false;
}
switch (filter[0]) {
case 'has':
return filter.length >= 2 && filter[1] !== '$id' && filter[1] !== '$type';
case 'in':
case '!in':
case '!has':
case 'none':
return false;
case '==':
case '!=':
case '>':
case '>=':
case '<':
case '<=':
return filter.length === 3 && (Array.isArray(filter[1]) || Array.isArray(filter[2]));
case 'any':
case 'all':
for (const f of filter.slice(1)) {
if (!isExpressionFilter(f) && typeof f !== 'boolean') {
return false;
}
}
return true;
default:
return true;
}
}
const types = ['Unknown', 'Point', 'LineString', 'Polygon'];
const filterSpec = {
'type': 'boolean',
'default': false,
'function': true,
'property-function': true
};
/**

@@ -14,4 +65,17 @@ * Given a filter expressed as nested arrays, return a new function

*/
function createFilter(filter) {
return new Function('f', `var p = (f && f.properties || {}); return ${compile(filter)}`);
function createFilter(filter: any): FeatureFilter {
if (!filter) {
return () => true;
}
if (!isExpressionFilter(filter)) {
return (new Function('g', 'f', `var p = (f && f.properties || {}); return ${compile(filter)}`): any);
}
const compiled = createExpression(filter, filterSpec, 'filter');
if (compiled.result === 'success') {
return compiled.evaluate;
} else {
throw new Error(compiled.errors.map(err => `${err.key}: ${err.message}`).join(', '));
}
}

@@ -18,0 +82,0 @@

const colorSpaces = require('./color_spaces');
const colorSpaces = require('../util/color_spaces');
const parseColor = require('../util/parse_color');

@@ -8,2 +8,6 @@ const extend = require('../util/extend');

function isFunction(value) {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function identityFunction(x) {

@@ -13,130 +17,132 @@ return x;

function createFunction(parameters, propertySpec) {
function createFunction(parameters, propertySpec, name) {
const isColor = propertySpec.type === 'color';
const zoomAndFeatureDependent = parameters.stops && typeof parameters.stops[0][0] === 'object';
const featureDependent = zoomAndFeatureDependent || parameters.property !== undefined;
const zoomDependent = zoomAndFeatureDependent || !featureDependent;
const type = parameters.type || (propertySpec.function === 'interpolated' ? 'exponential' : 'interval');
let fun;
if (isColor) {
parameters = extend({}, parameters);
if (!isFunctionDefinition(parameters)) {
if (isColor && parameters) {
parameters = parseColor(parameters);
if (parameters.stops) {
parameters.stops = parameters.stops.map((stop) => {
return [stop[0], parseColor(stop[1])];
});
}
fun = function() {
return parameters;
};
fun.isFeatureConstant = true;
fun.isZoomConstant = true;
} else {
const zoomAndFeatureDependent = parameters.stops && typeof parameters.stops[0][0] === 'object';
const featureDependent = zoomAndFeatureDependent || parameters.property !== undefined;
const zoomDependent = zoomAndFeatureDependent || !featureDependent;
const type = parameters.type || (propertySpec.function === 'interpolated' ? 'exponential' : 'interval');
if (parameters.default) {
parameters.default = parseColor(parameters.default);
} else {
parameters.default = parseColor(propertySpec.default);
}
}
if (isColor) {
parameters = extend({}, parameters);
let innerFun;
let hashedStops;
let categoricalKeyType;
if (type === 'exponential') {
innerFun = evaluateExponentialFunction;
} else if (type === 'interval') {
innerFun = evaluateIntervalFunction;
} else if (type === 'categorical') {
innerFun = evaluateCategoricalFunction;
if (parameters.stops) {
parameters.stops = parameters.stops.map((stop) => {
return [stop[0], parseColor(stop[1])];
});
}
if (parameters.default) {
parameters.default = parseColor(parameters.default);
} else {
parameters.default = parseColor(propertySpec.default);
}
// For categorical functions, generate an Object as a hashmap of the stops for fast searching
hashedStops = Object.create(null);
for (const stop of parameters.stops) {
hashedStops[stop[0]] = stop[1];
}
let innerFun;
let hashedStops;
let categoricalKeyType;
if (type === 'exponential') {
innerFun = evaluateExponentialFunction;
} else if (type === 'interval') {
innerFun = evaluateIntervalFunction;
} else if (type === 'categorical') {
innerFun = evaluateCategoricalFunction;
// Infer key type based on first stop key-- used to encforce strict type checking later
categoricalKeyType = typeof parameters.stops[0][0];
// For categorical functions, generate an Object as a hashmap of the stops for fast searching
hashedStops = Object.create(null);
for (const stop of parameters.stops) {
hashedStops[stop[0]] = stop[1];
}
} else if (type === 'identity') {
innerFun = evaluateIdentityFunction;
} else {
throw new Error(`Unknown function type "${type}"`);
}
// Infer key type based on first stop key-- used to encforce strict type checking later
categoricalKeyType = typeof parameters.stops[0][0];
let outputFunction;
} else if (type === 'identity') {
innerFun = evaluateIdentityFunction;
// If we're interpolating colors in a color system other than RGBA,
// first translate all stop values to that color system, then interpolate
// arrays as usual. The `outputFunction` option lets us then translate
// the result of that interpolation back into RGBA.
if (parameters.colorSpace && parameters.colorSpace !== 'rgb') {
if (colorSpaces[parameters.colorSpace]) {
const colorspace = colorSpaces[parameters.colorSpace];
// Avoid mutating the parameters value
parameters = JSON.parse(JSON.stringify(parameters));
for (let s = 0; s < parameters.stops.length; s++) {
parameters.stops[s] = [
parameters.stops[s][0],
colorspace.forward(parameters.stops[s][1])
];
}
outputFunction = colorspace.reverse;
} else {
throw new Error(`Unknown function type "${type}"`);
throw new Error(`Unknown color space: ${parameters.colorSpace}`);
}
} else {
outputFunction = identityFunction;
}
let outputFunction;
// If we're interpolating colors in a color system other than RGBA,
// first translate all stop values to that color system, then interpolate
// arrays as usual. The `outputFunction` option lets us then translate
// the result of that interpolation back into RGBA.
if (parameters.colorSpace && parameters.colorSpace !== 'rgb') {
if (colorSpaces[parameters.colorSpace]) {
const colorspace = colorSpaces[parameters.colorSpace];
// Avoid mutating the parameters value
parameters = JSON.parse(JSON.stringify(parameters));
for (let s = 0; s < parameters.stops.length; s++) {
parameters.stops[s] = [
parameters.stops[s][0],
colorspace.forward(parameters.stops[s][1])
];
}
outputFunction = colorspace.reverse;
} else {
throw new Error(`Unknown color space: ${parameters.colorSpace}`);
if (zoomAndFeatureDependent) {
const featureFunctions = {};
const zoomStops = [];
for (let s = 0; s < parameters.stops.length; s++) {
const stop = parameters.stops[s];
const zoom = stop[0].zoom;
if (featureFunctions[zoom] === undefined) {
featureFunctions[zoom] = {
zoom: zoom,
type: parameters.type,
property: parameters.property,
default: parameters.default,
stops: []
};
zoomStops.push(zoom);
}
} else {
outputFunction = identityFunction;
featureFunctions[zoom].stops.push([stop[0].value, stop[1]]);
}
if (zoomAndFeatureDependent) {
const featureFunctions = {};
const zoomStops = [];
for (let s = 0; s < parameters.stops.length; s++) {
const stop = parameters.stops[s];
const zoom = stop[0].zoom;
if (featureFunctions[zoom] === undefined) {
featureFunctions[zoom] = {
zoom: zoom,
type: parameters.type,
property: parameters.property,
default: parameters.default,
stops: []
};
zoomStops.push(zoom);
}
featureFunctions[zoom].stops.push([stop[0].value, stop[1]]);
}
const featureFunctionStops = [];
for (const z of zoomStops) {
featureFunctionStops.push([featureFunctions[z].zoom, createFunction(featureFunctions[z], propertySpec)]);
}
const featureFunctionStops = [];
for (const z of zoomStops) {
featureFunctionStops.push([featureFunctions[z].zoom, createFunction(featureFunctions[z], propertySpec)]);
}
fun = function(zoom, feature) {
return {
isFeatureConstant: false,
interpolation: {name: 'linear'},
zoomStops: featureFunctionStops.map(s => s[0]),
evaluate({zoom}, properties) {
return outputFunction(evaluateExponentialFunction({
stops: featureFunctionStops,
base: parameters.base
}, propertySpec, zoom)(zoom, feature));
};
fun.isFeatureConstant = false;
fun.isZoomConstant = false;
} else if (zoomDependent) {
fun = function(zoom) {
return outputFunction(innerFun(parameters, propertySpec, zoom, hashedStops, categoricalKeyType));
};
fun.isFeatureConstant = true;
fun.isZoomConstant = false;
}, propertySpec, zoom).evaluate(zoom, properties));
}
};
} else if (zoomDependent) {
let evaluate;
if (name === 'heatmap-color') {
evaluate = ({heatmapDensity}) => outputFunction(innerFun(parameters, propertySpec, heatmapDensity, hashedStops, categoricalKeyType));
} else {
fun = function(zoom, feature) {
const value = feature[parameters.property];
evaluate = ({zoom}) => outputFunction(innerFun(parameters, propertySpec, zoom, hashedStops, categoricalKeyType));
}
return {
isFeatureConstant: true,
isZoomConstant: false,
interpolation: type === 'exponential' ?
{name: 'exponential', base: parameters.base !== undefined ? parameters.base : 1} :
{name: 'step'},
zoomStops: parameters.stops.map(s => s[0]),
evaluate
};
} else {
return {
isFeatureConstant: false,
isZoomConstant: true,
evaluate(_, feature) {
const value = feature && feature.properties ? feature.properties[parameters.property] : undefined;
if (value === undefined) {

@@ -146,9 +152,5 @@ return coalesce(parameters.default, propertySpec.default);

return outputFunction(innerFun(parameters, propertySpec, value, hashedStops, categoricalKeyType));
};
fun.isFeatureConstant = false;
fun.isZoomConstant = true;
}
}
};
}
return fun;
}

@@ -200,11 +202,13 @@

if (typeof outputLower === 'function') {
return function(...args) {
const evaluatedLower = outputLower.apply(undefined, args);
const evaluatedUpper = outputUpper.apply(undefined, args);
// Special case for fill-outline-color, which has no spec default.
if (evaluatedLower === undefined || evaluatedUpper === undefined) {
return undefined;
if (typeof outputLower.evaluate === 'function') {
return {
evaluate(...args) {
const evaluatedLower = outputLower.evaluate.apply(undefined, args);
const evaluatedUpper = outputUpper.evaluate.apply(undefined, args);
// Special case for fill-outline-color, which has no spec default.
if (evaluatedLower === undefined || evaluatedUpper === undefined) {
return undefined;
}
return interp(evaluatedLower, evaluatedUpper, t);
}
return interp(evaluatedLower, evaluatedUpper, t);
};

@@ -253,6 +257,2 @@ }

function isFunctionDefinition(value) {
return typeof value === 'object' && (value.stops || value.type === 'identity');
}
/**

@@ -295,3 +295,3 @@ * Returns a ratio that can be used to interpolate between exponential function

* @private
*/
*/
function interpolationFactor(input, base, lowerValue, upperValue) {

@@ -310,5 +310,5 @@ const difference = upperValue - lowerValue;

module.exports = createFunction;
module.exports.isFunctionDefinition = isFunctionDefinition;
module.exports.interpolationFactor = interpolationFactor;
module.exports.findStopLessThanOrEqualTo = findStopLessThanOrEqualTo;
module.exports = {
createFunction,
isFunction
};

@@ -6,3 +6,3 @@

const type = typeof obj;
if (type === 'number' || type === 'string' || obj === undefined || obj === null)
if (type === 'number' || type === 'boolean' || type === 'string' || obj === undefined || obj === null)
return JSON.stringify(obj);

@@ -9,0 +9,0 @@

@@ -13,3 +13,3 @@

exports.ParsingError = require('./error/parsing_error');
exports.function = require('./function');
exports.expression = require('./expression');
exports.featureFilter = require('./feature_filter');

@@ -16,0 +16,0 @@

{
"name": "@mapbox/mapbox-gl-style-spec",
"description": "a specification for mapbox gl styles",
"version": "9.0.1",
"version": "10.0.0",
"author": "Mapbox",

@@ -6,0 +6,0 @@ "keywords": [

@@ -0,5 +1,6 @@

// @flow
const parseColorString = require('csscolorparser').parseCSSColor;
module.exports = function parseColor(input) {
module.exports = function parseColor(input: string | [number, number, number, number]): ?[number, number, number, number] {
if (typeof input === 'string') {

@@ -6,0 +7,0 @@ const rgba = parseColorString(input);

// Turn jsonlint-lines-primitives objects into primitive objects
module.exports = function unbundle(value) {
function unbundle(value) {
if (value instanceof Number || value instanceof String || value instanceof Boolean) {

@@ -9,2 +9,12 @@ return value.valueOf();

}
};
}
function deepUnbundle(value) {
if (Array.isArray(value)) {
return value.map(deepUnbundle);
}
return unbundle(value);
}
module.exports = unbundle;
module.exports.deep = deepUnbundle;

@@ -13,7 +13,7 @@

if (valueSpec.values.indexOf(unbundle(value)) === -1) {
errors.push(new ValidationError(key, value, 'expected one of [%s], %s found', valueSpec.values.join(', '), value));
errors.push(new ValidationError(key, value, 'expected one of [%s], %s found', valueSpec.values.join(', '), JSON.stringify(value)));
}
} else { // >=v8
if (Object.keys(valueSpec.values).indexOf(unbundle(value)) === -1) {
errors.push(new ValidationError(key, value, 'expected one of [%s], %s found', Object.keys(valueSpec.values).join(', '), value));
errors.push(new ValidationError(key, value, 'expected one of [%s], %s found', Object.keys(valueSpec.values).join(', '), JSON.stringify(value)));
}

@@ -20,0 +20,0 @@ }

const ValidationError = require('../error/validation_error');
const validateExpression = require('./validate_expression');
const validateEnum = require('./validate_enum');
const getType = require('../util/get_type');
const unbundle = require('../util/unbundle_jsonlint');
const extend = require('../util/extend');
const {isExpressionFilter} = require('../feature_filter');

@@ -19,2 +22,9 @@ module.exports = function validateFilter(options) {

if (isExpressionFilter(unbundle.deep(value))) {
return validateExpression(extend({}, options, {
expressionContext: 'filter',
valueSpec: { value: 'boolean' }
}));
}
if (value.length < 1) {

@@ -21,0 +31,0 @@ return [new ValidationError(key, value, 'filter array must have at least 1 element')];

@@ -133,3 +133,3 @@

styleSpec: options.styleSpec
}));
}, value));
}

@@ -146,14 +146,16 @@

function validateStopDomainValue(options) {
function validateStopDomainValue(options, stop) {
const type = getType(options.value);
const value = unbundle(options.value);
const reportValue = options.value !== null ? options.value : stop;
if (!stopKeyType) {
stopKeyType = type;
} else if (type !== stopKeyType) {
return [new ValidationError(options.key, options.value, '%s stop domain type must match previous stop domain type %s', type, stopKeyType)];
return [new ValidationError(options.key, reportValue, '%s stop domain type must match previous stop domain type %s', type, stopKeyType)];
}
if (type !== 'number' && type !== 'string' && type !== 'boolean') {
return [new ValidationError(options.key, options.value, 'stop domain value must be a number, string, or boolean')];
return [new ValidationError(options.key, reportValue, 'stop domain value must be a number, string, or boolean')];
}

@@ -166,11 +168,11 @@

}
return [new ValidationError(options.key, options.value, message, type)];
return [new ValidationError(options.key, reportValue, message, type)];
}
if (functionType === 'categorical' && type === 'number' && (!isFinite(value) || Math.floor(value) !== value)) {
return [new ValidationError(options.key, options.value, 'integer expected, found %s', value)];
return [new ValidationError(options.key, reportValue, 'integer expected, found %s', value)];
}
if (functionType !== 'categorical' && type === 'number' && previousStopDomainValue !== undefined && value < previousStopDomainValue) {
return [new ValidationError(options.key, options.value, 'stop domain values must appear in ascending order')];
return [new ValidationError(options.key, reportValue, 'stop domain values must appear in ascending order')];
} else {

@@ -181,3 +183,3 @@ previousStopDomainValue = value;

if (functionType === 'categorical' && value in stopDomainValues) {
return [new ValidationError(options.key, options.value, 'stop domain values must be unique')];
return [new ValidationError(options.key, reportValue, 'stop domain values must be unique')];
} else {

@@ -184,0 +186,0 @@ stopDomainValues[value] = true;

@@ -46,3 +46,3 @@

objectKey: objectKey
}));
}, object));
}

@@ -49,0 +49,0 @@

@@ -55,4 +55,5 @@

style: style,
styleSpec: styleSpec
styleSpec: styleSpec,
expressionContext: 'property'
}));
};

@@ -5,2 +5,5 @@

const extend = require('../util/extend');
const unbundle = require('../util/unbundle_jsonlint');
const {isExpression} = require('../expression');
const {isFunction} = require('../function');

@@ -19,2 +22,3 @@ // Main recursive validation function. Tracks:

const validateFunction = require('./validate_function');
const validateExpression = require('./validate_expression');
const validateObject = require('./validate_object');

@@ -56,5 +60,8 @@ const VALIDATORS = {

if (valueSpec.function && getType(value) === 'object') {
if (valueSpec.function && isFunction(unbundle(value))) {
return validateFunction(options);
} else if (valueSpec.function && isExpression(unbundle.deep(value))) {
return validateExpression(options);
} else if (valueSpec.type && VALIDATORS[valueSpec.type]) {

@@ -61,0 +68,0 @@ return VALIDATORS[valueSpec.type](options);

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc