mirror of
https://github.com/maputnik/editor.git
synced 2026-03-24 11:10:19 +00:00
Improve tests (#854)
Recover commented out tests, Improve usage of helper in driver, Added data-wd-key for test to use instead of classes Moved all non tsx file to a single folder (lib) instead of lib and utils --------- Co-authored-by: Yuri Astrakhan <yuriastrakhan@gmail.com>
This commit is contained in:
179
src/libs/codemirror-mgl.ts
Normal file
179
src/libs/codemirror-mgl.ts
Normal file
@@ -0,0 +1,179 @@
|
||||
// @ts-ignore - this is a fork of jsonlint
|
||||
import jsonlint from 'jsonlint';
|
||||
import CodeMirror, { MarkerRange } from 'codemirror';
|
||||
import jsonToAst from 'json-to-ast';
|
||||
import {expression, validate} from '@maplibre/maplibre-gl-style-spec';
|
||||
|
||||
type MarkerRangeWithMessage = MarkerRange & {message: string};
|
||||
|
||||
|
||||
CodeMirror.defineMode("mgl", (config, parserConfig) => {
|
||||
// Just using the javascript mode with json enabled. Our logic is in the linter below.
|
||||
return CodeMirror.modes.javascript(
|
||||
{...config, json: true} as any,
|
||||
parserConfig
|
||||
);
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("lint", "json", (text: string) => {
|
||||
const found: MarkerRangeWithMessage[] = [];
|
||||
|
||||
// NOTE: This was modified from the original to remove the global, also the
|
||||
// old jsonlint API was 'jsonlint.parseError' its now
|
||||
// 'jsonlint.parser.parseError'
|
||||
(jsonlint as any).parser.parseError = (str: string, hash: any) => {
|
||||
const loc = hash.loc;
|
||||
found.push({
|
||||
from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
|
||||
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
|
||||
message: str
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
jsonlint.parse(text);
|
||||
}
|
||||
catch(e) {
|
||||
// Do nothing we catch the error above
|
||||
}
|
||||
return found;
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) => {
|
||||
const found: MarkerRangeWithMessage[] = [];
|
||||
const {parser} = jsonlint as any;
|
||||
const {context} = opts;
|
||||
|
||||
parser.parseError = (str: string, hash: any) => {
|
||||
const loc = hash.loc;
|
||||
found.push({
|
||||
from: CodeMirror.Pos(loc.first_line - 1, loc.first_column),
|
||||
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column),
|
||||
message: str
|
||||
});
|
||||
};
|
||||
try {
|
||||
parser.parse(text);
|
||||
}
|
||||
catch (e) {
|
||||
// ignore errors
|
||||
}
|
||||
|
||||
if (found.length > 0) {
|
||||
// JSON invalid so don't go any further
|
||||
return found;
|
||||
}
|
||||
|
||||
const ast = jsonToAst(text);
|
||||
const input = JSON.parse(text);
|
||||
|
||||
function getArrayPositionalFromAst(node: any, path: string[]) {
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
else if (path.length < 1) {
|
||||
return node;
|
||||
}
|
||||
else if (!node.children) {
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
const key = path[0];
|
||||
let newNode;
|
||||
if (key.match(/^[0-9]+$/)) {
|
||||
newNode = node.children[path[0]];
|
||||
}
|
||||
else {
|
||||
newNode = node.children.find((childNode: any) => {
|
||||
return (
|
||||
childNode.key &&
|
||||
childNode.key.type === "Identifier" &&
|
||||
childNode.key.value === key
|
||||
);
|
||||
});
|
||||
if (newNode) {
|
||||
newNode = newNode.value;
|
||||
}
|
||||
}
|
||||
return getArrayPositionalFromAst(newNode, path.slice(1))
|
||||
}
|
||||
}
|
||||
|
||||
let out: ReturnType<typeof expression.createExpression> | null = null;
|
||||
if (context === "layer") {
|
||||
// Just an empty style so we can validate a layer.
|
||||
const errors = validate({
|
||||
"version": 8,
|
||||
"name": "Empty Style",
|
||||
"metadata": {},
|
||||
"sources": {},
|
||||
"sprite": "",
|
||||
"glyphs": "https://example.com/glyphs/{fontstack}/{range}.pbf",
|
||||
"layers": [
|
||||
input
|
||||
]
|
||||
});
|
||||
|
||||
if (errors) {
|
||||
out = {
|
||||
result: "error",
|
||||
value: errors
|
||||
.filter(err => {
|
||||
// Remove missing 'layer source' errors, because we don't include them
|
||||
return !err.message.match(/^layers\[0\]: source ".*" not found$/);
|
||||
})
|
||||
.map(err => {
|
||||
// Remove the 'layers[0].' as we're validating the layer only here
|
||||
const errMessageParts = err.message.replace(/^layers\[0\]./, "").split(":");
|
||||
return {
|
||||
name: '',
|
||||
key: errMessageParts[0],
|
||||
message: errMessageParts[1],
|
||||
};
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (context === "expression") {
|
||||
out = expression.createExpression(input, opts.spec);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Invalid context ${context}`);
|
||||
}
|
||||
|
||||
if (out?.result === "error") {
|
||||
const errors = out.value;
|
||||
errors.forEach(error => {
|
||||
const {key, message} = error;
|
||||
|
||||
if (!key) {
|
||||
const lastLineHandle = doc.getLineHandle(doc.lastLine());
|
||||
const err = {
|
||||
from: CodeMirror.Pos(doc.firstLine(), 0),
|
||||
to: CodeMirror.Pos(doc.lastLine(), lastLineHandle.text.length),
|
||||
message: message,
|
||||
}
|
||||
found.push(err);
|
||||
}
|
||||
else if (key) {
|
||||
const path = key.replace(/^\[|\]$/g, "").split(/\.|[[\]]+/).filter(Boolean)
|
||||
const parsedError = getArrayPositionalFromAst(ast, path);
|
||||
if (!parsedError) {
|
||||
console.warn("Something went wrong parsing error:", error);
|
||||
return;
|
||||
}
|
||||
|
||||
const {loc} = parsedError;
|
||||
const {start, end} = loc;
|
||||
|
||||
found.push({
|
||||
from: CodeMirror.Pos(start.line - 1, start.column),
|
||||
to: CodeMirror.Pos(end.line - 1, end.column),
|
||||
message: message,
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return found;
|
||||
});
|
||||
3
src/libs/format.ts
Normal file
3
src/libs/format.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function formatLayerId (id: string | undefined) {
|
||||
return id === "" ? "[empty_string]" : `'${id}'`;
|
||||
}
|
||||
13
src/libs/label-from-field-name.ts
Normal file
13
src/libs/label-from-field-name.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import capitalize from 'lodash.capitalize'
|
||||
|
||||
export default function labelFromFieldName(fieldName: string) {
|
||||
let label;
|
||||
const parts = fieldName.split('-');
|
||||
if (parts.length > 1) {
|
||||
label = fieldName.split('-').slice(1).join(' ');
|
||||
}
|
||||
else {
|
||||
label = fieldName;
|
||||
}
|
||||
return capitalize(label);
|
||||
}
|
||||
18
src/libs/spec-helper.ts
Normal file
18
src/libs/spec-helper.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* If we don't have a default value just make one up
|
||||
*/
|
||||
export function findDefaultFromSpec(spec: { type: 'string' | 'color' | 'boolean' | 'array', default?: any }) {
|
||||
if (Object.prototype.hasOwnProperty.call(spec, 'default')) {
|
||||
return spec.default;
|
||||
}
|
||||
|
||||
const defaults = {
|
||||
'color': '#000000',
|
||||
'string': '',
|
||||
'boolean': false,
|
||||
'number': 0,
|
||||
'array': [],
|
||||
}
|
||||
|
||||
return defaults[spec.type] || '';
|
||||
}
|
||||
Reference in New Issue
Block a user