UNPKG

codemirror-json-schema

Version:

Codemirror 6 extensions that provide full JSONSchema support for `@codemirror/lang-json` and `codemirror-json5`

95 lines (94 loc) 4.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getJsonPointers = exports.jsonPointerForPosition = exports.resolveTokenName = void 0; exports.getJsonPointerAt = getJsonPointerAt; const language_1 = require("@codemirror/language"); const constants_1 = require("../constants"); const node_1 = require("./node"); const resolveTokenName = (nodeName, mode) => { var _a, _b; switch (mode) { case constants_1.MODES.YAML: return (_a = constants_1.YAML_TOKENS_MAPPING[nodeName]) !== null && _a !== void 0 ? _a : nodeName; case constants_1.MODES.JSON5: return (_b = constants_1.JSON5_TOKENS_MAPPING[nodeName]) !== null && _b !== void 0 ? _b : nodeName; default: return nodeName; } }; exports.resolveTokenName = resolveTokenName; // adapted from https://discuss.codemirror.net/t/json-pointer-at-cursor-seeking-implementation-critique/4793/3 // this could be useful for other things later! function getJsonPointerAt(docText, node, mode) { const path = []; for (let n = node; n === null || n === void 0 ? void 0 : n.parent; n = n.parent) { switch ((0, exports.resolveTokenName)(n.parent.name, mode)) { case constants_1.TOKENS.PROPERTY: { const name = (0, node_1.getMatchingChildNode)(n.parent, constants_1.TOKENS.PROPERTY_NAME, mode); if (name) { let word = (0, node_1.getWord)(docText, name).replace(/[/~]/g, (v) => v === "~" ? "~0" : "~1"); // TODO generally filter out pointers to objects being started? // if (word !== '') { path.unshift(word); // } } break; } case constants_1.TOKENS.ARRAY: { if ((0, node_1.isValueNode)(n, mode)) { const index = (0, node_1.findNodeIndexInArrayNode)(n.parent, n, mode); path.unshift(`${index}`); } break; } } } if (path.length === 0) { // TODO json-schema-library does not seem to like / as root pointer (it probably just uses split and it will return two empty strings). So is this fine? And why is it not prefixed with #? return ""; } return "/" + path.join("/"); } /** * retrieve a JSON pointer for a given position in the editor * @group Utilities */ const jsonPointerForPosition = (state, pos, side = -1, mode) => { return getJsonPointerAt(state.doc, (0, language_1.syntaxTree)(state).resolve(pos, side), mode); }; exports.jsonPointerForPosition = jsonPointerForPosition; /** * retrieve a Map of all the json pointers in a document * @group Utilities */ const getJsonPointers = (state, mode) => { const tree = (0, language_1.syntaxTree)(state); const pointers = new Map(); tree.iterate({ enter: (type) => { var _a, _b, _c, _d, _e, _f, _g, _h; if ([constants_1.TOKENS.PROPERTY_NAME, constants_1.TOKENS.OBJECT].includes((0, exports.resolveTokenName)(type.name, mode))) { const pointer = getJsonPointerAt(state.doc, type.node, mode); const { from: keyFrom, to: keyTo } = type.node; // if there's no value, we can't get the valueFrom/to if (!((_b = (_a = type.node) === null || _a === void 0 ? void 0 : _a.nextSibling) === null || _b === void 0 ? void 0 : _b.node)) { pointers.set(pointer, { keyFrom, keyTo }); return true; } // TODO: Make this generic enough to avoid mode-specific checks const nextNode = mode === constants_1.MODES.JSON ? (_d = (_c = type.node) === null || _c === void 0 ? void 0 : _c.nextSibling) === null || _d === void 0 ? void 0 : _d.node : (_h = (_g = (_f = (_e = type.node) === null || _e === void 0 ? void 0 : _e.nextSibling) === null || _f === void 0 ? void 0 : _f.node) === null || _g === void 0 ? void 0 : _g.nextSibling) === null || _h === void 0 ? void 0 : _h.node; if (!nextNode) { pointers.set(pointer, { keyFrom, keyTo }); return true; } const { from: valueFrom, to: valueTo } = nextNode; pointers.set(pointer, { keyFrom, keyTo, valueFrom, valueTo }); return true; } }, }); return pointers; }; exports.getJsonPointers = getJsonPointers;