UNPKG

mongoku

Version:

[![CI](https://github.com/huggingface/Mongoku/actions/workflows/ci.yml/badge.svg)](https://github.com/huggingface/Mongoku/actions/workflows/ci.yml)

183 lines (180 loc) 5.39 kB
import { parseScript } from 'esprima'; const ALLOWED_AGGREGATION_STAGES = /* @__PURE__ */ new Set([ "$addFields", "$bucket", "$bucketAuto", "$collStats", "$count", "$densify", "$documents", "$facet", "$fill", "$geoNear", "$graphLookup", "$group", "$indexStats", "$limit", "$listClusterCatalog", "$listSampledQueries", "$listSearchIndexes", "$listSessions", "$lookup", "$match", "$project", "$querySettings", "$queryStats", "$rankFusion", "$redact", "$replaceRoot", "$replaceWith", "$sample", "$search", "$searchMeta", "$set", "$setWindowFields", "$skip", "$sort", "$sortByCount", "$unionWith", "$unset", "$unwind", "$vectorSearch" ]); function validateAggregationPipeline(pipeline) { for (let i = 0; i < pipeline.length; i++) { const stage = pipeline[i]; if (!stage || typeof stage !== "object") { throw new Error(`Invalid stage at index ${i}: must be an object`); } const stageKeys = Object.keys(stage); if (stageKeys.length !== 1) { throw new Error(`Invalid stage at index ${i}: must have exactly one key, found ${stageKeys.length}`); } const stageOperator = stageKeys[0]; if (!ALLOWED_AGGREGATION_STAGES.has(stageOperator)) { throw new Error( `Disallowed stage operator at index ${i}: "${stageOperator}". Only allowed stages are permitted, to avoid future write stages like '$merge' or '$out'.` ); } } } function isEmptyObject(obj) { for (const key in obj) { return false; } return true; } function buildObject(node) { switch (node.type) { case "ObjectExpression": { const obj = {}; for (const prop of node.properties) { let name; if (prop.type === "SpreadElement") { throw new Error(`Expected "Property" but received: ${prop.type}`); } if (prop.key.type === "Identifier") { name = prop.key.name; } else if (prop.key.type === "Literal") { if (prop.key.value instanceof RegExp || typeof prop.key.value === "bigint" || prop.key.value === false || prop.key.value === null || prop.key.value === true || prop.key.value === void 0) { throw new Error(`Expected "Identifier" for object key but received: ${prop.key.type}`); } name = prop.key.value; } else { throw new Error(`Expected "Identifier" but received: ${prop.key.type}`); } obj[name] = buildObject(prop.value); } return obj; } case "ArrayExpression": { const obj = []; for (const prop of node.elements) { if (prop === null) { throw new Error(`Expected "Expression" but received: ${prop}`); } obj.push(buildObject(prop)); } return obj; } case "Literal": { if (node.value instanceof RegExp) { return { $type: "RegExp", $value: { $pattern: node.value.source, $flags: node.value.flags } }; } return node.value; } case "UnaryExpression": { if (node.operator === "-" && node.argument.type === "Literal" && typeof node.argument.value === "number") { return -node.argument.value; } throw new Error(`${node.type} are not authorized`); } case "NewExpression": case "CallExpression": { const authorizedCalls = ["ObjectId", "Date", "RegExp", "BinData"]; const callee = node.callee.type === "Identifier" ? node.callee.name : null; if (callee && authorizedCalls.includes(callee)) { if (callee === "RegExp") { const [pattern, flags] = node.arguments.map((arg) => buildObject(arg)); return { $type: "RegExp", $value: { $pattern: pattern, $flags: flags } }; } if (callee === "BinData") { const [subType, base64] = node.arguments.map((arg) => buildObject(arg)); return { $type: "Binary", $value: base64, $subType: subType }; } return { $type: callee, $value: buildObject(node.arguments[0]) }; } else { throw new Error(`Unknown ${node.type}: ${callee}`); } } case "Identifier": { if (node.name === "undefined") { return void 0; } if (node.name === "Infinity") { return Infinity; } throw `Unknown identifier: ${node.name}`; } default: throw new Error(`Sorry but ${node.type} are not authorized`); } } function parseJSON(text, opts) { const tree = parseScript(`var __JSON__ = ${text};`, { tolerant: true }); const varDeclaration = tree.body[0]; if (varDeclaration.type !== "VariableDeclaration") { throw new Error("Expected VariableDeclaration but received: " + varDeclaration.type); } const objExpression = varDeclaration.declarations[0].init; if (opts?.allowArray && objExpression?.type === "ArrayExpression") { return buildObject(objExpression); } if (objExpression?.type !== "ObjectExpression") { throw new Error("Expected ObjectExpression but received: " + objExpression?.type); } return buildObject(objExpression); } export { isEmptyObject as i, parseJSON as p, validateAggregationPipeline as v }; //# sourceMappingURL=jsonParser-C3QUcODD.js.map