expand-value
Version:
Get deeply nested values from an object, like dot-prop and get-value, but with support for advanced features like bracket-notation and more.
297 lines (291 loc) • 7.64 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// src/nodes/Location.ts
var Position = class {
static {
__name(this, "Position");
}
index;
line;
col;
constructor(loc) {
this.index = loc.index;
this.line = loc.line;
this.col = loc.col;
}
};
var Location = class {
static {
__name(this, "Location");
}
start;
end;
constructor(start, end) {
this.start = start;
this.end = end;
}
slice(input) {
return input.slice(...this.range);
}
get range() {
return [this.start.index, this.end.index];
}
get lines() {
return [this.start.line, this.end.line];
}
};
var location = /* @__PURE__ */ __name((loc) => {
const start = new Position(loc);
return (node) => {
node.loc = new Location(start, new Position(loc));
return node;
};
}, "location");
location.Position = Position;
location.Location = Location;
location.location = location;
// src/utils.ts
import isNumber from "is-number";
import { Segmenter } from "intl-segmenter";
var { defineProperty } = Reflect;
var isObject = /* @__PURE__ */ __name((val) => val && typeof val === "object" && !Array.isArray(val), "isObject");
var define = /* @__PURE__ */ __name((node, key, value) => {
defineProperty(node, key, {
configurable: true,
enumerable: false,
writable: true,
value
});
}, "define");
// src/nodes/Node.ts
var Node = class {
static {
__name(this, "Node");
}
type;
value;
output;
symbol;
parent;
constructor(node) {
this.type = node.type;
this.value = node.value || "";
if (node.output != null && node.output !== "") {
this.output = node.output;
}
if (node.symbol) {
this.symbol = node.symbol;
}
define(this, "alt", node.alt);
define(this, "match", node.match);
define(this, "loc", node.loc);
}
get siblings() {
return this.parent?.nodes || [];
}
};
// src/nodes/Block.ts
var Block = class extends Node {
static {
__name(this, "Block");
}
nodes;
constructor(node) {
super(node);
this.nodes = node.nodes || [];
}
append(input) {
this.parent && this.parent.append(input);
this.output = this.output || "";
this.output += input;
}
push(node) {
define(node, "parent", this);
this.nodes.push(node);
}
};
// src/nodes/Token.ts
var { defineProperty: defineProperty2 } = Reflect;
var Token = class {
static {
__name(this, "Token");
}
type;
value;
loc;
match;
constructor(token) {
this.type = token.type;
this.value = token.value;
defineProperty2(this, "loc", { value: token.loc, writable: true });
defineProperty2(this, "match", { value: token.match });
}
};
// src/parse.ts
var QUOTED_STRING = /^(['"`])((?:\\.|(?!\1)[\s\S])*?)(\1)/;
var IDENT_DOT = /^([a-zA-Z_][-a-zA-Z0-9_.]*(?<!\.))/;
var IDENT = /^([a-zA-Z_$][a-zA-Z0-9_$-]*(?<!-))/;
var NUMBER = /^(-?[0-9]+(?:\.[0-9]+)?|-?Infinity|NaN)/;
var RANGE = /^\.\.(?=[0-9a-z])/i;
var SYMBOL = /^Symbol\((.*?)\)/;
var parse = /* @__PURE__ */ __name((input = "", options = {}) => {
if (!isObject(options)) options = {};
const loc = { index: 0, line: 1, col: 0, row: 1 };
let pos = location(loc);
const str = String(input);
const ast = new Block({ type: "root" });
ast.output = "";
const stack = [ast];
const stash = [];
const tokens = [];
let remaining = str;
let block = ast;
let token;
let match;
let prev;
let separator = /^\./;
let IDENTITY = IDENT;
if (typeof options.separator === "string") {
separator = new RegExp(`^\\${options.separator.replace(/^[\\^]+/, "")}`);
IDENTITY = IDENT_DOT;
}
const eos = /* @__PURE__ */ __name(() => remaining === void 0 || remaining === "", "eos");
const scan = /* @__PURE__ */ __name((regex, type = "text") => {
if (match = regex.exec(remaining)) {
consume(match[0]);
return new Token({ type, value: match[0], match });
}
}, "scan");
const updateLocation = /* @__PURE__ */ __name((value, len) => {
const i = value.lastIndexOf("\n");
loc.index += len;
loc.col = ~i ? len - i : loc.col + len;
loc.row += Math.max(0, value.split("\n").length - 1);
}, "updateLocation");
const consume = /* @__PURE__ */ __name((value, len = value.length) => {
updateLocation(value, len);
remaining = remaining.slice(len);
return value;
}, "consume");
const drop = /* @__PURE__ */ __name(() => {
if (stash.length) {
block.push(stash.shift());
}
}, "drop");
const shouldPush = /* @__PURE__ */ __name((node) => {
return node.type !== "newline" || options.newlines !== false;
}, "shouldPush");
const push = /* @__PURE__ */ __name((node) => {
pos(node);
if (prev?.type === "ident" && node.type === "ident") {
block.append(node.output || node.match[0]);
prev.value += node.value;
return;
}
if (!shouldPush(node)) return;
block.push(node);
if (node.nodes) {
stack.push(node);
block = node;
} else {
block.append(node.output || node.match[0]);
tokens.push(node);
}
pos = location(loc);
prev = node;
if (block.type === "root") {
drop();
}
}, "push");
const pop = /* @__PURE__ */ __name(() => {
const parent = stack.pop();
block = stack[stack.length - 1];
return parent;
}, "pop");
const advance = /* @__PURE__ */ __name(() => {
if (token = scan(/^\\+/, "escaped")) {
if (token.value.length % 2 === 1) {
token.value += consume(remaining[0]);
}
if (token.value === "\\.") {
token.type = "ident";
token.value = ".";
token.output = "\\.";
}
push(new Node(token));
return;
}
if (token = scan(SYMBOL, "symbol")) {
token.value = token.match[1];
token.symbol = Symbol.for(token.value);
push(new Node(token));
return;
}
if (token = scan(/^\[/, "left_bracket")) {
token.index = tokens.length;
push(new Block({ type: "bracket" }));
push(new Node(token));
return;
}
if (token = scan(/^\]/, "right_bracket")) {
push(new Node(token));
if (block.type === "bracket") {
pop();
}
return;
}
if (token = scan(/^\(/, "left_paren")) {
token.index = tokens.length;
push(new Block({ type: "paren" }));
push(new Node(token));
return;
}
if (token = scan(/^\)/, "right_paren")) {
push(new Node(token));
if (block.type === "paren") {
pop();
}
return;
}
if (block.type === "bracket" && (token = scan(RANGE, "range"))) {
push(new Node(token));
return;
}
if (!options.separator && (token = scan(separator, "separator"))) {
push(new Node(token));
return;
}
if (token = scan(/^[0-9]+/, "integer")) {
push(new Node(token));
return;
}
if (token = scan(IDENTITY, "ident")) {
push(new Node(token));
return;
}
if (options.separator && options.separator !== ".") {
if (token = scan(separator, "separator")) {
push(new Node(token));
return;
}
}
if (token = scan(QUOTED_STRING, "quoted")) {
push(new Node(token));
return;
}
if (token = scan(NUMBER, "number")) {
if (token.value === "-0") {
token.alt = "0";
}
push(new Node(token));
return;
}
push(new Node(scan(/^(.)/, "text")));
}, "advance");
while (!eos()) advance();
return { ast, tokens, output: ast.output };
}, "parse");
export {
parse
};
//# sourceMappingURL=parse.mjs.map