Skip to content

Commit

Permalink
basic implementation of validator
Browse files Browse the repository at this point in the history
  • Loading branch information
samanpwbb committed Aug 20, 2019
1 parent 8f0998d commit 2ae7ecc
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/style-spec/validate/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const VALIDATORS = {
// scalar value.
// - valueSpec: current spec being evaluated. Tracks value.
// - styleSpec: current full spec being evaluated.
// - mapboxApiSupported: If true, assert that style can be uploaded to the Mapbox Styles API.

export default function validate(options) {
const value = options.value;
Expand Down
95 changes: 95 additions & 0 deletions src/style-spec/validate/validate_mapbox_api_supported.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// @flow
import ValidationError from '../error/validation_error';

const SUPPORTED_SPEC_VERSION = 8;
const MAX_SOURCES_IN_STYLE = 15;
const SOURCE_KEYS = ['type', 'url', 'tileSize'];

function validateKeys(obj: Object, keys: Array<*>, errors: Array<?Error>, path: ?string): void {
const allowed = new Set(keys);
Object.keys(obj).forEach(k => {
if (!allowed.has(k)) {
const prop = path ? `${path}.${k}` : k;
errors.push(new ValidationError(prop, null, `Unsupported property "${prop}"`));
}
});
}

function isValidSpriteURL(url: string): boolean {
const validPattern = /^mapbox:\/\/sprites\/([^/]*)\/([^/]*)\/([^/]*)?$/;
return !!url.match(validPattern);
}

function isValidGlyphsURL(url: string): boolean {
const validPattern = /^mapbox:\/\/fonts\/([^/]*)\/{fontstack}\/{range}.pbf$/;
return !!url.match(validPattern);
}

function validateSource(sources: Object, errors: Array<?Error>): void {
const count = Object.keys(sources).reduce((count, key) => {
const source = sources[key];
return count + source.url.replace('mapbox://', '').split(',').length;
}, 0);

if (count > MAX_SOURCES_IN_STYLE) {
errors.push(new ValidationError('sources', null, `Styles must contain ${MAX_SOURCES_IN_STYLE} or fewer sources`));
}

for (const q in sources) {
if (!sources[q].url) {
errors.push(new ValidationError('sources', null, 'Source must include url'));
}

if (sources[q].url.indexOf('mapbox://') !== 0) {
errors.push(new ValidationError('sources.url', null, 'Style must reference sources hosted by Mapbox'));
}

validateKeys(sources[q], SOURCE_KEYS, errors, 'source');
}

}

function validate(style: Object, errors: Array<?Error>): void {
if (style.version !== SUPPORTED_SPEC_VERSION) {
errors.push(new ValidationError('version', null, `style version must be ${SUPPORTED_SPEC_VERSION}`));
}

if (style.sprite && !isValidGlyphsURL(style.glyphs)) {
errors.push(new ValidationError('glyphs', null, 'Styles must reference glyphs hosted by Mapbox'));
}

if (style.sprite && !isValidSpriteURL(style.sprite)) {
errors.push(new ValidationError('sprite', null, 'Styles must reference sprites hosted by Mapbox'));
}

if (style.visibility && style.visibility.match(/^(public|private)/)) {
errors.push(new ValidationError('visibility', null, 'Style visibility must be public or private'));
}
}

function validateRootKeys(value: Object, specKeys: Array<any>, errors: Array<?Error>): void {
const optionalRootProperties = [
'owner',
'id',
'cacheControl',
'visibility',
'draft',
'created',
'modified'
];
validateKeys(value, [...specKeys, ...optionalRootProperties], errors);
}

function validateMapboxApiSupported(options: Object) {
const value = options.value;
const specKeys = Object.keys(options.styleSpec.$root);
const errors = [];

validateRootKeys(value, specKeys, errors);
validateSource(value.source, errors);
validate(value, errors);

return errors;
}

export default validateMapboxApiSupported;
9 changes: 5 additions & 4 deletions src/style-spec/validate_style.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@ import {v8} from './style-spec';
* or `Buffer` is provided, the returned errors will contain line numbers.
* @param {Object} [styleSpec] The style specification to validate against.
* If omitted, the spec version is inferred from the stylesheet.
* @param {Object} options
* @param {boolean} [options.mapboxApiSupported] If true, assert that
* style can be uploaded to the Mapbox Styles API.
* @returns {Array<ValidationError|ParsingError>}
* @example
* var validate = require('mapbox-gl-style-spec').validate;
* var style = fs.readFileSync('./style.json', 'utf8');
* var errors = validate(style);
*/

export default function validateStyle(style, styleSpec) {
export default function validateStyle(style, styleSpec = v8, options) {
if (style instanceof String || typeof style === 'string' || style instanceof Buffer) {
try {
style = jsonlint.parse(style.toString());
Expand All @@ -29,9 +32,7 @@ export default function validateStyle(style, styleSpec) {
}
}

styleSpec = styleSpec || v8;

return validateStyleMin(style, styleSpec);
return validateStyleMin(style, styleSpec, options);
}

export const source = validateStyleMin.source;
Expand Down
9 changes: 6 additions & 3 deletions src/style-spec/validate_style.min.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ import validateLayoutProperty from './validate/validate_layout_property';
* @param {Object} style The style to be validated.
* @param {Object} [styleSpec] The style specification to validate against.
* If omitted, the latest style spec is used.
* @param {Object} options
* @param {boolean} [options.mapboxApiSupported] If true, assert that
* style can be uploaded to the Mapbox Styles API.
* @returns {Array<ValidationError>}
* @example
* var validate = require('mapbox-gl-style-spec/lib/validate_style.min');
* var errors = validate(style);
*/
function validateStyleMin(style, styleSpec) {
styleSpec = styleSpec || latestStyleSpec;
function validateStyleMin(style, styleSpec = latestStyleSpec, options = {}) {

let errors = [];

Expand All @@ -42,7 +44,8 @@ function validateStyleMin(style, styleSpec) {
'*'() {
return [];
}
}
},
mapboxApiSupported: options.mapboxApiSupported
}));

if (style.constants) {
Expand Down

0 comments on commit 2ae7ecc

Please sign in to comment.