Son CV dans un terminal web en Javascript!
https://terminal-cv.gregandev.fr
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
13 KiB
391 lines
13 KiB
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.fuzzySearch = fuzzySearch;
|
|
exports.default = void 0;
|
|
|
|
function _diagnostic() {
|
|
const data = _interopRequireWildcard(require("@parcel/diagnostic"));
|
|
|
|
_diagnostic = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _nullthrows() {
|
|
const data = _interopRequireDefault(require("nullthrows"));
|
|
|
|
_nullthrows = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _fastestLevenshtein() {
|
|
const data = _interopRequireDefault(require("fastest-levenshtein"));
|
|
|
|
_fastestLevenshtein = function () {
|
|
return data;
|
|
};
|
|
|
|
return data;
|
|
}
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
|
|
|
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
|
|
// flowlint-next-line untyped-import:off
|
|
function validateSchema(schema, data) {
|
|
function walk(schemaAncestors, dataNode, dataPath) {
|
|
let [schemaNode] = schemaAncestors;
|
|
|
|
if (schemaNode.type) {
|
|
let type = Array.isArray(dataNode) ? 'array' : typeof dataNode;
|
|
|
|
if (schemaNode.type !== type) {
|
|
return {
|
|
type: 'type',
|
|
dataType: 'value',
|
|
dataPath,
|
|
expectedTypes: [schemaNode.type],
|
|
ancestors: schemaAncestors,
|
|
prettyType: schemaNode.__type
|
|
};
|
|
} else {
|
|
switch (schemaNode.type) {
|
|
case 'array':
|
|
{
|
|
if (schemaNode.items) {
|
|
let results = []; // $FlowFixMe type was already checked
|
|
|
|
for (let i = 0; i < dataNode.length; i++) {
|
|
let result = walk([schemaNode.items].concat(schemaAncestors), // $FlowFixMe type was already checked
|
|
dataNode[i], dataPath + '/' + i);
|
|
if (result) results.push(result);
|
|
}
|
|
|
|
if (results.length) return results.reduce((acc, v) => acc.concat(v), []);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'string':
|
|
{
|
|
// $FlowFixMe type was already checked
|
|
let value = dataNode;
|
|
|
|
if (schemaNode.enum) {
|
|
if (!schemaNode.enum.includes(value)) {
|
|
return {
|
|
type: 'enum',
|
|
dataType: 'value',
|
|
dataPath,
|
|
expectedValues: schemaNode.enum,
|
|
actualValue: value,
|
|
ancestors: schemaAncestors
|
|
};
|
|
}
|
|
} else if (schemaNode.__validate) {
|
|
let validationError = schemaNode.__validate(value);
|
|
|
|
if (typeof validationError == 'string') {
|
|
return {
|
|
type: 'other',
|
|
dataType: 'value',
|
|
dataPath,
|
|
message: validationError,
|
|
actualValue: value,
|
|
ancestors: schemaAncestors
|
|
};
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'number':
|
|
{
|
|
// $FlowFixMe type was already checked
|
|
let value = dataNode;
|
|
|
|
if (schemaNode.enum) {
|
|
if (!schemaNode.enum.includes(value)) {
|
|
return {
|
|
type: 'enum',
|
|
dataType: 'value',
|
|
dataPath,
|
|
expectedValues: schemaNode.enum,
|
|
actualValue: value,
|
|
ancestors: schemaAncestors
|
|
};
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'object':
|
|
{
|
|
let results = [];
|
|
let invalidProps;
|
|
|
|
if (schemaNode.__forbiddenProperties) {
|
|
// $FlowFixMe type was already checked
|
|
let keys = Object.keys(dataNode);
|
|
invalidProps = schemaNode.__forbiddenProperties.filter(val => keys.includes(val));
|
|
results.push(...invalidProps.map(k => ({
|
|
type: 'forbidden-prop',
|
|
dataPath: dataPath + '/' + (0, _diagnostic().encodeJSONKeyComponent)(k),
|
|
dataType: 'key',
|
|
prop: k,
|
|
expectedProps: Object.keys(schemaNode.properties),
|
|
actualProps: keys,
|
|
ancestors: schemaAncestors
|
|
})));
|
|
}
|
|
|
|
if (schemaNode.required) {
|
|
// $FlowFixMe type was already checked
|
|
let keys = Object.keys(dataNode);
|
|
let missingKeys = schemaNode.required.filter(val => !keys.includes(val));
|
|
results.push(...missingKeys.map(k => ({
|
|
type: 'missing-prop',
|
|
dataPath,
|
|
dataType: 'value',
|
|
prop: k,
|
|
expectedProps: schemaNode.required,
|
|
actualProps: keys,
|
|
ancestors: schemaAncestors
|
|
})));
|
|
}
|
|
|
|
if (schemaNode.properties) {
|
|
let {
|
|
additionalProperties = true
|
|
} = schemaNode; // $FlowFixMe type was already checked
|
|
|
|
for (let k in dataNode) {
|
|
if (invalidProps && invalidProps.includes(k)) {
|
|
// Don't check type on forbidden props
|
|
continue;
|
|
} else if (k in schemaNode.properties) {
|
|
let result = walk([schemaNode.properties[k]].concat(schemaAncestors), // $FlowFixMe type was already checked
|
|
dataNode[k], dataPath + '/' + (0, _diagnostic().encodeJSONKeyComponent)(k));
|
|
if (result) results.push(result);
|
|
} else {
|
|
if (typeof additionalProperties === 'boolean') {
|
|
if (!additionalProperties) {
|
|
results.push({
|
|
type: 'enum',
|
|
dataType: 'key',
|
|
dataPath: dataPath + '/' + (0, _diagnostic().encodeJSONKeyComponent)(k),
|
|
expectedValues: Object.keys(schemaNode.properties).filter( // $FlowFixMe type was already checked
|
|
p => !(p in dataNode)),
|
|
actualValue: k,
|
|
ancestors: schemaAncestors,
|
|
prettyType: schemaNode.__type
|
|
});
|
|
}
|
|
} else {
|
|
let result = walk([additionalProperties].concat(schemaAncestors), // $FlowFixMe type was already checked
|
|
dataNode[k], dataPath + '/' + (0, _diagnostic().encodeJSONKeyComponent)(k));
|
|
if (result) results.push(result);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (results.length) return results.reduce((acc, v) => acc.concat(v), []);
|
|
break;
|
|
}
|
|
|
|
case 'boolean':
|
|
// NOOP, type was checked already
|
|
break;
|
|
|
|
default:
|
|
throw new Error(`Unimplemented schema type ${type}?`);
|
|
}
|
|
}
|
|
} else {
|
|
if (schemaNode.enum && !schemaNode.enum.includes(dataNode)) {
|
|
return {
|
|
type: 'enum',
|
|
dataType: 'value',
|
|
dataPath: dataPath,
|
|
expectedValues: schemaNode.enum,
|
|
actualValue: schemaNode,
|
|
ancestors: schemaAncestors
|
|
};
|
|
}
|
|
|
|
if (schemaNode.oneOf || schemaNode.allOf) {
|
|
let list = schemaNode.oneOf || schemaNode.allOf;
|
|
let results = [];
|
|
|
|
for (let f of list) {
|
|
let result = walk([f].concat(schemaAncestors), dataNode, dataPath);
|
|
if (result) results.push(result);
|
|
}
|
|
|
|
if (schemaNode.oneOf ? results.length == schemaNode.oneOf.length : results.length > 0) {
|
|
// return the result with more values / longer key
|
|
results.sort((a, b) => Array.isArray(a) || Array.isArray(b) ? Array.isArray(a) && !Array.isArray(b) ? -1 : !Array.isArray(a) && Array.isArray(b) ? 1 : Array.isArray(a) && Array.isArray(b) ? b.length - a.length : 0 : b.dataPath.length - a.dataPath.length);
|
|
return results[0];
|
|
}
|
|
} else if (schemaNode.not) {
|
|
let result = walk([schemaNode.not].concat(schemaAncestors), dataNode, dataPath);
|
|
|
|
if (!result || result.length == 0) {
|
|
return {
|
|
type: 'other',
|
|
dataPath,
|
|
dataType: null,
|
|
message: schemaNode.__message,
|
|
actualValue: dataNode,
|
|
ancestors: schemaAncestors
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
let result = walk([schema], data, '');
|
|
return Array.isArray(result) ? result : result ? [result] : [];
|
|
}
|
|
|
|
var _default = validateSchema;
|
|
exports.default = _default;
|
|
|
|
function fuzzySearch(expectedValues, actualValue) {
|
|
let result = expectedValues.map(exp => [exp, _fastestLevenshtein().default.distance(exp, actualValue)]).filter( // Remove if more than half of the string would need to be changed
|
|
([, d]) => d * 2 < actualValue.length);
|
|
result.sort(([, a], [, b]) => a - b);
|
|
return result.map(([v]) => v);
|
|
}
|
|
|
|
validateSchema.diagnostic = function (schema, data, origin, message) {
|
|
var _data$data;
|
|
|
|
if ('source' in data && 'data' in data && typeof data.source !== 'string' && !data) {
|
|
throw new Error('At least one of data.source and data.source must be defined!');
|
|
}
|
|
|
|
let object = data.map ? data.map.data : // $FlowFixMe we can assume it's a JSON object
|
|
(_data$data = data.data) !== null && _data$data !== void 0 ? _data$data : JSON.parse(data.source);
|
|
let errors = validateSchema(schema, object);
|
|
|
|
if (errors.length) {
|
|
var _data$filePath;
|
|
|
|
let keys = errors.map(e => {
|
|
let message;
|
|
|
|
if (e.type === 'enum') {
|
|
let {
|
|
actualValue
|
|
} = e;
|
|
let expectedValues = e.expectedValues.map(String);
|
|
let likely = actualValue != null ? fuzzySearch(expectedValues, String(actualValue)) : [];
|
|
|
|
if (likely.length > 0) {
|
|
message = `Did you mean ${likely.map(v => JSON.stringify(v)).join(', ')}?`;
|
|
} else if (expectedValues.length > 0) {
|
|
message = `Possible values: ${expectedValues.map(v => JSON.stringify(v)).join(', ')}`;
|
|
} else {
|
|
message = 'Unexpected value';
|
|
}
|
|
} else if (e.type === 'forbidden-prop') {
|
|
let {
|
|
prop,
|
|
expectedProps,
|
|
actualProps
|
|
} = e;
|
|
let likely = fuzzySearch(expectedProps, prop).filter(v => !actualProps.includes(v));
|
|
|
|
if (likely.length > 0) {
|
|
message = `Did you mean ${likely.map(v => JSON.stringify(v)).join(', ')}?`;
|
|
} else {
|
|
message = 'Unexpected property';
|
|
}
|
|
} else if (e.type === 'missing-prop') {
|
|
let {
|
|
prop,
|
|
actualProps
|
|
} = e;
|
|
let likely = fuzzySearch(actualProps, prop);
|
|
|
|
if (likely.length > 0) {
|
|
message = `Did you mean ${JSON.stringify(prop)}?`;
|
|
e.dataPath += '/' + likely[0];
|
|
e.dataType = 'key';
|
|
} else {
|
|
message = `Missing property ${prop}`;
|
|
}
|
|
} else if (e.type === 'type') {
|
|
if (e.prettyType != null) {
|
|
message = `Expected ${e.prettyType}`;
|
|
} else {
|
|
message = `Expected type ${e.expectedTypes.join(', ')}`;
|
|
}
|
|
} else {
|
|
message = e.message;
|
|
}
|
|
|
|
return {
|
|
key: e.dataPath,
|
|
type: e.dataType,
|
|
message
|
|
};
|
|
});
|
|
let map, code;
|
|
|
|
if (data.map) {
|
|
map = data.map;
|
|
code = data.source;
|
|
} else {
|
|
var _data$source;
|
|
|
|
// $FlowFixMe we can assume that data is valid JSON
|
|
map = (_data$source = data.source) !== null && _data$source !== void 0 ? _data$source : JSON.stringify((0, _nullthrows().default)(data.data), 0, '\t');
|
|
code = map;
|
|
}
|
|
|
|
let codeFrames = [{
|
|
filePath: (_data$filePath = data.filePath) !== null && _data$filePath !== void 0 ? _data$filePath : undefined,
|
|
language: 'json',
|
|
code,
|
|
codeHighlights: (0, _diagnostic().generateJSONCodeHighlights)(map, keys.map(({
|
|
key,
|
|
type,
|
|
message
|
|
}) => {
|
|
var _data$prependKey;
|
|
|
|
return {
|
|
key: ((_data$prependKey = data.prependKey) !== null && _data$prependKey !== void 0 ? _data$prependKey : '') + key,
|
|
type: type,
|
|
message: message != null ? (0, _diagnostic().escapeMarkdown)(message) : message
|
|
};
|
|
}))
|
|
}];
|
|
throw new (_diagnostic().default)({
|
|
diagnostic: {
|
|
message: message,
|
|
origin,
|
|
codeFrames
|
|
}
|
|
});
|
|
}
|
|
}; |