UNPKG

astexplorer.app

Version:

https://astexplorer.net with ES Modules support and Hot Reloading

1 lines 29.1 kB
(window.webpackJsonp=window.webpackJsonp||[]).push([[81],{"./node_modules/@humanwhocodes/momoa/api.js":function(module,exports,__webpack_require__){"use strict";eval('\n\nObject.defineProperty(exports, \'__esModule\', { value: true });\n\n/**\n * @fileoverview JSON syntax helpers\n * @author Nicholas C. Zakas\n */\n\n//-----------------------------------------------------------------------------\n// Predefined Tokens\n//-----------------------------------------------------------------------------\n\nconst LBRACKET = "[";\nconst RBRACKET = "]";\nconst LBRACE = "{";\nconst RBRACE = "}";\nconst COLON = ":";\nconst COMMA = ",";\n\nconst TRUE = "true";\nconst FALSE = "false";\nconst NULL = "null";\n\nconst QUOTE = "\\"";\n\nconst expectedKeywords = new Map([\n ["t", TRUE],\n ["f", FALSE],\n ["n", NULL]\n]);\n\nconst escapeToChar = new Map([\n [QUOTE, QUOTE],\n ["\\\\", "\\\\"],\n ["/", "/"],\n ["b", "\\b"],\n ["n", "\\n"],\n ["f", "\\f"],\n ["r", "\\r"],\n ["t", "\\t"]\n]);\n\nconst knownTokenTypes = new Map([\n [LBRACKET, "Punctuator"],\n [RBRACKET, "Punctuator"],\n [LBRACE, "Punctuator"],\n [RBRACE, "Punctuator"],\n [COLON, "Punctuator"],\n [COMMA, "Punctuator"],\n [TRUE, "Boolean"],\n [FALSE, "Boolean"],\n [NULL, "Null"]\n]);\n\n/**\n * @fileoverview JSON tokenization/parsing errors\n * @author Nicholas C. Zakas\n */\n\n\n/**\n * Base class that attaches location to an error.\n */\nclass ErrorWithLocation extends Error {\n\n /**\n * \n * @param {string} message The error message to report. \n * @param {int} loc.line The line on which the error occurred.\n * @param {int} loc.column The column in the line where the error occurrred.\n * @param {int} loc.index The index in the string where the error occurred.\n */\n constructor(message, { line, column, index }) {\n super(`${ message } (${ line }:${ column})`);\n\n /**\n * The line on which the error occurred.\n * @type int\n * @property line\n */\n this.line = line;\n\n /**\n * The column on which the error occurred.\n * @type int\n * @property column\n */\n this.column = column;\n \n /**\n * The index into the string where the error occurred.\n * @type int\n * @property index\n */\n this.index = index;\n }\n\n}\n\n/**\n * Error thrown when an unexpected character is found during tokenizing.\n */\nclass UnexpectedChar extends ErrorWithLocation {\n\n /**\n * Creates a new instance.\n * @param {string} unexpected The character that was found.\n * @param {Object} loc The location information for the found character.\n */\n constructor(unexpected, loc) {\n super(`Unexpected character ${ unexpected } found.`, loc);\n }\n}\n\n/**\n * Error thrown when an unexpected token is found during parsing.\n */\nclass UnexpectedToken extends ErrorWithLocation {\n\n /**\n * Creates a new instance.\n * @param {string} expected The character that was expected. \n * @param {string} unexpected The character that was found.\n * @param {Object} loc The location information for the found character.\n */\n constructor(token) {\n super(`Unexpected token ${ token.type }(${ token.value }) found.`, token.loc.start);\n }\n}\n\n/**\n * Error thrown when the end of input is found where it isn\'t expected.\n */\nclass UnexpectedEOF extends ErrorWithLocation {\n\n /**\n * Creates a new instance.\n * @param {Object} loc The location information for the found character.\n */\n constructor(loc) {\n super("Unexpected end of input found.", loc);\n }\n}\n\n/**\n * @fileoverview JSON tokenizer\n * @author Nicholas C. Zakas\n */\n\n//-----------------------------------------------------------------------------\n// Helpers\n//-----------------------------------------------------------------------------\n\nconst QUOTE$1 = "\\"";\nconst SLASH = "/";\nconst STAR = "*";\n\nconst DEFAULT_OPTIONS = {\n comments: false,\n ranges: false\n};\n\nfunction isWhitespace(c) {\n return /[\\s\\n]/.test(c);\n}\n\nfunction isDigit(c) {\n return c >= "0" && c <= "9";\n}\n\nfunction isHexDigit(c) {\n return isDigit(c) || /[a-f]/i.test(c);\n}\n\nfunction isPositiveDigit(c) {\n return c >= "1" && c <= "9";\n}\n\nfunction isKeywordStart(c) {\n return /[tfn]/.test(c);\n}\n\nfunction isNumberStart(c) {\n return isDigit(c) || c === "." || c === "-";\n}\n\n//-----------------------------------------------------------------------------\n// Main\n//-----------------------------------------------------------------------------\n\n/**\n * Creates an iterator over the tokens representing the source text.\n * @param {string} text The source text to tokenize.\n * @returns {Iterator} An iterator over the tokens. \n */\nfunction tokenize(text, options) {\n\n options = Object.freeze({\n ...DEFAULT_OPTIONS,\n ...options\n });\n\n // normalize line endings\n text = text.replace(/\\n\\r?/g, "\\n");\n\n let offset = -1;\n let line = 1;\n let column = 0;\n let newLine = false;\n\n const tokens = [];\n\n\n function createToken(tokenType, value, startLoc, endLoc) {\n \n const endOffset = startLoc.offset + value.length;\n let range = options.ranges ? {\n range: [startLoc.offset, endOffset]\n } : undefined;\n \n return {\n type: tokenType,\n value,\n loc: {\n start: startLoc,\n end: endLoc || {\n line: startLoc.line,\n column: startLoc.column + value.length,\n offset: endOffset\n }\n },\n ...range\n };\n }\n\n function next() {\n let c = text.charAt(++offset);\n \n if (newLine) {\n line++;\n column = 1;\n newLine = false;\n } else {\n column++;\n }\n\n if (c === "\\r") {\n newLine = true;\n\n // if we already see a \\r, just ignore upcoming \\n\n if (text.charAt(offset + 1) === "\\n") {\n offset++;\n }\n } else if (c === "\\n") {\n newLine = true;\n }\n\n return c;\n }\n\n function locate() {\n return {\n line,\n column,\n offset\n };\n }\n\n function readKeyword(c) {\n\n // get the expected keyword\n let value = expectedKeywords.get(c);\n\n // check to see if it actually exists\n if (text.slice(offset, offset + value.length) === value) {\n offset += value.length - 1;\n column += value.length - 1;\n return { value, c: next() };\n }\n\n // find the first unexpected character\n for (let j = 1; j < value.length; j++) {\n if (value[j] !== text.charAt(offset + j)) {\n unexpected(next());\n }\n }\n\n }\n\n function readString(c) {\n let value = c;\n c = next();\n\n while (c !== QUOTE$1) {\n\n // escapes\n if (c === "\\\\") {\n value += c;\n c = next();\n\n if (escapeToChar.has(c)) {\n value += c;\n } else if (c === "u") {\n value += c;\n for (let i = 0; i < 4; i++) {\n c = next();\n if (isHexDigit(c)) {\n value += c;\n } else {\n unexpected(c);\n }\n }\n } else {\n unexpected(c);\n }\n } else {\n value += c;\n }\n\n c = next();\n }\n\n value += c;\n\n return { value, c: next() };\n }\n\n\n function readNumber(c) {\n\n let value = "";\n\n // Number may start with a minus but not a plus\n if (c === "-") {\n\n value += c;\n\n c = next();\n\n // Next digit cannot be zero\n if (!isDigit(c)) {\n unexpected(c);\n }\n\n }\n\n // Zero must be followed by a decimal point or nothing\n if (c === "0") {\n\n value += c;\n\n c = next();\n if (isDigit(c)) {\n unexpected(c);\n }\n\n } else {\n if (!isPositiveDigit(c)) {\n unexpected(c);\n }\n\n do {\n value += c;\n c = next();\n } while (isDigit(c));\n }\n\n // Decimal point may be followed by any number of digits\n if (c === ".") {\n\n do {\n value += c;\n c = next();\n } while (isDigit(c));\n }\n\n // Exponent is always last\n if (c === "e" || c === "E") {\n\n value += c;\n c = next();\n\n if (c === "+" || c === "-") {\n value += c;\n c = next();\n }\n\n while (isDigit(c)) {\n value += c;\n c = next();\n }\n }\n\n\n return { value, c };\n }\n\n /**\n * Reads in either a single-line or multi-line comment.\n * @param {string} c The first character of the comment.\n * @returns {string} The comment string.\n * @throws {UnexpectedChar} when the comment cannot be read.\n * @throws {UnexpectedEOF} when EOF is reached before the comment is\n * finalized.\n */\n function readComment(c) {\n\n let value = c;\n\n // next character determines single- or multi-line\n c = next();\n\n // single-line comments\n if (c === "/") {\n \n do {\n value += c;\n c = next();\n } while (c && c !== "\\r" && c !== "\\n");\n\n return { value, c };\n }\n\n // multi-line comments\n if (c === STAR) {\n\n while (c) {\n value += c;\n c = next();\n\n // check for end of comment\n if (c === STAR) {\n value += c;\n c = next();\n \n //end of comment\n if (c === SLASH) {\n value += c;\n\n /*\n * The single-line comment functionality cues up the\n * next character, so we do the same here to avoid\n * splitting logic later.\n */\n c = next();\n return { value, c };\n }\n }\n }\n\n unexpectedEOF();\n \n }\n\n // if we\'ve made it here, there\'s an invalid character\n unexpected(c); \n }\n\n\n /**\n * Convenience function for throwing unexpected character errors.\n * @param {string} c The unexpected character.\n * @returns {void}\n * @throws {UnexpectedChar} always.\n */\n function unexpected(c) {\n throw new UnexpectedChar(c, locate());\n }\n\n /**\n * Convenience function for throwing unexpected EOF errors.\n * @returns {void}\n * @throws {UnexpectedEOF} always.\n */\n function unexpectedEOF() {\n throw new UnexpectedEOF(locate());\n }\n\n let c = next();\n\n while (offset < text.length) {\n\n while (isWhitespace(c)) {\n c = next();\n }\n\n if (!c) {\n break;\n }\n\n const start = locate();\n\n // check for easy case\n if (knownTokenTypes.has(c)) {\n tokens.push(createToken(knownTokenTypes.get(c), c, start));\n c = next();\n } else if (isKeywordStart(c)) {\n const result = readKeyword(c);\n let value = result.value;\n c = result.c;\n tokens.push(createToken(knownTokenTypes.get(value), value, start));\n } else if (isNumberStart(c)) {\n const result = readNumber(c);\n let value = result.value;\n c = result.c;\n tokens.push(createToken("Number", value, start));\n } else if (c === QUOTE$1) {\n const result = readString(c);\n let value = result.value;\n c = result.c;\n tokens.push(createToken("String", value, start));\n } else if (c === SLASH && options.comments) {\n const result = readComment(c);\n let value = result.value;\n c = result.c;\n tokens.push(createToken(value.startsWith("//") ? "LineComment" : "BlockComment", value, start, locate()));\n } else {\n unexpected(c);\n }\n }\n\n return tokens;\n\n}\n\n/**\n * @fileoverview Momoa JSON AST types\n * @author Nicholas C. Zakas\n */\n\nconst types = {\n document(body, parts = {}) {\n return {\n type: "Document",\n body,\n ...parts\n };\n },\n string(value, parts = {}) {\n return {\n type: "String",\n value,\n ...parts\n };\n },\n number(value, parts = {}) {\n return {\n type: "Number",\n value,\n ...parts\n };\n },\n boolean(value, parts = {}) {\n return {\n type: "Boolean",\n value,\n ...parts\n };\n },\n null(parts = {}) {\n return {\n type: "Null",\n value: "null",\n ...parts\n };\n },\n array(elements, parts = {}) {\n return {\n type: "Array",\n elements,\n ...parts\n };\n },\n object(members, parts = {}) {\n return {\n type: "Object",\n members,\n ...parts\n };\n },\n member(name, value, parts = {}) {\n return {\n type: "Member",\n name,\n value,\n ...parts\n };\n },\n\n};\n\n/**\n * @fileoverview JSON parser\n * @author Nicholas C. Zakas\n */\n\n//-----------------------------------------------------------------------------\n// Helpers\n//-----------------------------------------------------------------------------\n\nconst DEFAULT_OPTIONS$1 = {\n tokens: false,\n comments: false,\n ranges: false\n};\n\n/**\n * Converts a JSON-encoded string into a JavaScript string, interpreting each\n * escape sequence.\n * @param {Token} token The string token to convert into a JavaScript string.\n * @returns {string} A JavaScript string.\n */\nfunction getStringValue(token) {\n \n // slice off the quotation marks\n let value = token.value.slice(1, -1);\n let result = "";\n let escapeIndex = value.indexOf("\\\\");\n let lastIndex = 0;\n\n // While there are escapes, interpret them to build up the result\n while (escapeIndex >= 0) {\n\n // append the text that happened before the escape\n result += value.slice(lastIndex, escapeIndex);\n\n // get the character immediately after the \\\n const escapeChar = value.charAt(escapeIndex + 1);\n \n // check for the non-Unicode escape sequences first\n if (escapeToChar.has(escapeChar)) {\n result += escapeToChar.get(escapeChar);\n lastIndex = escapeIndex + 2;\n } else if (escapeChar === "u") {\n const hexCode = value.slice(escapeIndex + 2, escapeIndex + 6);\n if (hexCode.length < 4 || /[^0-9a-f]/i.test(hexCode)) {\n throw new ErrorWithLocation(\n `Invalid unicode escape \\\\u${ hexCode}.`,\n {\n line: token.loc.start.line,\n column: token.loc.start.column + escapeIndex,\n offset: token.loc.start.offset + escapeIndex\n }\n );\n }\n \n result += String.fromCharCode(parseInt(hexCode, 16));\n lastIndex = escapeIndex + 6;\n } else {\n throw new ErrorWithLocation(\n `Invalid escape \\\\${ escapeChar }.`,\n {\n line: token.loc.start.line,\n column: token.loc.start.column + escapeIndex,\n offset: token.loc.start.offset + escapeIndex\n }\n );\n }\n\n // find the next escape sequence\n escapeIndex = value.indexOf("\\\\", lastIndex);\n }\n\n // get the last segment of the string value\n result += value.slice(lastIndex);\n\n return result;\n}\n\n/**\n * Gets the JavaScript value represented by a JSON token.\n * @param {Token} token The JSON token to get a value for.\n * @returns {*} A number, string, boolean, or `null`. \n */\nfunction getLiteralValue(token) {\n switch (token.type) {\n case "Boolean":\n return token.value === "true";\n \n case "Number":\n return Number(token.value);\n\n case "Null":\n return null;\n\n case "String":\n return getStringValue(token);\n }\n}\n\n//-----------------------------------------------------------------------------\n// Main Function\n//-----------------------------------------------------------------------------\n\n/**\n * \n * @param {string} text The text to parse.\n * @param {boolean} [options.tokens=false] Determines if tokens are returned in\n * the AST. \n * @param {boolean} [options.comments=false] Determines if comments are allowed\n * in the JSON.\n * @param {boolean} [options.ranges=false] Determines if ranges will be returned\n * in addition to `loc` properties.\n * @returns {Object} The AST representing the parsed JSON.\n * @throws {Error} When there is a parsing error. \n */\nfunction parse(text, options) {\n\n options = Object.freeze({\n ...DEFAULT_OPTIONS$1,\n ...options\n });\n\n const tokens = tokenize(text, {\n comments: !!options.comments,\n ranges: !!options.ranges\n });\n let tokenIndex = 0;\n\n function nextNoComments() {\n return tokens[tokenIndex++];\n }\n \n function nextSkipComments() {\n const nextToken = tokens[tokenIndex++];\n if (nextToken && nextToken.type.endsWith("Comment")) {\n return nextSkipComments();\n }\n\n return nextToken;\n\n }\n\n // determine correct way to evaluate tokens based on presence of comments\n const next = options.comments ? nextSkipComments : nextNoComments;\n\n function assertTokenValue(token, value) {\n if (!token || token.value !== value) {\n throw new UnexpectedToken(token);\n }\n }\n\n function assertTokenType(token, type) {\n if (!token || token.type !== type) {\n throw new UnexpectedToken(token);\n }\n }\n\n function createRange(start, end) {\n return options.ranges ? {\n range: [start.offset, end.offset]\n } : undefined;\n }\n\n function createLiteralNode(token) {\n const range = createRange(token.loc.start, token.loc.end);\n\n return {\n type: token.type,\n value: getLiteralValue(token),\n loc: {\n start: {\n ...token.loc.start\n },\n end: {\n ...token.loc.end\n }\n },\n ...range\n };\n }\n\n\n function parseProperty(token) {\n assertTokenType(token, "String");\n const name = createLiteralNode(token);\n\n token = next();\n assertTokenValue(token, ":");\n const value = parseValue();\n const range = createRange(name.loc.start, value.loc.end);\n\n return types.member(name, value, {\n loc: {\n start: {\n ...name.loc.start\n },\n end: {\n ...value.loc.end\n }\n },\n ...range\n });\n }\n\n function parseObject(firstToken) {\n\n // The first token must be a { or else it\'s an error\n assertTokenValue(firstToken, "{");\n\n const members = [];\n let token = next();\n\n while (token && token.value !== "}") {\n\n // add the value into the array\n members.push(parseProperty(token));\n\n token = next();\n\n if (token.value === ",") {\n token = next();\n } else {\n break;\n }\n }\n\n assertTokenValue(token, "}");\n const range = createRange(firstToken.loc.start, token.loc.end);\n\n return types.object(members, {\n loc: {\n start: {\n ...firstToken.loc.start\n },\n end: {\n ...token.loc.end\n }\n },\n ...range\n });\n\n }\n\n function parseArray(firstToken) {\n\n // The first token must be a [ or else it\'s an error\n assertTokenValue(firstToken, "[");\n\n const elements = [];\n let token = next();\n \n while (token && token.value !== "]") {\n\n // add the value into the array\n elements.push(parseValue(token));\n\n token = next();\n \n if (token.value === ",") {\n token = next();\n } else {\n break;\n }\n }\n\n assertTokenValue(token, "]");\n const range = createRange(firstToken.loc.start, token.loc.end);\n\n return types.array(elements, {\n type: "Array",\n elements,\n loc: {\n start: {\n ...firstToken.loc.start\n },\n end: {\n ...token.loc.end\n }\n },\n ...range\n });\n\n }\n\n\n\n function parseValue(token) {\n\n token = token || next();\n \n switch (token.type) {\n case "String":\n case "Boolean":\n case "Number":\n case "Null":\n return createLiteralNode(token);\n\n case "Punctuator":\n if (token.value === "{") {\n return parseObject(token);\n } else if (token.value === "[") {\n return parseArray(token);\n }\n /*falls through*/\n\n default:\n throw new UnexpectedToken(token);\n }\n\n }\n\n \n const docBody = parseValue();\n \n const unexpectedToken = next();\n if (unexpectedToken) {\n throw new UnexpectedToken(unexpectedToken);\n }\n \n \n const docParts = {\n loc: {\n start: {\n line: 1,\n column: 1,\n offset: 0\n },\n end: {\n ...docBody.loc.end\n }\n }\n };\n \n\n if (options.tokens) {\n docParts.tokens = tokens;\n }\n\n if (options.ranges) {\n docParts.range = createRange(docParts.loc.start, docParts.loc.end);\n }\n\n return types.document(docBody, docParts);\n\n}\n\n/**\n * @fileoverview Traversal approaches for Momoa JSON AST.\n * @author Nicholas C. Zakas\n */\n\n//-----------------------------------------------------------------------------\n// Data\n//-----------------------------------------------------------------------------\n\nconst childKeys = new Map([\n ["Document", ["body"]],\n ["Object", ["members"]],\n ["Member", ["name", "value"]],\n ["Array", ["elements"]],\n ["String", []],\n ["Number", []],\n ["Boolean", []],\n ["Null", []]\n]);\n\n//-----------------------------------------------------------------------------\n// Helpers\n//-----------------------------------------------------------------------------\n\n/**\n * Determines if a given value is an object.\n * @param {*} value The value to check.\n * @returns {boolean} True if the value is an object, false if not. \n */\nfunction isObject(value) {\n return value && (typeof value === "object");\n}\n\n/**\n * Determines if a given value is an AST node.\n * @param {*} value The value to check.\n * @returns {boolean} True if the value is a node, false if not. \n */\nfunction isNode(value) {\n return isObject(value) && (typeof value.type === "string");\n}\n\n//-----------------------------------------------------------------------------\n// Exports\n//-----------------------------------------------------------------------------\n\n/**\n * Traverses an AST from the given node.\n * @param {Node} root The node to traverse from \n * @param {Object} visitor An object with an `enter` and `exit` method. \n */\nfunction traverse(root, visitor) {\n\n /**\n * Recursively visits a node.\n * @param {Node} node The node to visit.\n * @param {Node} parent The parent of the node to visit.\n * @returns {void}\n */\n function visitNode(node, parent) {\n\n if (typeof visitor.enter === "function") {\n visitor.enter(node, parent);\n }\n\n for (const key of childKeys.get(node.type)) {\n const value = node[key];\n\n if (isObject(value)) {\n if (Array.isArray(value)) {\n value.forEach(child => visitNode(child, node));\n } else if (isNode(value)) {\n visitNode(value, node);\n }\n }\n }\n\n if (typeof visitor.exit === "function") {\n visitor.exit(node, parent);\n }\n }\n\n visitNode(root);\n}\n\n/**\n * Creates an iterator over the given AST.\n * @param {Node} root The root AST node to traverse. \n * @param {Function} [filter] A filter function to determine which steps to\n * return;\n * @returns {Iterator} An iterator over the AST. \n */\nfunction iterator(root, filter = () => true) {\n\n const traversal = [];\n\n traverse(root, {\n enter(node, parent) {\n traversal.push({ node, parent, phase: "enter" });\n },\n exit(node, parent) {\n traversal.push({ node, parent, phase: "exit" });\n }\n });\n\n return traversal.filter(filter).values();\n}\n\n/**\n * @fileoverview Evaluator for Momoa AST.\n * @author Nicholas C. Zakas\n */\n\n//-----------------------------------------------------------------------------\n// Exports\n//-----------------------------------------------------------------------------\n\n/**\n * Evaluates a Momoa AST node into a JavaScript value.\n * @param {Node} node The node to interpet.\n * @returns {*} The JavaScript value for the node. \n */\nfunction evaluate(node) {\n switch (node.type) {\n case "String":\n case "Number":\n case "Boolean":\n return node.value;\n\n case "Null":\n return null;\n\n case "Array":\n return node.elements.map(evaluate);\n\n case "Object": {\n\n const object = {};\n\n node.members.forEach(member => {\n object[evaluate(member.name)] = evaluate(member.value);\n }); \n\n return object;\n } \n\n case "Document":\n return evaluate(node.body);\n\n case "Property":\n throw new Error("Cannot evaluate object property outside of an object.");\n\n default:\n throw new Error(`Unknown node type ${ node.type }.`);\n }\n}\n\n/**\n * @fileoverview Printer for Momoa AST.\n * @author Nicholas C. Zakas\n */\n\n//-----------------------------------------------------------------------------\n// Exports\n//-----------------------------------------------------------------------------\n\n/**\n * Converts a Momoa AST back into a JSON string.\n * @param {Node} node The node to print.\n * @param {int} [options.indent=0] The number of spaces to indent each line. If\n * greater than 0, then newlines and indents will be added to output. \n * @returns {string} The JSON representation of the AST.\n */\nfunction print(node, { indent = 0 } = {}) {\n const value = evaluate(node);\n return JSON.stringify(value, null, indent);\n}\n\n/**\n * @fileoverview File defining the interface of the package.\n * @author Nicholas C. Zakas\n */\n\nexports.evaluate = evaluate;\nexports.iterator = iterator;\nexports.parse = parse;\nexports.print = print;\nexports.tokenize = tokenize;\nexports.traverse = traverse;\nexports.types = types;\n\n\n//# sourceURL=webpack:///./node_modules/@humanwhocodes/momoa/api.js?')}}]);