From 5abdd8de19a06d3829ac0cc4fd0fb581ed40dcf1 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Wed, 8 Jul 2026 13:11:36 +0530 Subject: [PATCH 01/23] Parse window frame clauses (ROWS/RANGE/GROUPS ... BETWEEN) Adds the frame clause to OVER(): [ROWS | RANGE | GROUPS] ( | BETWEEN AND ) with UNBOUNDED PRECEDING/FOLLOWING, CURRENT ROW and PRECEDING/FOLLOWING bounds. Offsets are restricted to integer literals, parameters or parenthesized expressions (a general expr would be ambiguous against the keyword bounds). New AST nodes: CallOver.frame, CallOverFrame, FrameBound - emitted by toSql and covered by roundtripping specs. Co-Authored-By: Claude Fable 5 --- bun.lock | 2059 +++++++++++++++++++++++++++++++++++++++ src/syntax/ast.ts | 13 + src/syntax/base.ne | 6 + src/syntax/expr.ne | 27 + src/syntax/expr.spec.ts | 56 ++ src/to-sql.ts | 22 +- 6 files changed, 2182 insertions(+), 1 deletion(-) create mode 100644 bun.lock diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..ccdce68 --- /dev/null +++ b/bun.lock @@ -0,0 +1,2059 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "pgsql-ast-parser", + "dependencies": { + "moo": "^0.5.1", + "nearley": "^2.19.5", + }, + "devDependencies": { + "@types/chai": "^4.2.11", + "@types/mocha": "^8.0.0", + "@types/moo": "^0.5.3", + "@types/nearley": "^2.11.1", + "chai": "^4.2.0", + "copy-webpack-plugin": "^6.0.3", + "cross-env": "^7.0.2", + "istanbul-instrumenter-loader": "^3.0.1", + "mocha": "^8.0.1", + "mochapack": "^2.0.3", + "nyc": "^15.1.0", + "rimraf": "^3.0.2", + "ts-loader": "^8.0.0", + "ts-node": "^8.10.2", + "typescript": "^4.7.4", + "vscode-mocha-hmr": "^1.0.0", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.12", + "webpack-dev-server": "^4.10.0", + "webpack-node-externals": "^1.7.2", + }, + }, + }, + "packages": { + "@ampproject/remapping": ["@ampproject/remapping@2.2.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" } }, "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w=="], + + "@babel/code-frame": ["@babel/code-frame@7.16.7", "", { "dependencies": { "@babel/highlight": "^7.16.7" } }, "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg=="], + + "@babel/compat-data": ["@babel/compat-data@7.17.10", "", {}, "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw=="], + + "@babel/core": ["@babel/core@7.18.2", "", { "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.18.2", "@babel/helper-compilation-targets": "^7.18.2", "@babel/helper-module-transforms": "^7.18.0", "@babel/helpers": "^7.18.2", "@babel/parser": "^7.18.0", "@babel/template": "^7.16.7", "@babel/traverse": "^7.18.2", "@babel/types": "^7.18.2", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.1", "semver": "^6.3.0" } }, "sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ=="], + + "@babel/generator": ["@babel/generator@7.18.2", "", { "dependencies": { "@babel/types": "^7.18.2", "@jridgewell/gen-mapping": "^0.3.0", "jsesc": "^2.5.1" } }, "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.18.2", "", { "dependencies": { "@babel/compat-data": "^7.17.10", "@babel/helper-validator-option": "^7.16.7", "browserslist": "^4.20.2", "semver": "^6.3.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-s1jnPotJS9uQnzFtiZVBUxe67CuBa679oWFHpxYYnTpRL/1ffhyX44R9uYiXoa/pLXcY9H2moJta0iaanlk/rQ=="], + + "@babel/helper-environment-visitor": ["@babel/helper-environment-visitor@7.18.2", "", {}, "sha512-14GQKWkX9oJzPiQQ7/J36FTXcD4kSp8egKjO9nINlSKiHITRA9q/R74qu8S9xlc/b/yjsJItQUeeh3xnGN0voQ=="], + + "@babel/helper-function-name": ["@babel/helper-function-name@7.17.9", "", { "dependencies": { "@babel/template": "^7.16.7", "@babel/types": "^7.17.0" } }, "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg=="], + + "@babel/helper-hoist-variables": ["@babel/helper-hoist-variables@7.16.7", "", { "dependencies": { "@babel/types": "^7.16.7" } }, "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.16.7", "", { "dependencies": { "@babel/types": "^7.16.7" } }, "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.18.0", "", { "dependencies": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", "@babel/traverse": "^7.18.0", "@babel/types": "^7.18.0" } }, "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA=="], + + "@babel/helper-simple-access": ["@babel/helper-simple-access@7.18.2", "", { "dependencies": { "@babel/types": "^7.18.2" } }, "sha512-7LIrjYzndorDY88MycupkpQLKS1AFfsVRm2k/9PtKScSy5tZq0McZTj+DiMRynboZfIqOKvo03pmhTaUgiD6fQ=="], + + "@babel/helper-split-export-declaration": ["@babel/helper-split-export-declaration@7.16.7", "", { "dependencies": { "@babel/types": "^7.16.7" } }, "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.16.7", "", {}, "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.16.7", "", {}, "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ=="], + + "@babel/helpers": ["@babel/helpers@7.18.2", "", { "dependencies": { "@babel/template": "^7.16.7", "@babel/traverse": "^7.18.2", "@babel/types": "^7.18.2" } }, "sha512-j+d+u5xT5utcQSzrh9p+PaJX94h++KN+ng9b9WEJq7pkUPAd61FGqhjuUEdfknb3E/uDBb7ruwEeKkIxNJPIrg=="], + + "@babel/highlight": ["@babel/highlight@7.17.12", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg=="], + + "@babel/parser": ["@babel/parser@7.18.4", "", { "bin": { "parser": "bin/babel-parser.js" } }, "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow=="], + + "@babel/runtime-corejs2": ["@babel/runtime-corejs2@7.18.3", "", { "dependencies": { "core-js": "^2.6.12", "regenerator-runtime": "^0.13.4" } }, "sha512-r9L5eZChdP1DHSL+YwGEd7Rcs8Yk2KDOwSJ4cdB8ZAMolqiW7Qa9I1ir/05lte/i6N979PKYr5288OqoyZkabA=="], + + "@babel/template": ["@babel/template@7.16.7", "", { "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/parser": "^7.16.7", "@babel/types": "^7.16.7" } }, "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w=="], + + "@babel/traverse": ["@babel/traverse@7.18.2", "", { "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.18.2", "@babel/helper-environment-visitor": "^7.18.2", "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/parser": "^7.18.0", "@babel/types": "^7.18.2", "debug": "^4.1.0", "globals": "^11.1.0" } }, "sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA=="], + + "@babel/types": ["@babel/types@7.18.4", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" } }, "sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw=="], + + "@gar/promisify": ["@gar/promisify@1.1.3", "", {}, "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw=="], + + "@istanbuljs/load-nyc-config": ["@istanbuljs/load-nyc-config@1.1.0", "", { "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" } }, "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="], + + "@istanbuljs/schema": ["@istanbuljs/schema@0.1.3", "", {}, "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.1.1", "", { "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.0.7", "", {}, "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA=="], + + "@jridgewell/set-array": ["@jridgewell/set-array@1.1.1", "", {}, "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.4.13", "", {}, "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.13", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w=="], + + "@leichtgewicht/ip-codec": ["@leichtgewicht/ip-codec@2.0.4", "", {}, "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@npmcli/fs": ["@npmcli/fs@1.1.1", "", { "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" } }, "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ=="], + + "@npmcli/move-file": ["@npmcli/move-file@1.1.2", "", { "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" } }, "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg=="], + + "@types/body-parser": ["@types/body-parser@1.19.2", "", { "dependencies": { "@types/connect": "*", "@types/node": "*" } }, "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g=="], + + "@types/bonjour": ["@types/bonjour@3.5.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw=="], + + "@types/chai": ["@types/chai@4.3.1", "", {}, "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ=="], + + "@types/connect": ["@types/connect@3.4.35", "", { "dependencies": { "@types/node": "*" } }, "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ=="], + + "@types/connect-history-api-fallback": ["@types/connect-history-api-fallback@1.3.5", "", { "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" } }, "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw=="], + + "@types/express": ["@types/express@4.17.14", "", { "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.18", "@types/qs": "*", "@types/serve-static": "*" } }, "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg=="], + + "@types/express-serve-static-core": ["@types/express-serve-static-core@4.17.31", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*" } }, "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q=="], + + "@types/glob": ["@types/glob@7.2.0", "", { "dependencies": { "@types/minimatch": "*", "@types/node": "*" } }, "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA=="], + + "@types/http-proxy": ["@types/http-proxy@1.17.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw=="], + + "@types/json-schema": ["@types/json-schema@7.0.11", "", {}, "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ=="], + + "@types/mime": ["@types/mime@3.0.1", "", {}, "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA=="], + + "@types/minimatch": ["@types/minimatch@3.0.5", "", {}, "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="], + + "@types/mocha": ["@types/mocha@8.2.3", "", {}, "sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw=="], + + "@types/moo": ["@types/moo@0.5.5", "", {}, "sha512-eXQpwnkI4Ntw5uJg6i2PINdRFWLr55dqjuYQaLHNjvqTzF14QdNWbCbml9sza0byyXNA0hZlHtcdN+VNDcgVHA=="], + + "@types/nearley": ["@types/nearley@2.11.2", "", {}, "sha512-jeyIDNBxxyWyEk6HemDC+t32b4fxthVsgWDxf88qD2WpX0QpOyY8JvA80AElPTBGRUsO0EKnr6OeVOjK3ZDdnA=="], + + "@types/node": ["@types/node@14.18.18", "", {}, "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig=="], + + "@types/qs": ["@types/qs@6.9.7", "", {}, "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="], + + "@types/range-parser": ["@types/range-parser@1.2.4", "", {}, "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="], + + "@types/retry": ["@types/retry@0.12.0", "", {}, "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="], + + "@types/serve-index": ["@types/serve-index@1.9.1", "", { "dependencies": { "@types/express": "*" } }, "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg=="], + + "@types/serve-static": ["@types/serve-static@1.15.0", "", { "dependencies": { "@types/mime": "*", "@types/node": "*" } }, "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg=="], + + "@types/sockjs": ["@types/sockjs@0.3.33", "", { "dependencies": { "@types/node": "*" } }, "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw=="], + + "@types/ws": ["@types/ws@8.5.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w=="], + + "@ungap/promise-all-settled": ["@ungap/promise-all-settled@1.1.2", "", {}, "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q=="], + + "@webassemblyjs/ast": ["@webassemblyjs/ast@1.9.0", "", { "dependencies": { "@webassemblyjs/helper-module-context": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", "@webassemblyjs/wast-parser": "1.9.0" } }, "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA=="], + + "@webassemblyjs/floating-point-hex-parser": ["@webassemblyjs/floating-point-hex-parser@1.9.0", "", {}, "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA=="], + + "@webassemblyjs/helper-api-error": ["@webassemblyjs/helper-api-error@1.9.0", "", {}, "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw=="], + + "@webassemblyjs/helper-buffer": ["@webassemblyjs/helper-buffer@1.9.0", "", {}, "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA=="], + + "@webassemblyjs/helper-code-frame": ["@webassemblyjs/helper-code-frame@1.9.0", "", { "dependencies": { "@webassemblyjs/wast-printer": "1.9.0" } }, "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA=="], + + "@webassemblyjs/helper-fsm": ["@webassemblyjs/helper-fsm@1.9.0", "", {}, "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw=="], + + "@webassemblyjs/helper-module-context": ["@webassemblyjs/helper-module-context@1.9.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0" } }, "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g=="], + + "@webassemblyjs/helper-wasm-bytecode": ["@webassemblyjs/helper-wasm-bytecode@1.9.0", "", {}, "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw=="], + + "@webassemblyjs/helper-wasm-section": ["@webassemblyjs/helper-wasm-section@1.9.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", "@webassemblyjs/wasm-gen": "1.9.0" } }, "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw=="], + + "@webassemblyjs/ieee754": ["@webassemblyjs/ieee754@1.9.0", "", { "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg=="], + + "@webassemblyjs/leb128": ["@webassemblyjs/leb128@1.9.0", "", { "dependencies": { "@xtuc/long": "4.2.2" } }, "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw=="], + + "@webassemblyjs/utf8": ["@webassemblyjs/utf8@1.9.0", "", {}, "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w=="], + + "@webassemblyjs/wasm-edit": ["@webassemblyjs/wasm-edit@1.9.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", "@webassemblyjs/helper-wasm-section": "1.9.0", "@webassemblyjs/wasm-gen": "1.9.0", "@webassemblyjs/wasm-opt": "1.9.0", "@webassemblyjs/wasm-parser": "1.9.0", "@webassemblyjs/wast-printer": "1.9.0" } }, "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw=="], + + "@webassemblyjs/wasm-gen": ["@webassemblyjs/wasm-gen@1.9.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", "@webassemblyjs/ieee754": "1.9.0", "@webassemblyjs/leb128": "1.9.0", "@webassemblyjs/utf8": "1.9.0" } }, "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA=="], + + "@webassemblyjs/wasm-opt": ["@webassemblyjs/wasm-opt@1.9.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-buffer": "1.9.0", "@webassemblyjs/wasm-gen": "1.9.0", "@webassemblyjs/wasm-parser": "1.9.0" } }, "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A=="], + + "@webassemblyjs/wasm-parser": ["@webassemblyjs/wasm-parser@1.9.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-api-error": "1.9.0", "@webassemblyjs/helper-wasm-bytecode": "1.9.0", "@webassemblyjs/ieee754": "1.9.0", "@webassemblyjs/leb128": "1.9.0", "@webassemblyjs/utf8": "1.9.0" } }, "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA=="], + + "@webassemblyjs/wast-parser": ["@webassemblyjs/wast-parser@1.9.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/floating-point-hex-parser": "1.9.0", "@webassemblyjs/helper-api-error": "1.9.0", "@webassemblyjs/helper-code-frame": "1.9.0", "@webassemblyjs/helper-fsm": "1.9.0", "@xtuc/long": "4.2.2" } }, "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw=="], + + "@webassemblyjs/wast-printer": ["@webassemblyjs/wast-printer@1.9.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/wast-parser": "1.9.0", "@xtuc/long": "4.2.2" } }, "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA=="], + + "@xtuc/ieee754": ["@xtuc/ieee754@1.2.0", "", {}, "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="], + + "@xtuc/long": ["@xtuc/long@4.2.2", "", {}, "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="], + + "accepts": ["accepts@1.3.8", "", { "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" } }, "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw=="], + + "acorn": ["acorn@6.4.2", "", { "bin": "bin/acorn" }, "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="], + + "aggregate-error": ["aggregate-error@3.1.0", "", { "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" } }, "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ajv-errors": ["ajv-errors@1.0.1", "", { "peerDependencies": { "ajv": ">=5.0.0" } }, "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ=="], + + "ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" }, "peerDependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="], + + "ajv-keywords": ["ajv-keywords@3.5.2", "", { "peerDependencies": { "ajv": "^6.9.1" } }, "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="], + + "ansi-colors": ["ansi-colors@4.1.1", "", {}, "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="], + + "ansi-html-community": ["ansi-html-community@0.0.8", "", { "bin": { "ansi-html": "bin/ansi-html" } }, "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw=="], + + "ansi-regex": ["ansi-regex@3.0.1", "", {}, "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="], + + "ansi-styles": ["ansi-styles@3.2.1", "", { "dependencies": { "color-convert": "^1.9.0" } }, "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="], + + "anymatch": ["anymatch@3.1.2", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg=="], + + "append-transform": ["append-transform@2.0.0", "", { "dependencies": { "default-require-extensions": "^3.0.0" } }, "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg=="], + + "aproba": ["aproba@1.2.0", "", {}, "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="], + + "archy": ["archy@1.0.0", "", {}, "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="], + + "arg": ["arg@4.1.3", "", {}, "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "arr-diff": ["arr-diff@4.0.0", "", {}, "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA=="], + + "arr-flatten": ["arr-flatten@1.1.0", "", {}, "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="], + + "arr-union": ["arr-union@3.1.0", "", {}, "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q=="], + + "array-flatten": ["array-flatten@2.1.2", "", {}, "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ=="], + + "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], + + "array-unique": ["array-unique@0.3.2", "", {}, "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ=="], + + "asn1.js": ["asn1.js@5.4.1", "", { "dependencies": { "bn.js": "^4.0.0", "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0", "safer-buffer": "^2.1.0" } }, "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA=="], + + "assert": ["assert@1.5.0", "", { "dependencies": { "object-assign": "^4.1.1", "util": "0.10.3" } }, "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA=="], + + "assertion-error": ["assertion-error@1.1.0", "", {}, "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="], + + "assign-symbols": ["assign-symbols@1.0.0", "", {}, "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw=="], + + "async-each": ["async-each@1.0.3", "", {}, "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ=="], + + "atob": ["atob@2.1.2", "", { "bin": "bin/atob.js" }, "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="], + + "babel-code-frame": ["babel-code-frame@6.26.0", "", { "dependencies": { "chalk": "^1.1.3", "esutils": "^2.0.2", "js-tokens": "^3.0.2" } }, "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g=="], + + "babel-generator": ["babel-generator@6.26.1", "", { "dependencies": { "babel-messages": "^6.23.0", "babel-runtime": "^6.26.0", "babel-types": "^6.26.0", "detect-indent": "^4.0.0", "jsesc": "^1.3.0", "lodash": "^4.17.4", "source-map": "^0.5.7", "trim-right": "^1.0.1" } }, "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA=="], + + "babel-messages": ["babel-messages@6.23.0", "", { "dependencies": { "babel-runtime": "^6.22.0" } }, "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w=="], + + "babel-runtime": ["babel-runtime@6.26.0", "", { "dependencies": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" } }, "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g=="], + + "babel-template": ["babel-template@6.26.0", "", { "dependencies": { "babel-runtime": "^6.26.0", "babel-traverse": "^6.26.0", "babel-types": "^6.26.0", "babylon": "^6.18.0", "lodash": "^4.17.4" } }, "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg=="], + + "babel-traverse": ["babel-traverse@6.26.0", "", { "dependencies": { "babel-code-frame": "^6.26.0", "babel-messages": "^6.23.0", "babel-runtime": "^6.26.0", "babel-types": "^6.26.0", "babylon": "^6.18.0", "debug": "^2.6.8", "globals": "^9.18.0", "invariant": "^2.2.2", "lodash": "^4.17.4" } }, "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA=="], + + "babel-types": ["babel-types@6.26.0", "", { "dependencies": { "babel-runtime": "^6.26.0", "esutils": "^2.0.2", "lodash": "^4.17.4", "to-fast-properties": "^1.0.3" } }, "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g=="], + + "babylon": ["babylon@6.18.0", "", { "bin": "bin/babylon.js" }, "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base": ["base@0.11.2", "", { "dependencies": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", "component-emitter": "^1.2.1", "define-property": "^1.0.0", "isobject": "^3.0.1", "mixin-deep": "^1.2.0", "pascalcase": "^0.1.1" } }, "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "batch": ["batch@0.6.1", "", {}, "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw=="], + + "big.js": ["big.js@5.2.2", "", {}, "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="], + + "binary-extensions": ["binary-extensions@2.2.0", "", {}, "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="], + + "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], + + "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], + + "bn.js": ["bn.js@5.2.1", "", {}, "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="], + + "body-parser": ["body-parser@1.20.0", "", { "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.10.3", "raw-body": "2.5.1", "type-is": "~1.6.18", "unpipe": "1.0.0" } }, "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg=="], + + "bonjour-service": ["bonjour-service@1.0.14", "", { "dependencies": { "array-flatten": "^2.1.2", "dns-equal": "^1.0.0", "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ=="], + + "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], + + "braces": ["braces@3.0.2", "", { "dependencies": { "fill-range": "^7.0.1" } }, "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="], + + "brorand": ["brorand@1.1.0", "", {}, "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="], + + "browser-stdout": ["browser-stdout@1.3.1", "", {}, "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="], + + "browserify-aes": ["browserify-aes@1.2.0", "", { "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.3", "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA=="], + + "browserify-cipher": ["browserify-cipher@1.0.1", "", { "dependencies": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", "evp_bytestokey": "^1.0.0" } }, "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w=="], + + "browserify-des": ["browserify-des@1.0.2", "", { "dependencies": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A=="], + + "browserify-rsa": ["browserify-rsa@4.1.0", "", { "dependencies": { "bn.js": "^5.0.0", "randombytes": "^2.0.1" } }, "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog=="], + + "browserify-sign": ["browserify-sign@4.2.1", "", { "dependencies": { "bn.js": "^5.1.1", "browserify-rsa": "^4.0.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", "elliptic": "^6.5.3", "inherits": "^2.0.4", "parse-asn1": "^5.1.5", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" } }, "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg=="], + + "browserify-zlib": ["browserify-zlib@0.2.0", "", { "dependencies": { "pako": "~1.0.5" } }, "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA=="], + + "browserslist": ["browserslist@4.20.3", "", { "dependencies": { "caniuse-lite": "^1.0.30001332", "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", "node-releases": "^2.0.3", "picocolors": "^1.0.0" }, "bin": "cli.js" }, "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg=="], + + "buffer": ["buffer@4.9.2", "", { "dependencies": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", "isarray": "^1.0.0" } }, "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + + "buffer-xor": ["buffer-xor@1.0.3", "", {}, "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ=="], + + "builtin-status-codes": ["builtin-status-codes@3.0.0", "", {}, "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ=="], + + "bytes": ["bytes@3.0.0", "", {}, "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw=="], + + "cacache": ["cacache@15.3.0", "", { "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "glob": "^7.1.4", "infer-owner": "^1.0.4", "lru-cache": "^6.0.0", "minipass": "^3.1.1", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.2", "mkdirp": "^1.0.3", "p-map": "^4.0.0", "promise-inflight": "^1.0.1", "rimraf": "^3.0.2", "ssri": "^8.0.1", "tar": "^6.0.2", "unique-filename": "^1.1.1" } }, "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ=="], + + "cache-base": ["cache-base@1.0.1", "", { "dependencies": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", "get-value": "^2.0.6", "has-value": "^1.0.0", "isobject": "^3.0.1", "set-value": "^2.0.0", "to-object-path": "^0.3.0", "union-value": "^1.0.0", "unset-value": "^1.0.0" } }, "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ=="], + + "caching-transform": ["caching-transform@4.0.0", "", { "dependencies": { "hasha": "^5.0.0", "make-dir": "^3.0.0", "package-hash": "^4.0.0", "write-file-atomic": "^3.0.0" } }, "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA=="], + + "call-bind": ["call-bind@1.0.2", "", { "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" } }, "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA=="], + + "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001344", "", {}, "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g=="], + + "chai": ["chai@4.3.6", "", { "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", "deep-eql": "^3.0.1", "get-func-name": "^2.0.0", "loupe": "^2.3.1", "pathval": "^1.1.1", "type-detect": "^4.0.5" } }, "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q=="], + + "chalk": ["chalk@2.4.2", "", { "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="], + + "check-error": ["check-error@1.0.2", "", {}, "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA=="], + + "chokidar": ["chokidar@3.5.1", "", { "dependencies": { "anymatch": "~3.1.1", "braces": "~3.0.2", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.5.0" }, "optionalDependencies": { "fsevents": "~2.3.1" } }, "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw=="], + + "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + + "chrome-trace-event": ["chrome-trace-event@1.0.3", "", {}, "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg=="], + + "cipher-base": ["cipher-base@1.0.4", "", { "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q=="], + + "class-utils": ["class-utils@0.3.6", "", { "dependencies": { "arr-union": "^3.1.0", "define-property": "^0.2.5", "isobject": "^3.0.0", "static-extend": "^0.1.1" } }, "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg=="], + + "clean-stack": ["clean-stack@2.2.0", "", {}, "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="], + + "cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + + "co": ["co@4.6.0", "", {}, "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="], + + "collection-visit": ["collection-visit@1.0.0", "", { "dependencies": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" } }, "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw=="], + + "color-convert": ["color-convert@1.9.3", "", { "dependencies": { "color-name": "1.1.3" } }, "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="], + + "color-name": ["color-name@1.1.3", "", {}, "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="], + + "colorette": ["colorette@2.0.19", "", {}, "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ=="], + + "commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], + + "component-emitter": ["component-emitter@1.3.0", "", {}, "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="], + + "compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": ">= 1.43.0 < 2" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="], + + "compression": ["compression@1.7.4", "", { "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", "compressible": "~2.0.16", "debug": "2.6.9", "on-headers": "~1.0.2", "safe-buffer": "5.1.2", "vary": "~1.1.2" } }, "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "concat-stream": ["concat-stream@1.6.2", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" } }, "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw=="], + + "connect-history-api-fallback": ["connect-history-api-fallback@2.0.0", "", {}, "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA=="], + + "console-browserify": ["console-browserify@1.2.0", "", {}, "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA=="], + + "constants-browserify": ["constants-browserify@1.0.0", "", {}, "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ=="], + + "content-disposition": ["content-disposition@0.5.4", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="], + + "content-type": ["content-type@1.0.4", "", {}, "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="], + + "convert-source-map": ["convert-source-map@1.8.0", "", { "dependencies": { "safe-buffer": "~5.1.1" } }, "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA=="], + + "cookie": ["cookie@0.5.0", "", {}, "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="], + + "cookie-signature": ["cookie-signature@1.0.6", "", {}, "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="], + + "copy-concurrently": ["copy-concurrently@1.0.5", "", { "dependencies": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", "iferr": "^0.1.5", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.0" } }, "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A=="], + + "copy-descriptor": ["copy-descriptor@0.1.1", "", {}, "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw=="], + + "copy-webpack-plugin": ["copy-webpack-plugin@6.4.1", "", { "dependencies": { "cacache": "^15.0.5", "fast-glob": "^3.2.4", "find-cache-dir": "^3.3.1", "glob-parent": "^5.1.1", "globby": "^11.0.1", "loader-utils": "^2.0.0", "normalize-path": "^3.0.0", "p-limit": "^3.0.2", "schema-utils": "^3.0.0", "serialize-javascript": "^5.0.1", "webpack-sources": "^1.4.3" }, "peerDependencies": { "webpack": "^4.37.0 || ^5.0.0" } }, "sha512-MXyPCjdPVx5iiWyl40Va3JGh27bKzOTNY3NjUTrosD2q7dR/cLD0013uqJ3BpFbUjyONINjb6qI7nDIJujrMbA=="], + + "core-js": ["core-js@2.6.12", "", {}, "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + + "create-ecdh": ["create-ecdh@4.0.4", "", { "dependencies": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" } }, "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A=="], + + "create-hash": ["create-hash@1.2.0", "", { "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", "md5.js": "^1.3.4", "ripemd160": "^2.0.1", "sha.js": "^2.4.0" } }, "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg=="], + + "create-hmac": ["create-hmac@1.1.7", "", { "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", "inherits": "^2.0.1", "ripemd160": "^2.0.0", "safe-buffer": "^5.0.1", "sha.js": "^2.4.8" } }, "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg=="], + + "cross-env": ["cross-env@7.0.3", "", { "dependencies": { "cross-spawn": "^7.0.1" }, "bin": { "cross-env": "src/bin/cross-env.js", "cross-env-shell": "src/bin/cross-env-shell.js" } }, "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="], + + "cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="], + + "crypto-browserify": ["crypto-browserify@3.12.0", "", { "dependencies": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", "create-ecdh": "^4.0.0", "create-hash": "^1.1.0", "create-hmac": "^1.1.0", "diffie-hellman": "^5.0.0", "inherits": "^2.0.1", "pbkdf2": "^3.0.3", "public-encrypt": "^4.0.0", "randombytes": "^2.0.0", "randomfill": "^1.0.3" } }, "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg=="], + + "cyclist": ["cyclist@1.0.1", "", {}, "sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A=="], + + "debug": ["debug@4.3.1", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ=="], + + "decamelize": ["decamelize@1.2.0", "", {}, "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="], + + "decode-uri-component": ["decode-uri-component@0.2.0", "", {}, "sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og=="], + + "deep-eql": ["deep-eql@3.0.1", "", { "dependencies": { "type-detect": "^4.0.0" } }, "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw=="], + + "default-gateway": ["default-gateway@6.0.3", "", { "dependencies": { "execa": "^5.0.0" } }, "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg=="], + + "default-require-extensions": ["default-require-extensions@3.0.0", "", { "dependencies": { "strip-bom": "^4.0.0" } }, "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg=="], + + "define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="], + + "define-property": ["define-property@2.0.2", "", { "dependencies": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" } }, "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "des.js": ["des.js@1.0.1", "", { "dependencies": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" } }, "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA=="], + + "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], + + "detect-file": ["detect-file@1.0.0", "", {}, "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q=="], + + "detect-indent": ["detect-indent@4.0.0", "", { "dependencies": { "repeating": "^2.0.0" } }, "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A=="], + + "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], + + "diff": ["diff@5.0.0", "", {}, "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w=="], + + "diffie-hellman": ["diffie-hellman@5.0.3", "", { "dependencies": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" } }, "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg=="], + + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + + "discontinuous-range": ["discontinuous-range@1.0.0", "", {}, "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ=="], + + "dns-equal": ["dns-equal@1.0.0", "", {}, "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg=="], + + "dns-packet": ["dns-packet@5.4.0", "", { "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" } }, "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g=="], + + "domain-browser": ["domain-browser@1.2.0", "", {}, "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA=="], + + "duplexify": ["duplexify@3.7.1", "", { "dependencies": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" } }, "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "electron-to-chromium": ["electron-to-chromium@1.4.141", "", {}, "sha512-mfBcbqc0qc6RlxrsIgLG2wCqkiPAjEezHxGTu7p3dHHFOurH4EjS9rFZndX5axC8264rI1Pcbw8uQP39oZckeA=="], + + "elliptic": ["elliptic@6.5.4", "", { "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "emojis-list": ["emojis-list@3.0.0", "", {}, "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="], + + "encodeurl": ["encodeurl@1.0.2", "", {}, "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="], + + "end-of-stream": ["end-of-stream@1.4.4", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q=="], + + "enhanced-resolve": ["enhanced-resolve@4.5.0", "", { "dependencies": { "graceful-fs": "^4.1.2", "memory-fs": "^0.5.0", "tapable": "^1.0.0" } }, "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg=="], + + "errno": ["errno@0.1.8", "", { "dependencies": { "prr": "~1.0.1" }, "bin": "cli.js" }, "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A=="], + + "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], + + "escalade": ["escalade@3.1.1", "", {}, "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint-scope": ["eslint-scope@4.0.3", "", { "dependencies": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" } }, "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg=="], + + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "eventemitter3": ["eventemitter3@4.0.7", "", {}, "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="], + + "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + + "evp_bytestokey": ["evp_bytestokey@1.0.3", "", { "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA=="], + + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], + + "expand-brackets": ["expand-brackets@2.1.4", "", { "dependencies": { "debug": "^2.3.3", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "posix-character-classes": "^0.1.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" } }, "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA=="], + + "expand-tilde": ["expand-tilde@2.0.2", "", { "dependencies": { "homedir-polyfill": "^1.0.1" } }, "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw=="], + + "express": ["express@4.18.1", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.0", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.2.0", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", "qs": "6.10.3", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", "serve-static": "1.15.0", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q=="], + + "extend-shallow": ["extend-shallow@3.0.2", "", { "dependencies": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" } }, "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q=="], + + "extglob": ["extglob@2.0.4", "", { "dependencies": { "array-unique": "^0.3.2", "define-property": "^1.0.0", "expand-brackets": "^2.1.4", "extend-shallow": "^2.0.1", "fragment-cache": "^0.2.1", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" } }, "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.2.11", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" } }, "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fastq": ["fastq@1.13.0", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw=="], + + "faye-websocket": ["faye-websocket@0.11.4", "", { "dependencies": { "websocket-driver": ">=0.5.1" } }, "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g=="], + + "figgy-pudding": ["figgy-pudding@3.5.2", "", {}, "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw=="], + + "file-uri-to-path": ["file-uri-to-path@1.0.0", "", {}, "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="], + + "fill-range": ["fill-range@7.0.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ=="], + + "finalhandler": ["finalhandler@1.2.0", "", { "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", "statuses": "2.0.1", "unpipe": "~1.0.0" } }, "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg=="], + + "find-cache-dir": ["find-cache-dir@3.3.2", "", { "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" } }, "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "findup-sync": ["findup-sync@3.0.0", "", { "dependencies": { "detect-file": "^1.0.0", "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" } }, "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg=="], + + "flat": ["flat@5.0.2", "", { "bin": "cli.js" }, "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="], + + "flush-write-stream": ["flush-write-stream@1.1.1", "", { "dependencies": { "inherits": "^2.0.3", "readable-stream": "^2.3.6" } }, "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w=="], + + "follow-redirects": ["follow-redirects@1.15.2", "", {}, "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="], + + "for-in": ["for-in@1.0.2", "", {}, "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ=="], + + "foreground-child": ["foreground-child@2.0.0", "", { "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^3.0.2" } }, "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fragment-cache": ["fragment-cache@0.2.1", "", { "dependencies": { "map-cache": "^0.2.2" } }, "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA=="], + + "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], + + "from2": ["from2@2.3.0", "", { "dependencies": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" } }, "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g=="], + + "fromentries": ["fromentries@1.3.2", "", {}, "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg=="], + + "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], + + "fs-monkey": ["fs-monkey@1.0.3", "", {}, "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q=="], + + "fs-write-stream-atomic": ["fs-write-stream-atomic@1.0.10", "", { "dependencies": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", "imurmurhash": "^0.1.4", "readable-stream": "1 || 2" } }, "sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], + + "function-bind": ["function-bind@1.1.1", "", {}, "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-func-name": ["get-func-name@2.0.0", "", {}, "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig=="], + + "get-intrinsic": ["get-intrinsic@1.1.1", "", { "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", "has-symbols": "^1.0.1" } }, "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q=="], + + "get-package-type": ["get-package-type@0.1.0", "", {}, "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="], + + "get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + + "get-value": ["get-value@2.0.6", "", {}, "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA=="], + + "glob": ["glob@7.1.6", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA=="], + + "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "global-modules": ["global-modules@2.0.0", "", { "dependencies": { "global-prefix": "^3.0.0" } }, "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A=="], + + "global-prefix": ["global-prefix@3.0.0", "", { "dependencies": { "ini": "^1.3.5", "kind-of": "^6.0.2", "which": "^1.3.1" } }, "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg=="], + + "globals": ["globals@9.18.0", "", {}, "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="], + + "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], + + "graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="], + + "growl": ["growl@1.10.5", "", {}, "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="], + + "handle-thing": ["handle-thing@2.0.1", "", {}, "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg=="], + + "has": ["has@1.0.3", "", { "dependencies": { "function-bind": "^1.1.1" } }, "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="], + + "has-ansi": ["has-ansi@2.0.0", "", { "dependencies": { "ansi-regex": "^2.0.0" } }, "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-symbols": ["has-symbols@1.0.3", "", {}, "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="], + + "has-value": ["has-value@1.0.0", "", { "dependencies": { "get-value": "^2.0.6", "has-values": "^1.0.0", "isobject": "^3.0.0" } }, "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw=="], + + "has-values": ["has-values@1.0.0", "", { "dependencies": { "is-number": "^3.0.0", "kind-of": "^4.0.0" } }, "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ=="], + + "hash-base": ["hash-base@3.1.0", "", { "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", "safe-buffer": "^5.2.0" } }, "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA=="], + + "hash.js": ["hash.js@1.1.7", "", { "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.1" } }, "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA=="], + + "hasha": ["hasha@5.2.2", "", { "dependencies": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" } }, "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ=="], + + "he": ["he@1.2.0", "", { "bin": "bin/he" }, "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="], + + "hmac-drbg": ["hmac-drbg@1.0.1", "", { "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg=="], + + "homedir-polyfill": ["homedir-polyfill@1.0.3", "", { "dependencies": { "parse-passwd": "^1.0.0" } }, "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA=="], + + "hpack.js": ["hpack.js@2.1.6", "", { "dependencies": { "inherits": "^2.0.1", "obuf": "^1.0.0", "readable-stream": "^2.0.1", "wbuf": "^1.1.0" } }, "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ=="], + + "html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="], + + "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], + + "http-deceiver": ["http-deceiver@1.2.7", "", {}, "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw=="], + + "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], + + "http-parser-js": ["http-parser-js@0.5.6", "", {}, "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA=="], + + "http-proxy": ["http-proxy@1.18.1", "", { "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } }, "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ=="], + + "http-proxy-middleware": ["http-proxy-middleware@2.0.6", "", { "dependencies": { "@types/http-proxy": "^1.17.8", "http-proxy": "^1.18.1", "is-glob": "^4.0.1", "is-plain-obj": "^3.0.0", "micromatch": "^4.0.2" }, "peerDependencies": { "@types/express": "^4.17.13" } }, "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw=="], + + "https-browserify": ["https-browserify@1.0.0", "", {}, "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg=="], + + "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + + "iconv-lite": ["iconv-lite@0.4.24", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "iferr": ["iferr@0.1.5", "", {}, "sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA=="], + + "ignore": ["ignore@5.2.0", "", {}, "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="], + + "import-local": ["import-local@2.0.0", "", { "dependencies": { "pkg-dir": "^3.0.0", "resolve-cwd": "^2.0.0" }, "bin": { "import-local-fixture": "fixtures/cli.js" } }, "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + + "infer-owner": ["infer-owner@1.0.4", "", {}, "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A=="], + + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + + "interpret": ["interpret@1.4.0", "", {}, "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="], + + "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], + + "ipaddr.js": ["ipaddr.js@2.0.1", "", {}, "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng=="], + + "is-accessor-descriptor": ["is-accessor-descriptor@1.0.0", "", { "dependencies": { "kind-of": "^6.0.0" } }, "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-buffer": ["is-buffer@1.1.6", "", {}, "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="], + + "is-data-descriptor": ["is-data-descriptor@1.0.0", "", { "dependencies": { "kind-of": "^6.0.0" } }, "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ=="], + + "is-descriptor": ["is-descriptor@1.0.2", "", { "dependencies": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", "kind-of": "^6.0.2" } }, "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg=="], + + "is-docker": ["is-docker@2.2.1", "", { "bin": "cli.js" }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + + "is-extendable": ["is-extendable@1.0.1", "", { "dependencies": { "is-plain-object": "^2.0.4" } }, "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-finite": ["is-finite@1.1.0", "", {}, "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@2.0.0", "", {}, "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-number": ["is-number@3.0.0", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg=="], + + "is-plain-obj": ["is-plain-obj@2.1.0", "", {}, "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="], + + "is-plain-object": ["is-plain-object@2.0.4", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="], + + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "is-typedarray": ["is-typedarray@1.0.0", "", {}, "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="], + + "is-windows": ["is-windows@1.0.2", "", {}, "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="], + + "is-wsl": ["is-wsl@1.1.0", "", {}, "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw=="], + + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "isobject": ["isobject@3.0.1", "", {}, "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="], + + "istanbul-instrumenter-loader": ["istanbul-instrumenter-loader@3.0.1", "", { "dependencies": { "convert-source-map": "^1.5.0", "istanbul-lib-instrument": "^1.7.3", "loader-utils": "^1.1.0", "schema-utils": "^0.3.0" }, "peerDependencies": { "webpack": "^2.0.0 || ^3.0.0 || ^4.0.0" } }, "sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w=="], + + "istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.0", "", {}, "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw=="], + + "istanbul-lib-hook": ["istanbul-lib-hook@3.0.0", "", { "dependencies": { "append-transform": "^2.0.0" } }, "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ=="], + + "istanbul-lib-instrument": ["istanbul-lib-instrument@1.10.2", "", { "dependencies": { "babel-generator": "^6.18.0", "babel-template": "^6.16.0", "babel-traverse": "^6.18.0", "babel-types": "^6.18.0", "babylon": "^6.18.0", "istanbul-lib-coverage": "^1.2.1", "semver": "^5.3.0" } }, "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A=="], + + "istanbul-lib-processinfo": ["istanbul-lib-processinfo@2.0.2", "", { "dependencies": { "archy": "^1.0.0", "cross-spawn": "^7.0.0", "istanbul-lib-coverage": "^3.0.0-alpha.1", "make-dir": "^3.0.0", "p-map": "^3.0.0", "rimraf": "^3.0.0", "uuid": "^3.3.3" } }, "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw=="], + + "istanbul-lib-report": ["istanbul-lib-report@3.0.0", "", { "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", "supports-color": "^7.1.0" } }, "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw=="], + + "istanbul-lib-source-maps": ["istanbul-lib-source-maps@4.0.1", "", { "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" } }, "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw=="], + + "istanbul-reports": ["istanbul-reports@3.1.4", "", { "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" } }, "sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw=="], + + "js-tokens": ["js-tokens@3.0.2", "", {}, "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg=="], + + "js-yaml": ["js-yaml@4.0.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": "bin/js-yaml.js" }, "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q=="], + + "jsesc": ["jsesc@1.3.0", "", { "bin": "bin/jsesc" }, "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA=="], + + "json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json5": ["json5@2.2.1", "", { "bin": "lib/cli.js" }, "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="], + + "kind-of": ["kind-of@6.0.3", "", {}, "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="], + + "loader-runner": ["loader-runner@2.4.0", "", {}, "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw=="], + + "loader-utils": ["loader-utils@2.0.4", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^2.1.2" } }, "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], + + "lodash.flattendeep": ["lodash.flattendeep@4.4.0", "", {}, "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ=="], + + "log-symbols": ["log-symbols@4.0.0", "", { "dependencies": { "chalk": "^4.0.0" } }, "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": "cli.js" }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "loupe": ["loupe@2.3.4", "", { "dependencies": { "get-func-name": "^2.0.0" } }, "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ=="], + + "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + + "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "make-error": ["make-error@1.3.6", "", {}, "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="], + + "map-cache": ["map-cache@0.2.2", "", {}, "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="], + + "map-visit": ["map-visit@1.0.0", "", { "dependencies": { "object-visit": "^1.0.0" } }, "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48="], + + "md5.js": ["md5.js@1.3.5", "", { "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", "safe-buffer": "^5.1.2" } }, "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg=="], + + "media-typer": ["media-typer@0.3.0", "", {}, "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="], + + "memfs": ["memfs@3.4.11", "", { "dependencies": { "fs-monkey": "^1.0.3" } }, "sha512-GvsCITGAyDCxxsJ+X6prJexFQEhOCJaIlUbsAvjzSI5o5O7j2dle3jWvz5Z5aOdpOxW6ol3vI1+0ut+641F1+w=="], + + "memory-fs": ["memory-fs@0.4.1", "", { "dependencies": { "errno": "^0.1.3", "readable-stream": "^2.0.1" } }, "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI="], + + "merge-descriptors": ["merge-descriptors@1.0.1", "", {}, "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="], + + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "methods": ["methods@1.1.2", "", {}, "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="], + + "micromatch": ["micromatch@4.0.5", "", { "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" } }, "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA=="], + + "miller-rabin": ["miller-rabin@4.0.1", "", { "dependencies": { "bn.js": "^4.0.0", "brorand": "^1.0.1" }, "bin": "bin/miller-rabin" }, "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA=="], + + "mime": ["mime@1.6.0", "", { "bin": "cli.js" }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], + + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + + "minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="], + + "minimalistic-crypto-utils": ["minimalistic-crypto-utils@1.0.1", "", {}, "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="], + + "minimatch": ["minimatch@3.0.4", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA=="], + + "minimist": ["minimist@1.2.6", "", {}, "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="], + + "minipass": ["minipass@3.1.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ=="], + + "minipass-collect": ["minipass-collect@1.0.2", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA=="], + + "minipass-flush": ["minipass-flush@1.0.5", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw=="], + + "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], + + "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "mississippi": ["mississippi@3.0.0", "", { "dependencies": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", "end-of-stream": "^1.1.0", "flush-write-stream": "^1.0.0", "from2": "^2.1.0", "parallel-transform": "^1.1.0", "pump": "^3.0.0", "pumpify": "^1.3.3", "stream-each": "^1.1.0", "through2": "^2.0.0" } }, "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA=="], + + "mixin-deep": ["mixin-deep@1.3.2", "", { "dependencies": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" } }, "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA=="], + + "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": "bin/cmd.js" }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + + "mocha": ["mocha@8.4.0", "", { "dependencies": { "@ungap/promise-all-settled": "1.1.2", "ansi-colors": "4.1.1", "browser-stdout": "1.3.1", "chokidar": "3.5.1", "debug": "4.3.1", "diff": "5.0.0", "escape-string-regexp": "4.0.0", "find-up": "5.0.0", "glob": "7.1.6", "growl": "1.10.5", "he": "1.2.0", "js-yaml": "4.0.0", "log-symbols": "4.0.0", "minimatch": "3.0.4", "ms": "2.1.3", "nanoid": "3.1.20", "serialize-javascript": "5.0.1", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", "which": "2.0.2", "wide-align": "1.1.3", "workerpool": "6.1.0", "yargs": "16.2.0", "yargs-parser": "20.2.4", "yargs-unparser": "2.0.0" }, "bin": { "_mocha": "bin/_mocha", "mocha": "bin/mocha" } }, "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ=="], + + "mochapack": ["mochapack@2.1.4", "", { "dependencies": { "@babel/runtime-corejs2": "^7.0.0", "chalk": "^2.4.2", "chokidar": "^3.5.2", "glob-parent": "5.1.2", "globby": "^10.0.1", "interpret": "^1.2.0", "is-glob": "^4.0.1", "loader-utils": "^1.2.3", "lodash": "^4.17.15", "memory-fs": "^0.4.1", "minimatch": "^3.0.4", "nodent-runtime": "^3.2.1", "normalize-path": "^3.0.0", "progress": "^2.0.3", "source-map-support": "^0.5.13", "toposort": "^2.0.2", "yargs": "14.0.0" }, "peerDependencies": { "mocha": ">=6", "webpack": "^4.0.0 || ^5.0.0" }, "bin": "bin/mochapack" }, "sha512-qoZYT8ibht6z35e936P6Y/3nynFX843Jm+2l/pNWB3Sue63IHBfqZeAnF6Ypez85kUll7HtapMogfO2hGb2N2Q=="], + + "moo": ["moo@0.5.1", "", {}, "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w=="], + + "move-concurrently": ["move-concurrently@1.0.1", "", { "dependencies": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", "fs-write-stream-atomic": "^1.0.8", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "run-queue": "^1.0.3" } }, "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "multicast-dns": ["multicast-dns@7.2.5", "", { "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" }, "bin": "cli.js" }, "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg=="], + + "nan": ["nan@2.16.0", "", {}, "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA=="], + + "nanoid": ["nanoid@3.1.20", "", { "bin": "bin/nanoid.cjs" }, "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw=="], + + "nanomatch": ["nanomatch@1.2.13", "", { "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "fragment-cache": "^0.2.1", "is-windows": "^1.0.2", "kind-of": "^6.0.2", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.1" } }, "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA=="], + + "nearley": ["nearley@2.20.1", "", { "dependencies": { "commander": "^2.19.0", "moo": "^0.5.0", "railroad-diagrams": "^1.0.0", "randexp": "0.4.6" }, "bin": { "nearley-railroad": "bin/nearley-railroad.js", "nearley-test": "bin/nearley-test.js", "nearley-unparse": "bin/nearley-unparse.js", "nearleyc": "bin/nearleyc.js" } }, "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ=="], + + "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], + + "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], + + "nice-try": ["nice-try@1.0.5", "", {}, "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="], + + "node-forge": ["node-forge@1.3.1", "", {}, "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="], + + "node-libs-browser": ["node-libs-browser@2.2.1", "", { "dependencies": { "assert": "^1.1.1", "browserify-zlib": "^0.2.0", "buffer": "^4.3.0", "console-browserify": "^1.1.0", "constants-browserify": "^1.0.0", "crypto-browserify": "^3.11.0", "domain-browser": "^1.1.1", "events": "^3.0.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", "path-browserify": "0.0.1", "process": "^0.11.10", "punycode": "^1.2.4", "querystring-es3": "^0.2.0", "readable-stream": "^2.3.3", "stream-browserify": "^2.0.1", "stream-http": "^2.7.2", "string_decoder": "^1.0.0", "timers-browserify": "^2.0.4", "tty-browserify": "0.0.0", "url": "^0.11.0", "util": "^0.11.0", "vm-browserify": "^1.0.1" } }, "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q=="], + + "node-preload": ["node-preload@0.2.1", "", { "dependencies": { "process-on-spawn": "^1.0.0" } }, "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ=="], + + "node-releases": ["node-releases@2.0.5", "", {}, "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q=="], + + "nodent-runtime": ["nodent-runtime@3.2.1", "", {}, "sha512-7Ws63oC+215smeKJQCxzrK21VFVlCFBkwl0MOObt0HOpVQXs3u483sAmtkF33nNqZ5rSOQjB76fgyPBmAUrtCA=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + + "nyc": ["nyc@15.1.0", "", { "dependencies": { "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", "caching-transform": "^4.0.0", "convert-source-map": "^1.7.0", "decamelize": "^1.2.0", "find-cache-dir": "^3.2.0", "find-up": "^4.1.0", "foreground-child": "^2.0.0", "get-package-type": "^0.1.0", "glob": "^7.1.6", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-hook": "^3.0.0", "istanbul-lib-instrument": "^4.0.0", "istanbul-lib-processinfo": "^2.0.2", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", "make-dir": "^3.0.0", "node-preload": "^0.2.1", "p-map": "^3.0.0", "process-on-spawn": "^1.0.0", "resolve-from": "^5.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "spawn-wrap": "^2.0.0", "test-exclude": "^6.0.0", "yargs": "^15.0.2" }, "bin": "bin/nyc.js" }, "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="], + + "object-copy": ["object-copy@0.1.0", "", { "dependencies": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", "kind-of": "^3.0.3" } }, "sha1-fn2Fi3gb18mRpBupde04EnVOmYw="], + + "object-inspect": ["object-inspect@1.12.2", "", {}, "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ=="], + + "object-visit": ["object-visit@1.0.1", "", { "dependencies": { "isobject": "^3.0.0" } }, "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs="], + + "object.pick": ["object.pick@1.3.0", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c="], + + "obuf": ["obuf@1.1.2", "", {}, "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "on-headers": ["on-headers@1.0.2", "", {}, "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha1-WDsap3WWHUsROsF9nFC6753Xa9E="], + + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "open": ["open@8.4.0", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q=="], + + "os-browserify": ["os-browserify@0.3.0", "", {}, "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "p-map": ["p-map@3.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ=="], + + "p-retry": ["p-retry@4.6.2", "", { "dependencies": { "@types/retry": "0.12.0", "retry": "^0.13.1" } }, "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ=="], + + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + + "package-hash": ["package-hash@4.0.0", "", { "dependencies": { "graceful-fs": "^4.1.15", "hasha": "^5.0.0", "lodash.flattendeep": "^4.4.0", "release-zalgo": "^1.0.0" } }, "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ=="], + + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + + "parallel-transform": ["parallel-transform@1.2.0", "", { "dependencies": { "cyclist": "^1.0.1", "inherits": "^2.0.3", "readable-stream": "^2.1.5" } }, "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg=="], + + "parse-asn1": ["parse-asn1@5.1.6", "", { "dependencies": { "asn1.js": "^5.2.0", "browserify-aes": "^1.0.0", "evp_bytestokey": "^1.0.0", "pbkdf2": "^3.0.3", "safe-buffer": "^5.1.1" } }, "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw=="], + + "parse-passwd": ["parse-passwd@1.0.0", "", {}, "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "pascalcase": ["pascalcase@0.1.1", "", {}, "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="], + + "path-browserify": ["path-browserify@0.0.1", "", {}, "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ=="], + + "path-dirname": ["path-dirname@1.0.2", "", {}, "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-to-regexp": ["path-to-regexp@0.1.7", "", {}, "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="], + + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], + + "pathval": ["pathval@1.1.1", "", {}, "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ=="], + + "pbkdf2": ["pbkdf2@3.1.2", "", { "dependencies": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", "ripemd160": "^2.0.1", "safe-buffer": "^5.0.1", "sha.js": "^2.4.8" } }, "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA=="], + + "picocolors": ["picocolors@1.0.0", "", {}, "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="], + + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], + + "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], + + "posix-character-classes": ["posix-character-classes@0.1.1", "", {}, "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="], + + "process": ["process@0.11.10", "", {}, "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="], + + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "process-on-spawn": ["process-on-spawn@1.0.0", "", { "dependencies": { "fromentries": "^1.2.0" } }, "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg=="], + + "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="], + + "promise-inflight": ["promise-inflight@1.0.1", "", {}, "sha1-mEcocL8igTL8vdhoEputEsPAKeM="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "prr": ["prr@1.0.1", "", {}, "sha1-0/wRS6BplaRexok/SEzrHXj19HY="], + + "public-encrypt": ["public-encrypt@4.0.3", "", { "dependencies": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" } }, "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q=="], + + "pump": ["pump@3.0.0", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww=="], + + "pumpify": ["pumpify@1.5.1", "", { "dependencies": { "duplexify": "^3.6.0", "inherits": "^2.0.3", "pump": "^2.0.0" } }, "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ=="], + + "punycode": ["punycode@1.4.1", "", {}, "sha1-wNWmOycYgArY4esPpSachN1BhF4="], + + "qs": ["qs@6.10.3", "", { "dependencies": { "side-channel": "^1.0.4" } }, "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ=="], + + "querystring": ["querystring@0.2.0", "", {}, "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="], + + "querystring-es3": ["querystring-es3@0.2.1", "", {}, "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "railroad-diagrams": ["railroad-diagrams@1.0.0", "", {}, "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234="], + + "randexp": ["randexp@0.4.6", "", { "dependencies": { "discontinuous-range": "1.0.0", "ret": "~0.1.10" } }, "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ=="], + + "randombytes": ["randombytes@2.1.0", "", { "dependencies": { "safe-buffer": "^5.1.0" } }, "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="], + + "randomfill": ["randomfill@1.0.4", "", { "dependencies": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" } }, "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@2.5.1", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig=="], + + "readable-stream": ["readable-stream@2.3.7", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw=="], + + "readdirp": ["readdirp@3.5.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ=="], + + "regenerator-runtime": ["regenerator-runtime@0.13.9", "", {}, "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="], + + "regex-not": ["regex-not@1.0.2", "", { "dependencies": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" } }, "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A=="], + + "release-zalgo": ["release-zalgo@1.0.0", "", { "dependencies": { "es6-error": "^4.0.1" } }, "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA="], + + "remove-trailing-separator": ["remove-trailing-separator@1.1.0", "", {}, "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="], + + "repeat-element": ["repeat-element@1.1.4", "", {}, "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ=="], + + "repeat-string": ["repeat-string@1.6.1", "", {}, "sha1-jcrkcOHIirwtYA//Sndihtp15jc="], + + "repeating": ["repeating@2.0.1", "", { "dependencies": { "is-finite": "^1.0.0" } }, "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="], + + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + + "require-main-filename": ["require-main-filename@2.0.0", "", {}, "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="], + + "requires-port": ["requires-port@1.0.0", "", {}, "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="], + + "resolve-cwd": ["resolve-cwd@2.0.0", "", { "dependencies": { "resolve-from": "^3.0.0" } }, "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo="], + + "resolve-dir": ["resolve-dir@1.0.1", "", { "dependencies": { "expand-tilde": "^2.0.0", "global-modules": "^1.0.0" } }, "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M="], + + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "resolve-url": ["resolve-url@0.2.1", "", {}, "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="], + + "ret": ["ret@0.1.15", "", {}, "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="], + + "retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], + + "reusify": ["reusify@1.0.4", "", {}, "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="], + + "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": "bin.js" }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + + "ripemd160": ["ripemd160@2.0.2", "", { "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "run-queue": ["run-queue@1.0.3", "", { "dependencies": { "aproba": "^1.1.1" } }, "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec="], + + "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "safe-regex": ["safe-regex@1.1.0", "", { "dependencies": { "ret": "~0.1.10" } }, "sha1-QKNmnzsHfR6UPURinhV91IAjvy4="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "schema-utils": ["schema-utils@3.1.1", "", { "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } }, "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw=="], + + "select-hose": ["select-hose@2.0.0", "", {}, "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo="], + + "selfsigned": ["selfsigned@2.1.1", "", { "dependencies": { "node-forge": "^1" } }, "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ=="], + + "semver": ["semver@7.3.7", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": "bin/semver.js" }, "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g=="], + + "send": ["send@0.18.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg=="], + + "serialize-javascript": ["serialize-javascript@5.0.1", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA=="], + + "serve-index": ["serve-index@1.9.1", "", { "dependencies": { "accepts": "~1.3.4", "batch": "0.6.1", "debug": "2.6.9", "escape-html": "~1.0.3", "http-errors": "~1.6.2", "mime-types": "~2.1.17", "parseurl": "~1.3.2" } }, "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk="], + + "serve-static": ["serve-static@1.15.0", "", { "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.18.0" } }, "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g=="], + + "set-blocking": ["set-blocking@2.0.0", "", {}, "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="], + + "set-value": ["set-value@2.0.1", "", { "dependencies": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", "is-plain-object": "^2.0.3", "split-string": "^3.0.1" } }, "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw=="], + + "setimmediate": ["setimmediate@1.0.5", "", {}, "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "sha.js": ["sha.js@2.4.11", "", { "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" }, "bin": "bin.js" }, "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.0.4", "", { "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", "object-inspect": "^1.9.0" } }, "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw=="], + + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + + "snapdragon": ["snapdragon@0.8.2", "", { "dependencies": { "base": "^0.11.1", "debug": "^2.2.0", "define-property": "^0.2.5", "extend-shallow": "^2.0.1", "map-cache": "^0.2.2", "source-map": "^0.5.6", "source-map-resolve": "^0.5.0", "use": "^3.1.0" } }, "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg=="], + + "snapdragon-node": ["snapdragon-node@2.1.1", "", { "dependencies": { "define-property": "^1.0.0", "isobject": "^3.0.0", "snapdragon-util": "^3.0.1" } }, "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw=="], + + "snapdragon-util": ["snapdragon-util@3.0.1", "", { "dependencies": { "kind-of": "^3.2.0" } }, "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ=="], + + "sockjs": ["sockjs@0.3.24", "", { "dependencies": { "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" } }, "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ=="], + + "source-list-map": ["source-list-map@2.0.1", "", {}, "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="], + + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "source-map-resolve": ["source-map-resolve@0.5.3", "", { "dependencies": { "atob": "^2.1.2", "decode-uri-component": "^0.2.0", "resolve-url": "^0.2.1", "source-map-url": "^0.4.0", "urix": "^0.1.0" } }, "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw=="], + + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + + "source-map-url": ["source-map-url@0.4.1", "", {}, "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw=="], + + "spawn-wrap": ["spawn-wrap@2.0.0", "", { "dependencies": { "foreground-child": "^2.0.0", "is-windows": "^1.0.2", "make-dir": "^3.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "which": "^2.0.1" } }, "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg=="], + + "spdy": ["spdy@4.0.2", "", { "dependencies": { "debug": "^4.1.0", "handle-thing": "^2.0.0", "http-deceiver": "^1.2.7", "select-hose": "^2.0.0", "spdy-transport": "^3.0.0" } }, "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA=="], + + "spdy-transport": ["spdy-transport@3.0.0", "", { "dependencies": { "debug": "^4.1.0", "detect-node": "^2.0.4", "hpack.js": "^2.1.6", "obuf": "^1.1.2", "readable-stream": "^3.0.6", "wbuf": "^1.7.3" } }, "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw=="], + + "split-string": ["split-string@3.1.0", "", { "dependencies": { "extend-shallow": "^3.0.0" } }, "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw=="], + + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="], + + "ssri": ["ssri@8.0.1", "", { "dependencies": { "minipass": "^3.1.1" } }, "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ=="], + + "static-extend": ["static-extend@0.1.2", "", { "dependencies": { "define-property": "^0.2.5", "object-copy": "^0.1.0" } }, "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY="], + + "statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + + "stream-browserify": ["stream-browserify@2.0.2", "", { "dependencies": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" } }, "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg=="], + + "stream-each": ["stream-each@1.2.3", "", { "dependencies": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" } }, "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw=="], + + "stream-http": ["stream-http@2.8.3", "", { "dependencies": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", "readable-stream": "^2.3.6", "to-arraybuffer": "^1.0.0", "xtend": "^4.0.0" } }, "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw=="], + + "stream-shift": ["stream-shift@1.0.1", "", {}, "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="], + + "string-width": ["string-width@2.1.1", "", { "dependencies": { "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^4.0.0" } }, "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw=="], + + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "strip-ansi": ["strip-ansi@4.0.0", "", { "dependencies": { "ansi-regex": "^3.0.0" } }, "sha1-qEeQIusaw2iocTibY1JixQXuNo8="], + + "strip-bom": ["strip-bom@4.0.0", "", {}, "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="], + + "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "tapable": ["tapable@1.1.3", "", {}, "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="], + + "tar": ["tar@6.1.11", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^3.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA=="], + + "terser": ["terser@4.8.1", "", { "dependencies": { "commander": "^2.20.0", "source-map": "~0.6.1", "source-map-support": "~0.5.12" }, "bin": "bin/terser" }, "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw=="], + + "terser-webpack-plugin": ["terser-webpack-plugin@1.4.5", "", { "dependencies": { "cacache": "^12.0.2", "find-cache-dir": "^2.1.0", "is-wsl": "^1.1.0", "schema-utils": "^1.0.0", "serialize-javascript": "^4.0.0", "source-map": "^0.6.1", "terser": "^4.1.2", "webpack-sources": "^1.4.0", "worker-farm": "^1.7.0" }, "peerDependencies": { "webpack": "^4.0.0" } }, "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw=="], + + "test-exclude": ["test-exclude@6.0.0", "", { "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" } }, "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="], + + "through2": ["through2@2.0.5", "", { "dependencies": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" } }, "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ=="], + + "thunky": ["thunky@1.1.0", "", {}, "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="], + + "timers-browserify": ["timers-browserify@2.0.12", "", { "dependencies": { "setimmediate": "^1.0.4" } }, "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ=="], + + "to-arraybuffer": ["to-arraybuffer@1.0.1", "", {}, "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="], + + "to-fast-properties": ["to-fast-properties@1.0.3", "", {}, "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="], + + "to-object-path": ["to-object-path@0.3.0", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68="], + + "to-regex": ["to-regex@3.0.2", "", { "dependencies": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "regex-not": "^1.0.2", "safe-regex": "^1.1.0" } }, "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "toposort": ["toposort@2.0.2", "", {}, "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="], + + "trim-right": ["trim-right@1.0.1", "", {}, "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM="], + + "ts-loader": ["ts-loader@8.4.0", "", { "dependencies": { "chalk": "^4.1.0", "enhanced-resolve": "^4.0.0", "loader-utils": "^2.0.0", "micromatch": "^4.0.0", "semver": "^7.3.4" }, "peerDependencies": { "typescript": "*", "webpack": "*" } }, "sha512-6nFY3IZ2//mrPc+ImY3hNWx1vCHyEhl6V+wLmL4CZcm6g1CqX7UKrkc6y0i4FwcfOhxyMPCfaEvh20f4r9GNpw=="], + + "ts-node": ["ts-node@8.10.2", "", { "dependencies": { "arg": "^4.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", "source-map-support": "^0.5.17", "yn": "3.1.1" }, "peerDependencies": { "typescript": ">=2.7" }, "bin": { "ts-node": "dist/bin.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js", "ts-script": "dist/bin-script-deprecated.js" } }, "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA=="], + + "tty-browserify": ["tty-browserify@0.0.0", "", {}, "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="], + + "type-detect": ["type-detect@4.0.8", "", {}, "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="], + + "type-fest": ["type-fest@0.8.1", "", {}, "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="], + + "type-is": ["type-is@1.6.18", "", { "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" } }, "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="], + + "typedarray": ["typedarray@0.0.6", "", {}, "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="], + + "typedarray-to-buffer": ["typedarray-to-buffer@3.1.5", "", { "dependencies": { "is-typedarray": "^1.0.0" } }, "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="], + + "typescript": ["typescript@4.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA=="], + + "union-value": ["union-value@1.0.1", "", { "dependencies": { "arr-union": "^3.1.0", "get-value": "^2.0.6", "is-extendable": "^0.1.1", "set-value": "^2.0.1" } }, "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg=="], + + "unique-filename": ["unique-filename@1.1.1", "", { "dependencies": { "unique-slug": "^2.0.0" } }, "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ=="], + + "unique-slug": ["unique-slug@2.0.2", "", { "dependencies": { "imurmurhash": "^0.1.4" } }, "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="], + + "unset-value": ["unset-value@1.0.0", "", { "dependencies": { "has-value": "^0.3.1", "isobject": "^3.0.0" } }, "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk="], + + "upath": ["upath@1.2.0", "", {}, "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "urix": ["urix@0.1.0", "", {}, "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="], + + "url": ["url@0.11.0", "", { "dependencies": { "punycode": "1.3.2", "querystring": "0.2.0" } }, "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE="], + + "use": ["use@3.1.1", "", {}, "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="], + + "util": ["util@0.11.1", "", { "dependencies": { "inherits": "2.0.3" } }, "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="], + + "utils-merge": ["utils-merge@1.0.1", "", {}, "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="], + + "uuid": ["uuid@3.4.0", "", { "bin": "bin/uuid" }, "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="], + + "v8-compile-cache": ["v8-compile-cache@2.3.0", "", {}, "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA=="], + + "vary": ["vary@1.1.2", "", {}, "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="], + + "vm-browserify": ["vm-browserify@1.1.2", "", {}, "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="], + + "vscode-mocha-hmr": ["vscode-mocha-hmr@1.0.0", "", {}, "sha512-FQ98jxH1CS/WgMqcKQnYdmBWBY6XyAZYPy22+QEru6KYaiJw+zO9n7cK1ctvHUowky4v2tm1DpBSlNmnVyraJg=="], + + "watchpack": ["watchpack@1.7.5", "", { "dependencies": { "graceful-fs": "^4.1.2", "neo-async": "^2.5.0" }, "optionalDependencies": { "chokidar": "^3.4.1", "watchpack-chokidar2": "^2.0.1" } }, "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ=="], + + "watchpack-chokidar2": ["watchpack-chokidar2@2.0.1", "", { "dependencies": { "chokidar": "^2.1.8" } }, "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww=="], + + "wbuf": ["wbuf@1.7.3", "", { "dependencies": { "minimalistic-assert": "^1.0.0" } }, "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA=="], + + "webpack": ["webpack@4.46.0", "", { "dependencies": { "@webassemblyjs/ast": "1.9.0", "@webassemblyjs/helper-module-context": "1.9.0", "@webassemblyjs/wasm-edit": "1.9.0", "@webassemblyjs/wasm-parser": "1.9.0", "acorn": "^6.4.1", "ajv": "^6.10.2", "ajv-keywords": "^3.4.1", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^4.5.0", "eslint-scope": "^4.0.3", "json-parse-better-errors": "^1.0.2", "loader-runner": "^2.4.0", "loader-utils": "^1.2.3", "memory-fs": "^0.4.1", "micromatch": "^3.1.10", "mkdirp": "^0.5.3", "neo-async": "^2.6.1", "node-libs-browser": "^2.2.1", "schema-utils": "^1.0.0", "tapable": "^1.1.3", "terser-webpack-plugin": "^1.4.3", "watchpack": "^1.7.4", "webpack-sources": "^1.4.1" }, "bin": "bin/webpack.js" }, "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q=="], + + "webpack-cli": ["webpack-cli@3.3.12", "", { "dependencies": { "chalk": "^2.4.2", "cross-spawn": "^6.0.5", "enhanced-resolve": "^4.1.1", "findup-sync": "^3.0.0", "global-modules": "^2.0.0", "import-local": "^2.0.0", "interpret": "^1.4.0", "loader-utils": "^1.4.0", "supports-color": "^6.1.0", "v8-compile-cache": "^2.1.1", "yargs": "^13.3.2" }, "peerDependencies": { "webpack": "4.x.x" }, "bin": "bin/cli.js" }, "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag=="], + + "webpack-dev-middleware": ["webpack-dev-middleware@5.3.3", "", { "dependencies": { "colorette": "^2.0.10", "memfs": "^3.4.3", "mime-types": "^2.1.31", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "peerDependencies": { "webpack": "^4.0.0 || ^5.0.0" } }, "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA=="], + + "webpack-dev-server": ["webpack-dev-server@4.11.1", "", { "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", "@types/express": "^4.17.13", "@types/serve-index": "^1.9.1", "@types/serve-static": "^1.13.10", "@types/sockjs": "^0.3.33", "@types/ws": "^8.5.1", "ansi-html-community": "^0.0.8", "bonjour-service": "^1.0.11", "chokidar": "^3.5.3", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", "default-gateway": "^6.0.3", "express": "^4.17.3", "graceful-fs": "^4.2.6", "html-entities": "^2.3.2", "http-proxy-middleware": "^2.0.3", "ipaddr.js": "^2.0.1", "open": "^8.0.9", "p-retry": "^4.5.0", "rimraf": "^3.0.2", "schema-utils": "^4.0.0", "selfsigned": "^2.1.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", "webpack-dev-middleware": "^5.3.1", "ws": "^8.4.2" }, "peerDependencies": { "webpack": "^4.37.0 || ^5.0.0" }, "bin": "bin/webpack-dev-server.js" }, "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw=="], + + "webpack-node-externals": ["webpack-node-externals@1.7.2", "", {}, "sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg=="], + + "webpack-sources": ["webpack-sources@1.4.3", "", { "dependencies": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" } }, "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ=="], + + "websocket-driver": ["websocket-driver@0.7.4", "", { "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="], + + "websocket-extensions": ["websocket-extensions@0.1.4", "", {}, "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "which-module": ["which-module@2.0.0", "", {}, "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="], + + "wide-align": ["wide-align@1.1.3", "", { "dependencies": { "string-width": "^1.0.2 || 2" } }, "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA=="], + + "worker-farm": ["worker-farm@1.7.0", "", { "dependencies": { "errno": "~0.1.7" } }, "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw=="], + + "workerpool": ["workerpool@6.1.0", "", {}, "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg=="], + + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="], + + "write-file-atomic": ["write-file-atomic@3.0.3", "", { "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="], + + "ws": ["ws@8.11.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg=="], + + "xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="], + + "yargs-parser": ["yargs-parser@20.2.4", "", {}, "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA=="], + + "yargs-unparser": ["yargs-unparser@2.0.0", "", { "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", "flat": "^5.0.2", "is-plain-obj": "^2.1.0" } }, "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA=="], + + "yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "@babel/core/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], + + "@babel/core/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "@babel/generator/@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.1", "", { "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.9" } }, "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg=="], + + "@babel/generator/jsesc": ["jsesc@2.5.2", "", { "bin": "bin/jsesc" }, "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="], + + "@babel/helper-compilation-targets/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "@babel/highlight/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "@babel/traverse/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], + + "@babel/traverse/globals": ["globals@11.12.0", "", {}, "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="], + + "@babel/types/to-fast-properties": ["to-fast-properties@2.0.0", "", {}, "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="], + + "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "@istanbuljs/load-nyc-config/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "@istanbuljs/load-nyc-config/js-yaml": ["js-yaml@3.14.1", "", { "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": "bin/js-yaml.js" }, "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="], + + "@istanbuljs/load-nyc-config/resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + + "@npmcli/fs/semver": ["semver@7.3.7", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": "bin/semver.js" }, "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g=="], + + "@npmcli/move-file/mkdirp": ["mkdirp@1.0.4", "", { "bin": "bin/cmd.js" }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "ajv-formats/ajv": ["ajv@8.11.2", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg=="], + + "asn1.js/bn.js": ["bn.js@4.12.0", "", {}, "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="], + + "assert/util": ["util@0.10.3", "", { "dependencies": { "inherits": "2.0.1" } }, "sha1-evsa/lCAUkZInj23/g7TeTNqwPk="], + + "babel-code-frame/chalk": ["chalk@1.1.3", "", { "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A=="], + + "babel-generator/source-map": ["source-map@0.5.7", "", {}, "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="], + + "babel-runtime/regenerator-runtime": ["regenerator-runtime@0.11.1", "", {}, "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="], + + "babel-traverse/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "base/define-property": ["define-property@1.0.0", "", { "dependencies": { "is-descriptor": "^1.0.0" } }, "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA=="], + + "body-parser/bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "browserify-sign/readable-stream": ["readable-stream@3.6.0", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA=="], + + "browserify-sign/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "cacache/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "cacache/mkdirp": ["mkdirp@1.0.4", "", { "bin": "bin/cmd.js" }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "cacache/p-map": ["p-map@4.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="], + + "caching-transform/make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "chalk/supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="], + + "class-utils/define-property": ["define-property@0.2.5", "", { "dependencies": { "is-descriptor": "^0.1.0" } }, "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA=="], + + "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "content-disposition/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "copy-concurrently/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": "bin/cmd.js" }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + + "copy-concurrently/rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": "bin.js" }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="], + + "create-ecdh/bn.js": ["bn.js@4.12.0", "", {}, "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="], + + "debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + + "diffie-hellman/bn.js": ["bn.js@4.12.0", "", {}, "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="], + + "elliptic/bn.js": ["bn.js@4.12.0", "", {}, "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="], + + "enhanced-resolve/memory-fs": ["memory-fs@0.5.0", "", { "dependencies": { "errno": "^0.1.3", "readable-stream": "^2.0.1" } }, "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA=="], + + "esrecurse/estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "expand-brackets/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "expand-brackets/define-property": ["define-property@0.2.5", "", { "dependencies": { "is-descriptor": "^0.1.0" } }, "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA=="], + + "expand-brackets/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "express/array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], + + "express/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "express/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "extglob/define-property": ["define-property@1.0.0", "", { "dependencies": { "is-descriptor": "^1.0.0" } }, "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA=="], + + "extglob/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "find-cache-dir/make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "findup-sync/micromatch": ["micromatch@3.1.10", "", { "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "braces": "^2.3.1", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "extglob": "^2.0.4", "fragment-cache": "^0.2.1", "kind-of": "^6.0.2", "nanomatch": "^1.2.9", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" } }, "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg=="], + + "global-prefix/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": "bin/which" }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], + + "has-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], + + "has-values/is-number": ["is-number@3.0.0", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg=="], + + "has-values/kind-of": ["kind-of@4.0.0", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw=="], + + "hash-base/readable-stream": ["readable-stream@3.6.0", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA=="], + + "hash-base/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "http-proxy-middleware/is-plain-obj": ["is-plain-obj@3.0.0", "", {}, "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA=="], + + "import-local/pkg-dir": ["pkg-dir@3.0.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw=="], + + "is-number/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "istanbul-instrumenter-loader/loader-utils": ["loader-utils@1.4.2", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^1.0.1" } }, "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg=="], + + "istanbul-instrumenter-loader/schema-utils": ["schema-utils@0.3.0", "", { "dependencies": { "ajv": "^5.0.0" } }, "sha512-QaVYBaD9U8scJw2EBWnCBY+LJ0AD+/2edTaigDs0XLDLBfJmSUK9KGqktg1rb32U3z4j/XwvFwHHH1YfbYFd7Q=="], + + "istanbul-lib-instrument/istanbul-lib-coverage": ["istanbul-lib-coverage@1.2.1", "", {}, "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ=="], + + "istanbul-lib-instrument/semver": ["semver@5.7.1", "", { "bin": "bin/semver" }, "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="], + + "istanbul-lib-processinfo/istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.0", "", {}, "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw=="], + + "istanbul-lib-processinfo/make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "istanbul-lib-processinfo/p-map": ["p-map@3.0.0", "", { "dependencies": { "aggregate-error": "^3.0.0" } }, "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ=="], + + "istanbul-lib-report/istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.0", "", {}, "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw=="], + + "istanbul-lib-report/make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "istanbul-lib-report/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "istanbul-lib-source-maps/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], + + "istanbul-lib-source-maps/istanbul-lib-coverage": ["istanbul-lib-coverage@3.2.0", "", {}, "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw=="], + + "log-symbols/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "loose-envify/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "make-dir/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "miller-rabin/bn.js": ["bn.js@4.12.0", "", {}, "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="], + + "mochapack/chokidar": ["chokidar@3.5.3", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw=="], + + "mochapack/globby": ["globby@10.0.2", "", { "dependencies": { "@types/glob": "^7.1.1", "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.0.3", "glob": "^7.1.3", "ignore": "^5.1.1", "merge2": "^1.2.3", "slash": "^3.0.0" } }, "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg=="], + + "mochapack/loader-utils": ["loader-utils@1.4.2", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^1.0.1" } }, "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg=="], + + "mochapack/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "mochapack/yargs": ["yargs@14.0.0", "", { "dependencies": { "cliui": "^5.0.0", "decamelize": "^1.2.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^13.1.1" } }, "sha512-ssa5JuRjMeZEUjg7bEL99AwpitxU/zWGAGpdj0di41pOEmJti8NR6kyUIJBkR78DTYNPZOU08luUo0GTHuB+ow=="], + + "move-concurrently/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": "bin/cmd.js" }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + + "move-concurrently/rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": "bin.js" }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="], + + "nyc/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "nyc/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "nyc/istanbul-lib-instrument": ["istanbul-lib-instrument@4.0.3", "", { "dependencies": { "@babel/core": "^7.7.5", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.0.0", "semver": "^6.3.0" } }, "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ=="], + + "nyc/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="], + + "object-copy/define-property": ["define-property@0.2.5", "", { "dependencies": { "is-descriptor": "^0.1.0" } }, "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA=="], + + "object-copy/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], + + "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "public-encrypt/bn.js": ["bn.js@4.12.0", "", {}, "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="], + + "pumpify/pump": ["pump@2.0.1", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA=="], + + "raw-body/bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "resolve-cwd/resolve-from": ["resolve-from@3.0.0", "", {}, "sha1-six699nWiBvItuZTM17rywoYh0g="], + + "resolve-dir/global-modules": ["global-modules@1.0.0", "", { "dependencies": { "global-prefix": "^1.0.1", "is-windows": "^1.0.1", "resolve-dir": "^1.0.0" } }, "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg=="], + + "rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "serve-index/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "serve-index/http-errors": ["http-errors@1.6.3", "", { "dependencies": { "depd": "~1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", "statuses": ">= 1.4.0 < 2" } }, "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A=="], + + "set-value/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "set-value/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "snapdragon/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "snapdragon/define-property": ["define-property@0.2.5", "", { "dependencies": { "is-descriptor": "^0.1.0" } }, "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA=="], + + "snapdragon/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "snapdragon/source-map": ["source-map@0.5.7", "", {}, "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="], + + "snapdragon-node/define-property": ["define-property@1.0.0", "", { "dependencies": { "is-descriptor": "^1.0.0" } }, "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA=="], + + "snapdragon-util/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "sockjs/uuid": ["uuid@8.3.2", "", { "bin": "dist/bin/uuid" }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "spawn-wrap/make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + + "spdy/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], + + "spdy-transport/debug": ["debug@4.3.4", "", { "dependencies": { "ms": "2.1.2" } }, "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ=="], + + "spdy-transport/readable-stream": ["readable-stream@3.6.0", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA=="], + + "static-extend/define-property": ["define-property@0.2.5", "", { "dependencies": { "is-descriptor": "^0.1.0" } }, "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA=="], + + "tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": "bin/cmd.js" }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "terser-webpack-plugin/cacache": ["cacache@12.0.4", "", { "dependencies": { "bluebird": "^3.5.5", "chownr": "^1.1.1", "figgy-pudding": "^3.5.1", "glob": "^7.1.4", "graceful-fs": "^4.1.15", "infer-owner": "^1.0.3", "lru-cache": "^5.1.1", "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.3", "ssri": "^6.0.1", "unique-filename": "^1.1.1", "y18n": "^4.0.0" } }, "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ=="], + + "terser-webpack-plugin/find-cache-dir": ["find-cache-dir@2.1.0", "", { "dependencies": { "commondir": "^1.0.1", "make-dir": "^2.0.0", "pkg-dir": "^3.0.0" } }, "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ=="], + + "terser-webpack-plugin/schema-utils": ["schema-utils@1.0.0", "", { "dependencies": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", "ajv-keywords": "^3.1.0" } }, "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g=="], + + "terser-webpack-plugin/serialize-javascript": ["serialize-javascript@4.0.0", "", { "dependencies": { "randombytes": "^2.1.0" } }, "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw=="], + + "test-exclude/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "test-exclude/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "to-object-path/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "to-regex-range/is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "ts-loader/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "ts-node/diff": ["diff@4.0.2", "", {}, "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="], + + "union-value/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "unset-value/has-value": ["has-value@0.3.1", "", { "dependencies": { "get-value": "^2.0.3", "has-values": "^0.1.4", "isobject": "^2.0.0" } }, "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q=="], + + "uri-js/punycode": ["punycode@2.1.1", "", {}, "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="], + + "url/punycode": ["punycode@1.3.2", "", {}, "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="], + + "util/inherits": ["inherits@2.0.3", "", {}, "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="], + + "watchpack/chokidar": ["chokidar@3.5.3", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw=="], + + "watchpack-chokidar2/chokidar": ["chokidar@2.1.8", "", { "dependencies": { "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", "is-glob": "^4.0.0", "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", "readdirp": "^2.2.1", "upath": "^1.1.1" }, "optionalDependencies": { "fsevents": "^1.2.7" } }, "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg=="], + + "webpack/loader-utils": ["loader-utils@1.4.2", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^1.0.1" } }, "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg=="], + + "webpack/micromatch": ["micromatch@3.1.10", "", { "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "braces": "^2.3.1", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "extglob": "^2.0.4", "fragment-cache": "^0.2.1", "kind-of": "^6.0.2", "nanomatch": "^1.2.9", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" } }, "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg=="], + + "webpack/schema-utils": ["schema-utils@1.0.0", "", { "dependencies": { "ajv": "^6.1.0", "ajv-errors": "^1.0.0", "ajv-keywords": "^3.1.0" } }, "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g=="], + + "webpack-cli/cross-spawn": ["cross-spawn@6.0.5", "", { "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", "semver": "^5.5.0", "shebang-command": "^1.2.0", "which": "^1.2.9" } }, "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ=="], + + "webpack-cli/loader-utils": ["loader-utils@1.4.2", "", { "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", "json5": "^1.0.1" } }, "sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg=="], + + "webpack-cli/supports-color": ["supports-color@6.1.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ=="], + + "webpack-cli/yargs": ["yargs@13.3.2", "", { "dependencies": { "cliui": "^5.0.0", "find-up": "^3.0.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^3.0.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^13.1.2" } }, "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw=="], + + "webpack-dev-middleware/colorette": ["colorette@2.0.19", "", {}, "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ=="], + + "webpack-dev-middleware/schema-utils": ["schema-utils@4.0.0", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.8.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.0.0" } }, "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg=="], + + "webpack-dev-server/chokidar": ["chokidar@3.5.3", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw=="], + + "webpack-dev-server/schema-utils": ["schema-utils@4.0.0", "", { "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.8.0", "ajv-formats": "^2.1.1", "ajv-keywords": "^5.0.0" } }, "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "wrap-ansi/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "yargs-unparser/decamelize": ["decamelize@4.0.0", "", {}, "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ=="], + + "@babel/core/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + + "@babel/traverse/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "@istanbuljs/load-nyc-config/js-yaml/argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], + + "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "assert/util/inherits": ["inherits@2.0.1", "", {}, "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA=="], + + "babel-code-frame/chalk/ansi-styles": ["ansi-styles@2.2.1", "", {}, "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="], + + "babel-code-frame/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "babel-code-frame/chalk/strip-ansi": ["strip-ansi@3.0.1", "", { "dependencies": { "ansi-regex": "^2.0.0" } }, "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8="], + + "babel-code-frame/chalk/supports-color": ["supports-color@2.0.0", "", {}, "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="], + + "babel-traverse/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "body-parser/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "cacache/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "caching-transform/make-dir/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "chalk/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "class-utils/define-property/is-descriptor": ["is-descriptor@0.1.6", "", { "dependencies": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" } }, "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg=="], + + "cliui/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "compression/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "copy-concurrently/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "expand-brackets/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "expand-brackets/define-property/is-descriptor": ["is-descriptor@0.1.6", "", { "dependencies": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" } }, "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg=="], + + "expand-brackets/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "express/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "extglob/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "find-cache-dir/make-dir/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "findup-sync/micromatch/braces": ["braces@2.3.2", "", { "dependencies": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", "extend-shallow": "^2.0.1", "fill-range": "^4.0.0", "isobject": "^3.0.1", "repeat-element": "^1.1.2", "snapdragon": "^0.8.1", "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" } }, "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w=="], + + "has-values/is-number/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "import-local/pkg-dir/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], + + "istanbul-instrumenter-loader/loader-utils/json5": ["json5@1.0.1", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow=="], + + "istanbul-instrumenter-loader/schema-utils/ajv": ["ajv@5.5.2", "", { "dependencies": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.3.0" } }, "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw=="], + + "istanbul-lib-processinfo/make-dir/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "istanbul-lib-report/make-dir/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "istanbul-lib-report/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "istanbul-lib-source-maps/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + + "log-symbols/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "log-symbols/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "mochapack/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "mochapack/globby/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "mochapack/globby/slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + + "mochapack/loader-utils/json5": ["json5@1.0.1", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow=="], + + "mochapack/yargs/cliui": ["cliui@5.0.0", "", { "dependencies": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", "wrap-ansi": "^5.1.0" } }, "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA=="], + + "mochapack/yargs/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], + + "mochapack/yargs/string-width": ["string-width@3.1.0", "", { "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } }, "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w=="], + + "mochapack/yargs/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], + + "mochapack/yargs/yargs-parser": ["yargs-parser@13.1.2", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg=="], + + "move-concurrently/rimraf/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "nyc/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "nyc/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "nyc/istanbul-lib-instrument/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "nyc/yargs/cliui": ["cliui@6.0.0", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="], + + "nyc/yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "nyc/yargs/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], + + "nyc/yargs/yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="], + + "object-copy/define-property/is-descriptor": ["is-descriptor@0.1.6", "", { "dependencies": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" } }, "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg=="], + + "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], + + "resolve-dir/global-modules/global-prefix": ["global-prefix@1.0.2", "", { "dependencies": { "expand-tilde": "^2.0.2", "homedir-polyfill": "^1.0.1", "ini": "^1.3.4", "is-windows": "^1.0.1", "which": "^1.2.14" } }, "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg=="], + + "rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "send/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "serve-index/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "serve-index/http-errors/depd": ["depd@1.1.2", "", {}, "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="], + + "serve-index/http-errors/inherits": ["inherits@2.0.3", "", {}, "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="], + + "serve-index/http-errors/setprototypeof": ["setprototypeof@1.1.0", "", {}, "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="], + + "serve-index/http-errors/statuses": ["statuses@1.5.0", "", {}, "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="], + + "snapdragon/debug/ms": ["ms@2.0.0", "", {}, "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="], + + "snapdragon/define-property/is-descriptor": ["is-descriptor@0.1.6", "", { "dependencies": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" } }, "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg=="], + + "snapdragon/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "spawn-wrap/make-dir/semver": ["semver@6.3.0", "", { "bin": "bin/semver.js" }, "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="], + + "spdy-transport/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + + "spdy/debug/ms": ["ms@2.1.2", "", {}, "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="], + + "static-extend/define-property/is-descriptor": ["is-descriptor@0.1.6", "", { "dependencies": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", "kind-of": "^5.0.0" } }, "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg=="], + + "terser-webpack-plugin/cacache/chownr": ["chownr@1.1.4", "", {}, "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="], + + "terser-webpack-plugin/cacache/glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "terser-webpack-plugin/cacache/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "terser-webpack-plugin/cacache/mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": "bin/cmd.js" }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + + "terser-webpack-plugin/cacache/rimraf": ["rimraf@2.7.1", "", { "dependencies": { "glob": "^7.1.3" }, "bin": "bin.js" }, "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="], + + "terser-webpack-plugin/cacache/ssri": ["ssri@6.0.2", "", { "dependencies": { "figgy-pudding": "^3.5.1" } }, "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q=="], + + "terser-webpack-plugin/cacache/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], + + "terser-webpack-plugin/find-cache-dir/make-dir": ["make-dir@2.1.0", "", { "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" } }, "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA=="], + + "terser-webpack-plugin/find-cache-dir/pkg-dir": ["pkg-dir@3.0.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw=="], + + "ts-loader/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "ts-loader/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "unset-value/has-value/has-values": ["has-values@0.1.4", "", {}, "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ=="], + + "unset-value/has-value/isobject": ["isobject@2.1.0", "", { "dependencies": { "isarray": "1.0.0" } }, "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA=="], + + "watchpack-chokidar2/chokidar/anymatch": ["anymatch@2.0.0", "", { "dependencies": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" } }, "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw=="], + + "watchpack-chokidar2/chokidar/braces": ["braces@2.3.2", "", { "dependencies": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", "extend-shallow": "^2.0.1", "fill-range": "^4.0.0", "isobject": "^3.0.1", "repeat-element": "^1.1.2", "snapdragon": "^0.8.1", "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" } }, "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w=="], + + "watchpack-chokidar2/chokidar/fsevents": ["fsevents@1.2.13", "", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.12.1" }, "os": "darwin" }, "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw=="], + + "watchpack-chokidar2/chokidar/glob-parent": ["glob-parent@3.1.0", "", { "dependencies": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" } }, "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA=="], + + "watchpack-chokidar2/chokidar/is-binary-path": ["is-binary-path@1.0.1", "", { "dependencies": { "binary-extensions": "^1.0.0" } }, "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q=="], + + "watchpack-chokidar2/chokidar/readdirp": ["readdirp@2.2.1", "", { "dependencies": { "graceful-fs": "^4.1.11", "micromatch": "^3.1.10", "readable-stream": "^2.0.2" } }, "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ=="], + + "watchpack/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "webpack-cli/cross-spawn/path-key": ["path-key@2.0.1", "", {}, "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="], + + "webpack-cli/cross-spawn/semver": ["semver@5.7.1", "", { "bin": "bin/semver" }, "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="], + + "webpack-cli/cross-spawn/shebang-command": ["shebang-command@1.2.0", "", { "dependencies": { "shebang-regex": "^1.0.0" } }, "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo="], + + "webpack-cli/cross-spawn/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": "bin/which" }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], + + "webpack-cli/loader-utils/json5": ["json5@1.0.1", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow=="], + + "webpack-cli/supports-color/has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="], + + "webpack-cli/yargs/cliui": ["cliui@5.0.0", "", { "dependencies": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", "wrap-ansi": "^5.1.0" } }, "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA=="], + + "webpack-cli/yargs/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], + + "webpack-cli/yargs/string-width": ["string-width@3.1.0", "", { "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", "strip-ansi": "^5.1.0" } }, "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w=="], + + "webpack-cli/yargs/y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="], + + "webpack-cli/yargs/yargs-parser": ["yargs-parser@13.1.2", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg=="], + + "webpack-dev-middleware/schema-utils/ajv": ["ajv@8.11.2", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg=="], + + "webpack-dev-middleware/schema-utils/ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], + + "webpack-dev-server/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "webpack-dev-server/schema-utils/ajv": ["ajv@8.11.2", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg=="], + + "webpack-dev-server/schema-utils/ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="], + + "webpack/loader-utils/json5": ["json5@1.0.1", "", { "dependencies": { "minimist": "^1.2.0" }, "bin": "lib/cli.js" }, "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow=="], + + "webpack/micromatch/braces": ["braces@2.3.2", "", { "dependencies": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", "extend-shallow": "^2.0.1", "fill-range": "^4.0.0", "isobject": "^3.0.1", "repeat-element": "^1.1.2", "snapdragon": "^0.8.1", "snapdragon-node": "^2.0.1", "split-string": "^3.0.2", "to-regex": "^3.0.1" } }, "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w=="], + + "wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "wrap-ansi/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "babel-code-frame/chalk/strip-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], + + "class-utils/define-property/is-descriptor/is-accessor-descriptor": ["is-accessor-descriptor@0.1.6", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A=="], + + "class-utils/define-property/is-descriptor/is-data-descriptor": ["is-data-descriptor@0.1.4", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg=="], + + "class-utils/define-property/is-descriptor/kind-of": ["kind-of@5.1.0", "", {}, "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="], + + "copy-concurrently/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "expand-brackets/define-property/is-descriptor/is-accessor-descriptor": ["is-accessor-descriptor@0.1.6", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A=="], + + "expand-brackets/define-property/is-descriptor/is-data-descriptor": ["is-data-descriptor@0.1.4", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg=="], + + "expand-brackets/define-property/is-descriptor/kind-of": ["kind-of@5.1.0", "", {}, "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="], + + "findup-sync/micromatch/braces/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "findup-sync/micromatch/braces/fill-range": ["fill-range@4.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" } }, "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ=="], + + "import-local/pkg-dir/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], + + "istanbul-instrumenter-loader/schema-utils/ajv/fast-deep-equal": ["fast-deep-equal@1.1.0", "", {}, "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw=="], + + "istanbul-instrumenter-loader/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@0.3.1", "", {}, "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA=="], + + "log-symbols/chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "log-symbols/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "mochapack/yargs/cliui/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + + "mochapack/yargs/cliui/wrap-ansi": ["wrap-ansi@5.1.0", "", { "dependencies": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", "strip-ansi": "^5.0.0" } }, "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q=="], + + "mochapack/yargs/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], + + "mochapack/yargs/string-width/emoji-regex": ["emoji-regex@7.0.3", "", {}, "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="], + + "mochapack/yargs/string-width/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + + "mochapack/yargs/yargs-parser/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "move-concurrently/rimraf/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "nyc/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "nyc/yargs/cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "nyc/yargs/cliui/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], + + "nyc/yargs/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "nyc/yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "nyc/yargs/yargs-parser/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "object-copy/define-property/is-descriptor/is-accessor-descriptor": ["is-accessor-descriptor@0.1.6", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A=="], + + "object-copy/define-property/is-descriptor/is-data-descriptor": ["is-data-descriptor@0.1.4", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg=="], + + "object-copy/define-property/is-descriptor/kind-of": ["kind-of@5.1.0", "", {}, "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="], + + "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], + + "resolve-dir/global-modules/global-prefix/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": "bin/which" }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], + + "snapdragon/define-property/is-descriptor/is-accessor-descriptor": ["is-accessor-descriptor@0.1.6", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A=="], + + "snapdragon/define-property/is-descriptor/is-data-descriptor": ["is-data-descriptor@0.1.4", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg=="], + + "snapdragon/define-property/is-descriptor/kind-of": ["kind-of@5.1.0", "", {}, "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="], + + "static-extend/define-property/is-descriptor/is-accessor-descriptor": ["is-accessor-descriptor@0.1.6", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A=="], + + "static-extend/define-property/is-descriptor/is-data-descriptor": ["is-data-descriptor@0.1.4", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg=="], + + "static-extend/define-property/is-descriptor/kind-of": ["kind-of@5.1.0", "", {}, "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="], + + "terser-webpack-plugin/cacache/glob/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "terser-webpack-plugin/cacache/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "terser-webpack-plugin/find-cache-dir/make-dir/semver": ["semver@5.7.1", "", { "bin": "bin/semver" }, "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="], + + "terser-webpack-plugin/find-cache-dir/pkg-dir/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], + + "ts-loader/chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "ts-loader/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "watchpack-chokidar2/chokidar/anymatch/micromatch": ["micromatch@3.1.10", "", { "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "braces": "^2.3.1", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "extglob": "^2.0.4", "fragment-cache": "^0.2.1", "kind-of": "^6.0.2", "nanomatch": "^1.2.9", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" } }, "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg=="], + + "watchpack-chokidar2/chokidar/anymatch/normalize-path": ["normalize-path@2.1.1", "", { "dependencies": { "remove-trailing-separator": "^1.0.1" } }, "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk="], + + "watchpack-chokidar2/chokidar/braces/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "watchpack-chokidar2/chokidar/braces/fill-range": ["fill-range@4.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" } }, "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ=="], + + "watchpack-chokidar2/chokidar/glob-parent/is-glob": ["is-glob@3.1.0", "", { "dependencies": { "is-extglob": "^2.1.0" } }, "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw=="], + + "watchpack-chokidar2/chokidar/is-binary-path/binary-extensions": ["binary-extensions@1.13.1", "", {}, "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="], + + "watchpack-chokidar2/chokidar/readdirp/micromatch": ["micromatch@3.1.10", "", { "dependencies": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", "braces": "^2.3.1", "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "extglob": "^2.0.4", "fragment-cache": "^0.2.1", "kind-of": "^6.0.2", "nanomatch": "^1.2.9", "object.pick": "^1.3.0", "regex-not": "^1.0.0", "snapdragon": "^0.8.1", "to-regex": "^3.0.2" } }, "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg=="], + + "webpack-cli/cross-spawn/shebang-command/shebang-regex": ["shebang-regex@1.0.0", "", {}, "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="], + + "webpack-cli/yargs/cliui/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + + "webpack-cli/yargs/cliui/wrap-ansi": ["wrap-ansi@5.1.0", "", { "dependencies": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", "strip-ansi": "^5.0.0" } }, "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q=="], + + "webpack-cli/yargs/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], + + "webpack-cli/yargs/string-width/emoji-regex": ["emoji-regex@7.0.3", "", {}, "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="], + + "webpack-cli/yargs/string-width/strip-ansi": ["strip-ansi@5.2.0", "", { "dependencies": { "ansi-regex": "^4.1.0" } }, "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA=="], + + "webpack-cli/yargs/yargs-parser/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], + + "webpack-dev-middleware/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "webpack-dev-server/schema-utils/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "webpack/micromatch/braces/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "webpack/micromatch/braces/fill-range": ["fill-range@4.0.0", "", { "dependencies": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", "repeat-string": "^1.6.1", "to-regex-range": "^2.1.0" } }, "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ=="], + + "wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "@istanbuljs/load-nyc-config/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "class-utils/define-property/is-descriptor/is-accessor-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "class-utils/define-property/is-descriptor/is-data-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "expand-brackets/define-property/is-descriptor/is-accessor-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "expand-brackets/define-property/is-descriptor/is-data-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "findup-sync/micromatch/braces/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "findup-sync/micromatch/braces/fill-range/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "findup-sync/micromatch/braces/fill-range/is-number": ["is-number@3.0.0", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg=="], + + "findup-sync/micromatch/braces/fill-range/to-regex-range": ["to-regex-range@2.1.1", "", { "dependencies": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" } }, "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg="], + + "import-local/pkg-dir/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], + + "import-local/pkg-dir/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="], + + "log-symbols/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "mochapack/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], + + "mochapack/yargs/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], + + "mochapack/yargs/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="], + + "mochapack/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], + + "nyc/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "nyc/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "nyc/yargs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "nyc/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "object-copy/define-property/is-descriptor/is-accessor-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "object-copy/define-property/is-descriptor/is-data-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "snapdragon/define-property/is-descriptor/is-accessor-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "snapdragon/define-property/is-descriptor/is-data-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "static-extend/define-property/is-descriptor/is-accessor-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "static-extend/define-property/is-descriptor/is-data-descriptor/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "terser-webpack-plugin/find-cache-dir/pkg-dir/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], + + "ts-loader/chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "watchpack-chokidar2/chokidar/braces/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "watchpack-chokidar2/chokidar/braces/fill-range/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "watchpack-chokidar2/chokidar/braces/fill-range/is-number": ["is-number@3.0.0", "", { "dependencies": { "kind-of": "^3.0.2" } }, "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg=="], + + "watchpack-chokidar2/chokidar/braces/fill-range/to-regex-range": ["to-regex-range@2.1.1", "", { "dependencies": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" } }, "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg="], + + "webpack-cli/yargs/cliui/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], + + "webpack-cli/yargs/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], + + "webpack-cli/yargs/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="], + + "webpack-cli/yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@4.1.1", "", {}, "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="], + + "webpack/micromatch/braces/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "webpack/micromatch/braces/fill-range/extend-shallow": ["extend-shallow@2.0.1", "", { "dependencies": { "is-extendable": "^0.1.0" } }, "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug=="], + + "webpack/micromatch/braces/fill-range/to-regex-range": ["to-regex-range@2.1.1", "", { "dependencies": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" } }, "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg="], + + "findup-sync/micromatch/braces/fill-range/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "findup-sync/micromatch/braces/fill-range/is-number/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "import-local/pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "mochapack/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "nyc/yargs/cliui/wrap-ansi/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "terser-webpack-plugin/find-cache-dir/pkg-dir/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], + + "terser-webpack-plugin/find-cache-dir/pkg-dir/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="], + + "watchpack-chokidar2/chokidar/braces/fill-range/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "watchpack-chokidar2/chokidar/braces/fill-range/is-number/kind-of": ["kind-of@3.2.2", "", { "dependencies": { "is-buffer": "^1.1.5" } }, "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ=="], + + "webpack-cli/yargs/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "webpack/micromatch/braces/fill-range/extend-shallow/is-extendable": ["is-extendable@0.1.1", "", {}, "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="], + + "nyc/yargs/cliui/wrap-ansi/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "terser-webpack-plugin/find-cache-dir/pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + } +} diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 96ffbe1..674ecd5 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -936,6 +936,19 @@ export interface ExprCall extends PGNode { export interface CallOver extends PGNode { orderBy?: OrderByStatement[] | nil; partitionBy?: Expr[] | nil; + frame?: CallOverFrame | nil; +} + +export interface CallOverFrame extends PGNode { + unit: 'rows' | 'range' | 'groups'; + start: FrameBound; + end?: FrameBound | nil; +} + +export interface FrameBound extends PGNode { + type: 'unbounded preceding' | 'unbounded following' | 'current row' | 'preceding' | 'following'; + /** only set for 'preceding' & 'following' bound types */ + value?: Expr | nil; } diff --git a/src/syntax/base.ne b/src/syntax/base.ne index 2311103..d60a62b 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -203,6 +203,12 @@ kw_increment -> %word {% notReservedKw('increment') %} kw_by -> %word {% notReservedKw('by') %} kw_row -> %word {% notReservedKw('row') %} kw_rows -> %word {% notReservedKw('rows') %} +kw_range -> %word {% notReservedKw('range') %} +kw_groups -> %word {% notReservedKw('groups') %} +kw_unbounded -> %word {% notReservedKw('unbounded') %} +kw_preceding -> %word {% notReservedKw('preceding') %} +kw_following -> %word {% notReservedKw('following') %} +kw_current -> %word {% notReservedKw('current') %} kw_next -> %word {% notReservedKw('next') %} kw_match -> %word {% notReservedKw('match') %} kw_replace -> %word {% notReservedKw('replace') %} diff --git a/src/syntax/expr.ne b/src/syntax/expr.ne index aff8c67..804c204 100644 --- a/src/syntax/expr.ne +++ b/src/syntax/expr.ne @@ -220,11 +220,38 @@ expr_call_over -> kw_over lparen (kw_partition kw_by expr_list_raw {% last %}):? select_order_by:? + expr_call_over_frame:? rparen {% x => track(x, { ...x[2] && { partitionBy: x[2] }, ...x[3] && { orderBy: x[3] }, + ...x[4] && { frame: unwrap(x[4]) }, }) %} +# frame clause: https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-WINDOW-FUNCTIONS +expr_call_over_frame -> (kw_rows | kw_range | kw_groups) + expr_call_over_frame_bounds + {% x => track(x, { + unit: toStr(x[0]), + ...x[1], + }) %} + +expr_call_over_frame_bounds + -> kw_between expr_call_over_frame_bound %kw_and expr_call_over_frame_bound {% x => ({ start: unwrap(x[1]), end: unwrap(x[3]) }) %} + | expr_call_over_frame_bound {% x => ({ start: unwrap(x[0]) }) %} + +expr_call_over_frame_bound + -> kw_unbounded kw_preceding {% x => track(x, { type: 'unbounded preceding' }) %} + | kw_unbounded kw_following {% x => track(x, { type: 'unbounded following' }) %} + | kw_current kw_row {% x => track(x, { type: 'current row' }) %} + | expr_call_over_frame_value kw_preceding {% x => track(x, { type: 'preceding', value: unwrap(x[0]) }) %} + | expr_call_over_frame_value kw_following {% x => track(x, { type: 'following', value: unwrap(x[0]) }) %} + +# restricted to unambiguous forms (a general expr would clash with keyword bounds) +expr_call_over_frame_value + -> int {% x => track(x, { type: 'integer', value: unbox(x[0]) }) %} + | %qparam {% x => track(x, { type: 'parameter', name: toStr(x[0]) }) %} + | expr_paren {% unwrap %} + expr_call_within_group -> (kw_within %kw_group) lparen (%kw_order kw_by) diff --git a/src/syntax/expr.spec.ts b/src/syntax/expr.spec.ts index 5cb2efd..cf004c4 100644 --- a/src/syntax/expr.spec.ts +++ b/src/syntax/expr.spec.ts @@ -1558,6 +1558,62 @@ line`, } }) + checkTreeExpr(`SUM(v) OVER (ORDER BY v ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)`, { + type: 'call', + args: [ref('v')], + function: { name: 'sum' }, + over: { + orderBy: [{ by: ref('v') }], + frame: { + unit: 'rows', + start: { type: 'unbounded preceding' }, + end: { type: 'current row' }, + }, + } + }) + + checkTreeExpr(`SUM(v) OVER (ORDER BY v ROWS 2 PRECEDING)`, { + type: 'call', + args: [ref('v')], + function: { name: 'sum' }, + over: { + orderBy: [{ by: ref('v') }], + frame: { + unit: 'rows', + start: { type: 'preceding', value: { type: 'integer', value: 2 } }, + }, + } + }) + + checkTreeExpr(`SUM(v) OVER (PARTITION BY g RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING)`, { + type: 'call', + args: [ref('v')], + function: { name: 'sum' }, + over: { + partitionBy: [ref('g')], + frame: { + unit: 'range', + start: { type: 'current row' }, + end: { type: 'unbounded following' }, + }, + } + }) + + checkTreeExpr(`SUM(v) OVER (GROUPS BETWEEN $1 PRECEDING AND 1 FOLLOWING)`, { + type: 'call', + args: [ref('v')], + function: { name: 'sum' }, + over: { + frame: { + unit: 'groups', + start: { type: 'preceding', value: { type: 'parameter', name: '$1' } }, + end: { type: 'following', value: { type: 'integer', value: 1 } }, + }, + } + }) + + checkInvalidExpr(`SUM(v) OVER (ROWS BETWEEN UNBOUNDED PRECEDING)`); + checkTreeExpr(`pg_catalog.count(*) filter (where val)`, { type: 'call', args: [star], diff --git a/src/to-sql.ts b/src/to-sql.ts index 181023b..3dedd45 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1,7 +1,7 @@ import { IAstPartialMapper, AstDefaultMapper } from './ast-mapper'; import { astVisitor, IAstVisitor, IAstFullVisitor } from './ast-visitor'; import { NotSupported, nil, ReplaceReturnType, NoExtraProperties } from './utils'; -import { TableConstraint, JoinClause, ColumnConstraint, AlterSequenceStatement, CreateSequenceStatement, AlterSequenceSetOptions, CreateSequenceOptions, QName, SetGlobalValue, AlterColumnAddGenerated, QColumn, Name, OrderByStatement, QNameAliased } from './syntax/ast'; +import { TableConstraint, JoinClause, ColumnConstraint, AlterSequenceStatement, CreateSequenceStatement, AlterSequenceSetOptions, CreateSequenceOptions, QName, SetGlobalValue, AlterColumnAddGenerated, QColumn, Name, OrderByStatement, QNameAliased, FrameBound } from './syntax/ast'; import { literal } from './pg-escape'; import { sqlKeywords } from './keywords'; @@ -527,6 +527,26 @@ const visitor = astVisitor(m => ({ visitOrderBy(m, v.over.orderBy); ret.push(' '); } + if (v.over.frame) { + const { unit, start, end } = v.over.frame; + ret.push(unit.toUpperCase(), ' '); + const bound = (b: FrameBound) => { + if (b.value) { + m.expr(b.value); + ret.push(' ', b.type.toUpperCase(), ' '); + } else { + ret.push(b.type.toUpperCase(), ' '); + } + }; + if (end) { + ret.push('BETWEEN '); + bound(start); + ret.push('AND '); + bound(end); + } else { + bound(start); + } + } ret.push(') '); } }, From 38231d45c141350f255ca114d49aa9408f8c3e22 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Wed, 8 Jul 2026 14:03:16 +0530 Subject: [PATCH 02/23] Parse optional CTE column list, '#>' operator, SAVEPOINT statements - WITH RECURSIVE column list is now optional (columnNames?: Name[] | nil), inferred from the seed query by consumers when absent - add the '#>' json path operator (lexer token + ComparisonOperator) - SAVEPOINT / RELEASE [SAVEPOINT] / ROLLBACK TO [SAVEPOINT] statements with new SavepointStatement / ReleaseSavepointStatement AST nodes and RollbackStatement.to; emitted by toSql, covered by roundtripping specs Co-Authored-By: Claude Fable 5 --- src/ast-mapper.ts | 6 +++-- src/lexer.ts | 2 +- src/syntax/ast.ts | 19 +++++++++++++-- src/syntax/base.ne | 2 ++ src/syntax/expr.spec.ts | 13 ++++++++++ src/syntax/simple-statements.ne | 18 +++++++++++++- src/syntax/simple-statements.spec.ts | 15 ++++++++++++ src/syntax/with.ne | 4 ++-- src/syntax/with.spec.ts | 36 ++++++++++++++++++++++++++++ src/to-sql.ts | 19 ++++++++++----- 10 files changed, 120 insertions(+), 14 deletions(-) diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 8a22930..35b3a10 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -28,7 +28,7 @@ export interface IAstPartialMapper { deallocate?: (st: a.DeallocateStatement) => a.Statement | nil parameter?: (st: a.ExprParameter) => a.Expr | nil tableRef?: (st: a.QNameAliased) => a.QNameAliased | nil - transaction?: (val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement) => a.Statement | nil + transaction?: (val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement | a.SavepointStatement | a.ReleaseSavepointStatement) => a.Statement | nil createIndex?: (val: a.CreateIndexStatement) => a.Statement | nil alterTable?: (st: a.AlterTableStatement) => a.Statement | nil alterIndex?: (st: a.AlterIndexStatement) => a.Statement | nil @@ -224,6 +224,8 @@ export class AstDefaultMapper implements IAstMapper { case 'commit': case 'start transaction': case 'rollback': + case 'savepoint': + case 'release savepoint': return this.transaction(val); case 'create index': return this.createIndex(val); @@ -673,7 +675,7 @@ export class AstDefaultMapper implements IAstMapper { return st; } - transaction(val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement): a.Statement | nil { + transaction(val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement | a.SavepointStatement | a.ReleaseSavepointStatement): a.Statement | nil { return val; } diff --git a/src/lexer.ts b/src/lexer.ts index eafe785..19116f4 100644 --- a/src/lexer.ts +++ b/src/lexer.ts @@ -85,7 +85,7 @@ export const lexer = compile({ op_compare: { // group other comparison operators // ... to add: "IN" and "NOT IN" that are matched by keywords - match: ['>', '>=', '<', '<=', '@>', '<@', '?', '?|', '?&', '#>>', '>>', '<<', '~', '~*', '!~', '!~*', '@@'], + match: ['>', '>=', '<', '<=', '@>', '<@', '?', '?|', '?&', '#>>', '#>', '>>', '<<', '~', '~*', '!~', '!~*', '@@'], }, ops_others: { // referenced as (any other operator) in https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-PRECEDENCE diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 674ecd5..615163b 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -23,6 +23,8 @@ export type Statement = SelectStatement | DeleteStatement | WithStatement | RollbackStatement + | SavepointStatement + | ReleaseSavepointStatement | TablespaceStatement | CreateViewStatement | CreateMaterializedViewStatement @@ -239,6 +241,18 @@ export interface CommitStatement extends PGNode { } export interface RollbackStatement extends PGNode { type: 'rollback'; + /** rollback to a savepoint */ + to?: Name | nil; +} + +export interface SavepointStatement extends PGNode { + type: 'savepoint'; + name: Name; +} + +export interface ReleaseSavepointStatement extends PGNode { + type: 'release savepoint'; + name: Name; } export interface TablespaceStatement extends PGNode { @@ -640,7 +654,8 @@ export interface WithStatement extends PGNode { export interface WithRecursiveStatement extends PGNode { type: 'with recursive'; alias: Name; - columnNames: Name[]; + /** column names are optional (inferred from the seed query when absent) */ + columnNames?: Name[] | nil; bind: SelectFromUnion; in: WithStatementBinding; } @@ -820,7 +835,7 @@ export type LogicOperator = 'OR' | 'AND'; export type EqualityOperator = 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE' | '=' | '!='; // see https://www.postgresql.org/docs/12/functions-math.html export type MathOpsBinary = '|' | '&' | '>>' | '^' | '#' | '<<' | '>>'; -export type ComparisonOperator = '>' | '>=' | '<' | '<=' | '@>' | '<@' | '?' | '?|' | '?&' | '#>>' | '~' | '~*' | '!~' | '!~*' | '@@'; +export type ComparisonOperator = '>' | '>=' | '<' | '<=' | '@>' | '<@' | '?' | '?|' | '?&' | '#>' | '#>>' | '~' | '~*' | '!~' | '!~*' | '@@'; export type AdditiveOperator = '||' | '-' | '#-' | '&&' | '+'; export type MultiplicativeOperator = '*' | '%' | '/'; export type ConstructOperator = 'AT TIME ZONE'; diff --git a/src/syntax/base.ne b/src/syntax/base.ne index d60a62b..ef23cd2 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -203,6 +203,8 @@ kw_increment -> %word {% notReservedKw('increment') %} kw_by -> %word {% notReservedKw('by') %} kw_row -> %word {% notReservedKw('row') %} kw_rows -> %word {% notReservedKw('rows') %} +kw_savepoint -> %word {% notReservedKw('savepoint') %} +kw_release -> %word {% notReservedKw('release') %} kw_range -> %word {% notReservedKw('range') %} kw_groups -> %word {% notReservedKw('groups') %} kw_unbounded -> %word {% notReservedKw('unbounded') %} diff --git a/src/syntax/expr.spec.ts b/src/syntax/expr.spec.ts index cf004c4..5f3864d 100644 --- a/src/syntax/expr.spec.ts +++ b/src/syntax/expr.spec.ts @@ -356,6 +356,19 @@ line`, }, }); + checkTreeExpr(`a#>b`, { + type: 'binary', + op: '#>', + left: { + type: 'ref', + name: 'a', + }, + right: { + type: 'ref', + name: 'b', + }, + }); + checkTreeExpr(`a->>-1`, { type: 'member', op: '->>', diff --git a/src/syntax/simple-statements.ne b/src/syntax/simple-statements.ne index 7677bbf..3857330 100644 --- a/src/syntax/simple-statements.ne +++ b/src/syntax/simple-statements.ne @@ -8,6 +8,8 @@ simplestatements_all -> simplestatements_start_transaction | simplestatements_commit | simplestatements_rollback + | simplestatements_savepoint + | simplestatements_release | simplestatements_tablespace | simplestatements_set | simplestatements_show @@ -26,7 +28,21 @@ simplestatements_start_transaction -> (kw_start kw_transaction) {% x => track(x, simplestatements_commit -> kw_commit {% x => track(x, { type: 'commit' }) %} # https://www.postgresql.org/docs/12/sql-rollback.html -simplestatements_rollback -> kw_rollback {% x => track(x, { type: 'rollback' }) %} +simplestatements_rollback -> kw_rollback (%kw_to kw_savepoint:? ident {% last %}):? {% x => track(x, { + type: 'rollback', + ...x[1] && { to: asName(unwrap(x[1])) }, +}) %} + +# https://www.postgresql.org/docs/current/sql-savepoint.html +simplestatements_savepoint -> kw_savepoint ident {% x => track(x, { + type: 'savepoint', + name: asName(x[1]), +}) %} + +simplestatements_release -> kw_release kw_savepoint:? ident {% x => track(x, { + type: 'release savepoint', + name: asName(x[2]), +}) %} simplestatements_tablespace -> kw_tablespace word {% x => track(x, { type: 'tablespace', diff --git a/src/syntax/simple-statements.spec.ts b/src/syntax/simple-statements.spec.ts index 25dfcd8..be640ee 100644 --- a/src/syntax/simple-statements.spec.ts +++ b/src/syntax/simple-statements.spec.ts @@ -18,6 +18,21 @@ describe('Simple statements', () => { type: 'rollback', }); + checkStatement(['rollback to sp1', 'ROLLBACK TO SAVEPOINT sp1'], { + type: 'rollback', + to: { name: 'sp1' }, + }); + + checkStatement(['savepoint sp1', 'SAVEPOINT "sp1"'], { + type: 'savepoint', + name: { name: 'sp1' }, + }); + + checkStatement(['release savepoint sp1', 'RELEASE sp1'], { + type: 'release savepoint', + name: { name: 'sp1' }, + }); + checkStatement(['show server_version', 'show SERVER_VERSION'], { type: 'show', diff --git a/src/syntax/with.ne b/src/syntax/with.ne index a9be4d4..26d0b6a 100644 --- a/src/syntax/with.ne +++ b/src/syntax/with.ne @@ -10,7 +10,7 @@ with_statement -> %kw_with with_statement_bindings with_statement_statement {% x with_recursive_statement -> (%kw_with kw_recursive) ident - collist_paren + collist_paren:? %kw_as lparen union_statement @@ -18,7 +18,7 @@ with_recursive_statement -> (%kw_with kw_recursive) with_statement_statement {% x => track(x, { type: 'with recursive', alias: asName(x[1]), - columnNames: x[2].map(asName), + ...x[2] && { columnNames: x[2].map(asName) }, bind: x[5], in: unwrap(x[7]), }) %} diff --git a/src/syntax/with.spec.ts b/src/syntax/with.spec.ts index 9273ef0..788bde2 100644 --- a/src/syntax/with.spec.ts +++ b/src/syntax/with.spec.ts @@ -116,6 +116,42 @@ describe('With clause', () => { }) + checkStatement(`WITH RECURSIVE t AS ( + SELECT 1 AS n + UNION ALL + SELECT n+1 FROM t WHERE n < 100 + ) + SELECT sum(n) FROM t`, { + type: 'with recursive', + alias: name('t'), + bind: { + type: 'union all', + left: { + type: 'select', + columns: [{ expr: int(1), alias: name('n') }], + }, + right: { + type: 'select', + from: [tbl('t')], + columns: [{ + expr: binary(ref('n'), '+', int(1)) + }], + where: binary(ref('n'), '<', int(100)), + } + }, + in: { + type: 'select', + from: [tbl('t')], + columns: [{ + expr: { + type: 'call', + function: name('sum'), + args: [ref('n')], + } + }], + } + }) + checkStatement(`WITH RECURSIVE t(n) AS ( VALUES (1) UNION ALL diff --git a/src/to-sql.ts b/src/to-sql.ts index 3dedd45..e156444 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -827,11 +827,11 @@ const visitor = astVisitor(m => ({ }, withRecursive: val => { - ret.push('WITH RECURSIVE ' - , name(val.alias) - , '(' - , ...val.columnNames.map(name).join(', ') - , ') AS ('); + ret.push('WITH RECURSIVE ', name(val.alias)); + if (val.columnNames) { + ret.push('(', ...val.columnNames.map(name).join(', '), ')'); + } + ret.push(' AS ('); m.union(val.bind); ret.push(') '); m.statement(val.in); @@ -1507,7 +1507,14 @@ const visitor = astVisitor(m => ({ }, transaction: t => { - ret.push(t.type); + ret.push(t.type.toUpperCase()); + if (t.type === 'rollback' && t.to) { + ret.push(' TO ', name(t.to)); + } + if (t.type === 'savepoint' || t.type === 'release savepoint') { + ret.push(' ', name(t.name)); + } + ret.push(' '); }, unary: t => { From 39967445f70ce61ae9bf3a35e705de428ac2b48c Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Wed, 8 Jul 2026 14:48:38 +0530 Subject: [PATCH 03/23] Parse position(substring in string) special syntax New ExprPosition AST node (mirrors substring/overlay special-call handling), emitted by toSql as POSITION(x IN y). The generic call form 'position(...)' is rejected in the grammar (postgres has no such form - only the IN syntax), which also removes the parse ambiguity with 'x IN y' as a boolean argument. Co-Authored-By: Claude Fable 5 --- src/ast-mapper.ts | 10 ++++++++++ src/syntax/ast.ts | 10 +++++++++- src/syntax/expr.ne | 40 ++++++++++++++++++++++++++++++---------- src/syntax/expr.spec.ts | 6 ++++++ src/to-sql.ts | 8 ++++++++ 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 35b3a10..b0d3b4e 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -72,6 +72,7 @@ export interface IAstPartialMapper { cast?: (val: a.ExprCast) => a.Expr | nil call?: (val: a.ExprCall) => a.Expr | nil callSubstring?: (val: a.ExprSubstring) => a.Expr | nil + callPosition?: (val: a.ExprPosition) => a.Expr | nil callOverlay?: (val: a.ExprOverlay) => a.Expr | nil array?: (val: a.ExprList) => a.Expr | nil constant?: (value: a.ExprLiteral) => a.Expr | nil @@ -1146,6 +1147,8 @@ export class AstDefaultMapper implements IAstMapper { return this.callOverlay(val); case 'substring': return this.callSubstring(val); + case 'position': + return this.callPosition(val); case 'values': return this.values(val); case 'default': @@ -1275,6 +1278,13 @@ export class AstDefaultMapper implements IAstMapper { for: this.expr(val.for), }) } + + callPosition(val: a.ExprPosition): a.Expr | nil { + return assignChanged(val, { + substring: this.expr(val.substring), + string: this.expr(val.string), + }) + } callOverlay(val: a.ExprOverlay): a.Expr | nil { return assignChanged(val, { value: this.expr(val.value), diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 615163b..28ebe90 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -807,7 +807,8 @@ export type Expr = ExprRef | ExprConstant | ExprTernary | ExprOverlay - | ExprSubstring; + | ExprSubstring + | ExprPosition; /** @@ -830,6 +831,13 @@ export interface ExprSubstring extends PGNode { for?: Expr | nil; } +/** Handle special syntax: position('om' in 'Thomas') */ +export interface ExprPosition extends PGNode { + type: 'position'; + substring: Expr; + string: Expr; +} + // === https://www.postgresql.org/docs/12/functions.html export type LogicOperator = 'OR' | 'AND'; export type EqualityOperator = 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE' | '=' | '!='; diff --git a/src/syntax/expr.ne b/src/syntax/expr.ne index 804c204..a7a7ad6 100644 --- a/src/syntax/expr.ne +++ b/src/syntax/expr.ne @@ -205,16 +205,25 @@ expr_call -> expr_fn_name (kw_filter lparen %kw_where expr rparen {% get(3) %}):? expr_call_within_group:? expr_call_over:? - {% x => track(x, { - type: 'call', - function: unwrap(x[0]), - ...x[2] && {distinct: toStr(x[2])}, - args: x[3] || [], - ...x[4] && {orderBy: x[4]}, - ...x[6] && {filter: unwrap(x[6])}, - ...x[7] && {withinGroup: x[7]}, - ...x[8] && {over: unwrap(x[8])}, - }) %} + {% (x, _loc, reject) => { + const fn = unwrap(x[0]); + // "position" has no generic call form in postgres - only the special + // "position(x in y)" syntax (spe_position). Reject the generic parse to + // avoid an ambiguity, since "x in y" is also a valid boolean argument. + if (fn && !fn.schema && typeof fn.name === 'string' && fn.name.toLowerCase() === 'position') { + return reject; + } + return track(x, { + type: 'call', + function: fn, + ...x[2] && {distinct: toStr(x[2])}, + args: x[3] || [], + ...x[4] && {orderBy: x[4]}, + ...x[6] && {filter: unwrap(x[6])}, + ...x[7] && {withinGroup: x[7]}, + ...x[8] && {over: unwrap(x[8])}, + }); + } %} expr_call_over -> kw_over lparen @@ -347,6 +356,7 @@ value_keyword expr_special_calls -> spe_overlay | spe_substring + | spe_position spe_overlay -> (word {% kw('overlay') %}) (%lparen expr_nostar) @@ -372,6 +382,16 @@ spe_substring -> (word {% kw('substring') %}) ...x[3] && {for: x[3][1]}, }) %} +# https://www.postgresql.org/docs/current/functions-string.html position(substring in string) +spe_position -> (word {% kw('position') %}) + (%lparen expr_nostar) + (%kw_in expr_nostar) + %rparen {% x => track(x, { + type: 'position', + substring: x[1][1], + string: x[2][1], + }) %} + various_binaries -> kw_at kw_time kw_zone {% () => 'AT TIME ZONE' %} diff --git a/src/syntax/expr.spec.ts b/src/syntax/expr.spec.ts index 5f3864d..3807897 100644 --- a/src/syntax/expr.spec.ts +++ b/src/syntax/expr.spec.ts @@ -1092,6 +1092,12 @@ line`, type: 'integer', value: 3 }, }); + checkTreeExpr(`position('om' in 'Thomas')`, { + type: 'position', + substring: { type: 'string', value: 'om' }, + string: { type: 'string', value: 'Thomas' }, + }); + checkTreeExpr(`substring('val' from 2)`, { type: 'substring', value: { type: 'string', value: 'val' }, diff --git a/src/to-sql.ts b/src/to-sql.ts index e156444..3ba091e 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -489,6 +489,14 @@ const visitor = astVisitor(m => ({ ret.push(')'); }, + callPosition: p => { + ret.push('POSITION('); + m.expr(p.substring); + ret.push(' IN '); + m.expr(p.string); + ret.push(')'); + }, + binary: v => { m.expr(v.left); visitOp(v); From 5ed0f383e8de00eb8db0e3997b3677155aef101a Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Wed, 8 Jul 2026 16:28:41 +0530 Subject: [PATCH 04/23] Parse roles: CREATE ROLE/USER, DROP ROLE, SET ROLE, RESET Foundation for row-level security: - CREATE ROLE / CREATE USER (SUPERUSER/LOGIN/BYPASSRLS attributes and their NO- forms; PASSWORD and a few common options parsed & ignored; USER implies LOGIN) -> CreateRoleStatement - DROP ROLE / DROP USER (added to drop_what) -> 'drop role' - SET [SESSION|LOCAL] ROLE name | NONE -> SetRoleStatement - RESET role/param -> ResetStatement Unquoted 'none' after SET ROLE disambiguated in the postprocessor. New AST nodes emitted by toSql, covered by specs. Co-Authored-By: Claude Fable 5 --- src/ast-mapper.ts | 22 ++++++++++++ src/syntax/ast.ts | 30 +++++++++++++++- src/syntax/base.ne | 15 ++++++++ src/syntax/create-role.ne | 33 ++++++++++++++++++ src/syntax/create-role.spec.ts | 61 +++++++++++++++++++++++++++++++++ src/syntax/drop.ne | 1 + src/syntax/main.ne | 2 ++ src/syntax/simple-statements.ne | 20 +++++++++++ src/to-sql.ts | 18 ++++++++++ 9 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 src/syntax/create-role.ne create mode 100644 src/syntax/create-role.spec.ts diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index b0d3b4e..b1e2c70 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -84,6 +84,9 @@ export interface IAstPartialMapper { constraint?: (constraint: a.ColumnConstraint) => a.ColumnConstraint | nil valueKeyword?(val: a.ExprValueKeyword): a.Expr | nil tablespace?(val: a.TablespaceStatement): a.Statement | nil + createRole?(val: a.CreateRoleStatement): a.Statement | nil + setRole?(val: a.SetRoleStatement): a.Statement | nil + reset?(val: a.ResetStatement): a.Statement | nil setGlobal?(val: a.SetGlobalStatement): a.Statement | nil setTimezone?(val: a.SetTimezone): a.Statement | nil setNames?(val: a.SetNames): a.Statement | nil @@ -256,6 +259,12 @@ export class AstDefaultMapper implements IAstMapper { return this.setTimezone(val); case 'set names': return this.setNames(val); + case 'create role': + return this.createRole(val); + case 'set role': + return this.setRole(val); + case 'reset': + return this.reset(val); case 'create sequence': return this.createSequence(val); case 'alter sequence': @@ -267,6 +276,7 @@ export class AstDefaultMapper implements IAstMapper { case 'drop sequence': case 'drop type': case 'drop trigger': + case 'drop role': return this.drop(val); case 'create enum': return this.createEnum(val); @@ -401,6 +411,18 @@ export class AstDefaultMapper implements IAstMapper { return val; } + createRole(val: a.CreateRoleStatement): a.Statement | nil { + return val; + } + + setRole(val: a.SetRoleStatement): a.Statement | nil { + return val; + } + + reset(val: a.ResetStatement): a.Statement | nil { + return val; + } + createEnum(val: a.CreateEnumType): a.Statement | nil { return val; } diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 28ebe90..f8826c1 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -35,6 +35,9 @@ export type Statement = SelectStatement | SetGlobalStatement | SetTimezone | SetNames + | CreateRoleStatement + | SetRoleStatement + | ResetStatement | CreateEnumType | CreateCompositeType | AlterEnumType @@ -219,7 +222,7 @@ export interface TruncateTableStatement extends PGNode { } export interface DropStatement extends PGNode { - type: 'drop table' | 'drop sequence' | 'drop index' | 'drop type' | 'drop trigger'; + type: 'drop table' | 'drop sequence' | 'drop index' | 'drop type' | 'drop trigger' | 'drop role'; names: QName[]; ifExists?: boolean; cascade?: 'cascade' | 'restrict'; @@ -1043,6 +1046,31 @@ export interface SetGlobalStatement extends PGNode { scope?: string; set: SetGlobalValue; } + +export interface RoleOptions { + superuser?: boolean; + login?: boolean; + bypassRls?: boolean; +} + +export interface CreateRoleStatement extends PGNode { + type: 'create role'; + name: Name; + options: RoleOptions; +} + +export interface SetRoleStatement extends PGNode { + type: 'set role'; + scope?: string; + /** absent means "NONE" (reset to the session role) */ + role?: Name | nil; +} + +export interface ResetStatement extends PGNode { + type: 'reset'; + /** 'all', or the config parameter / 'role' being reset */ + identifier: 'all' | Name; +} export interface SetTimezone extends PGNode { type: 'set timezone', to: SetTimezoneValue; diff --git a/src/syntax/base.ne b/src/syntax/base.ne index ef23cd2..ef08edd 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -205,6 +205,21 @@ kw_row -> %word {% notReservedKw('row') %} kw_rows -> %word {% notReservedKw('rows') %} kw_savepoint -> %word {% notReservedKw('savepoint') %} kw_release -> %word {% notReservedKw('release') %} +kw_role -> %word {% notReservedKw('role') %} +kw_reset -> %word {% notReservedKw('reset') %} +kw_login -> %word {% notReservedKw('login') %} +kw_nologin -> %word {% notReservedKw('nologin') %} +kw_superuser -> %word {% notReservedKw('superuser') %} +kw_nosuperuser -> %word {% notReservedKw('nosuperuser') %} +kw_bypassrls -> %word {% notReservedKw('bypassrls') %} +kw_nobypassrls -> %word {% notReservedKw('nobypassrls') %} +kw_password -> %word {% notReservedKw('password') %} +kw_createdb -> %word {% notReservedKw('createdb') %} +kw_nocreatedb -> %word {% notReservedKw('nocreatedb') %} +kw_createrole -> %word {% notReservedKw('createrole') %} +kw_nocreaterole -> %word {% notReservedKw('nocreaterole') %} +kw_inherit -> %word {% notReservedKw('inherit') %} +kw_noinherit -> %word {% notReservedKw('noinherit') %} kw_range -> %word {% notReservedKw('range') %} kw_groups -> %word {% notReservedKw('groups') %} kw_unbounded -> %word {% notReservedKw('unbounded') %} diff --git a/src/syntax/create-role.ne b/src/syntax/create-role.ne new file mode 100644 index 0000000..360017b --- /dev/null +++ b/src/syntax/create-role.ne @@ -0,0 +1,33 @@ +@lexer lexerAny +@include "base.ne" + +# https://www.postgresql.org/docs/current/sql-createrole.html +# CREATE USER is CREATE ROLE with LOGIN implied. +createrole_statement -> %kw_create (kw_role | %kw_user) ident %kw_with:? role_option:* {% x => track(x, { + type: 'create role', + name: asName(x[2]), + // "user" (the keyword token) implies LOGIN + ...(toStr(unwrap(x[1])).toLowerCase() === 'user' ? { options: mergeRoleOptions([{ login: true }, ...(x[4] || [])]) } : { options: mergeRoleOptions(x[4] || []) }), +}) %} + +@{% +function mergeRoleOptions(opts: any[]) { + return Object.assign({}, ...opts); +} +%} + +role_option + -> kw_superuser {% () => ({ superuser: true }) %} + | kw_nosuperuser {% () => ({ superuser: false }) %} + | kw_login {% () => ({ login: true }) %} + | kw_nologin {% () => ({ login: false }) %} + | kw_bypassrls {% () => ({ bypassRls: true }) %} + | kw_nobypassrls {% () => ({ bypassRls: false }) %} + # parsed but not modelled (kept lenient for dumps): + | (kw_password string) {% () => ({}) %} + | kw_createdb {% () => ({}) %} + | kw_nocreatedb {% () => ({}) %} + | kw_createrole {% () => ({}) %} + | kw_nocreaterole {% () => ({}) %} + | kw_inherit {% () => ({}) %} + | kw_noinherit {% () => ({}) %} diff --git a/src/syntax/create-role.spec.ts b/src/syntax/create-role.spec.ts new file mode 100644 index 0000000..dc91b8b --- /dev/null +++ b/src/syntax/create-role.spec.ts @@ -0,0 +1,61 @@ +import 'mocha'; +import 'chai'; +import { checkStatement } from './spec-utils'; + +describe('Roles', () => { + + checkStatement(['create role bob'], { + type: 'create role', + name: { name: 'bob' }, + options: {}, + }); + + checkStatement(['create role bob with login superuser bypassrls'], { + type: 'create role', + name: { name: 'bob' }, + options: { login: true, superuser: true, bypassRls: true }, + }); + + checkStatement(['create role bob nologin nosuperuser nobypassrls'], { + type: 'create role', + name: { name: 'bob' }, + options: { login: false, superuser: false, bypassRls: false }, + }); + + checkStatement([`create user alice password 'x'`], { + type: 'create role', + name: { name: 'alice' }, + options: { login: true }, + }); + + checkStatement(['drop role bob'], { + type: 'drop role', + names: [{ name: 'bob' }], + }); + + checkStatement(['drop role if exists bob, alice'], { + type: 'drop role', + ifExists: true, + names: [{ name: 'bob' }, { name: 'alice' }], + }); + + checkStatement(['set role bob', 'SET ROLE bob'], { + type: 'set role', + role: { name: 'bob' }, + }); + + checkStatement(['set session role bob'], { + type: 'set role', + scope: 'session', + role: { name: 'bob' }, + }); + + checkStatement(['set role none'], { + type: 'set role', + }); + + checkStatement(['reset role'], { + type: 'reset', + identifier: { name: 'role' }, + }); +}); diff --git a/src/syntax/drop.ne b/src/syntax/drop.ne index b9c3e1d..63f95e8 100644 --- a/src/syntax/drop.ne +++ b/src/syntax/drop.ne @@ -22,6 +22,7 @@ drop_what | kw_sequence {% x => track(x, { type: 'drop sequence' }) %} | kw_type {% x => track(x, { type: 'drop type' }) %} | kw_trigger {% x => track(x, { type: 'drop trigger' }) %} + | (kw_role | %kw_user) {% x => track(x, { type: 'drop role' }) %} | kw_index %kw_concurrently:? {% x => track(x, { type: 'drop index', ...x[1] && {concurrently: true }, diff --git a/src/syntax/main.ne b/src/syntax/main.ne index 611df40..a73e07b 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -10,6 +10,7 @@ import {lexerAny} from '../lexer'; @include "create-table.ne" @include "create-index.ne" @include "create-extension.ne" +@include "create-role.ne" @include "simple-statements.ne" @include "insert.ne" @include "update.ne" @@ -48,6 +49,7 @@ statement_noprep -> selection | createtable_statement | createextension_statement + | createrole_statement | createindex_statement | simplestatements_all | insert_statement diff --git a/src/syntax/simple-statements.ne b/src/syntax/simple-statements.ne index 3857330..c12db4c 100644 --- a/src/syntax/simple-statements.ne +++ b/src/syntax/simple-statements.ne @@ -12,6 +12,8 @@ simplestatements_all | simplestatements_release | simplestatements_tablespace | simplestatements_set + | simplestatements_set_role + | simplestatements_reset | simplestatements_show | simplestatements_begin @@ -88,6 +90,24 @@ simplestatements_set_val_raw simplestatements_show -> kw_show ident {% x => track(x, { type: 'show', variable: asName(x[1]) }) %} +# https://www.postgresql.org/docs/current/sql-set-role.html +# unquoted "none" resets to the session role; anything else is a role name +simplestatements_set_role -> kw_set (kw_session | kw_local):? kw_role ident {% x => { + const r = asName(x[3]); + return track(x, { + type: 'set role', + scope: unwrap(x[1])?.toLowerCase(), + ...(r.name.toLowerCase() === 'none' ? {} : { role: r }), + }); +} %} + +# https://www.postgresql.org/docs/current/sql-reset.html +simplestatements_reset -> kw_reset (%kw_all {% () => 'all' %} | ident) {% x => track(x, { + type: 'reset', + identifier: unwrap(x[1]) === 'all' ? 'all' : asName(unwrap(x[1])), +}) %} + + # https://www.postgresql.org/docs/current/sql-createschema.html create_schema -> (%kw_create kw_schema) kw_ifnotexists:? ident {% x => track(x, { diff --git a/src/to-sql.ts b/src/to-sql.ts index 3ba091e..6d55412 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1442,6 +1442,24 @@ const visitor = astVisitor(m => ({ ret.push('SHOW ', name(s.variable)); }, + createRole: r => { + ret.push('CREATE ROLE ', name(r.name)); + const o = r.options; + if (o.superuser !== undefined) ret.push(o.superuser ? ' SUPERUSER' : ' NOSUPERUSER'); + if (o.login !== undefined) ret.push(o.login ? ' LOGIN' : ' NOLOGIN'); + if (o.bypassRls !== undefined) ret.push(o.bypassRls ? ' BYPASSRLS' : ' NOBYPASSRLS'); + }, + + setRole: r => { + ret.push('SET '); + if (r.scope) ret.push(r.scope.toUpperCase(), ' '); + ret.push('ROLE ', r.role ? name(r.role) : 'NONE'); + }, + + reset: r => { + ret.push('RESET ', r.identifier === 'all' ? 'ALL' : name(r.identifier)); + }, + prepare: s => { ret.push('PREPARE ', name(s.name)); if (s.args?.length) { From bca606d02b3ce04f6801be1aefe1cb95a944590a Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Wed, 8 Jul 2026 16:38:57 +0530 Subject: [PATCH 05/23] Parse RLS policy DDL: CREATE/DROP POLICY, ALTER TABLE ... ROW LEVEL SECURITY - CREATE POLICY name ON table [AS PERMISSIVE|RESTRICTIVE] [FOR ALL|SELECT|INSERT|UPDATE|DELETE] [TO roles] [USING (expr)] [WITH CHECK (expr)] -> CreatePolicyStatement - DROP POLICY [IF EXISTS] name ON table -> DropPolicyStatement - ALTER TABLE ... {ENABLE|DISABLE|FORCE|NO FORCE} ROW LEVEL SECURITY -> TableAlterationRowLevelSecurity New AST nodes emitted by toSql, covered by specs. Co-Authored-By: Claude Fable 5 --- src/ast-mapper.ts | 23 ++++++++++++ src/syntax/alter-table.ne | 7 ++++ src/syntax/ast.ts | 29 ++++++++++++++ src/syntax/base.ne | 8 ++++ src/syntax/main.ne | 3 ++ src/syntax/policy.ne | 44 ++++++++++++++++++++++ src/syntax/policy.spec.ts | 79 +++++++++++++++++++++++++++++++++++++++ src/to-sql.ts | 40 ++++++++++++++++++++ 8 files changed, 233 insertions(+) create mode 100644 src/syntax/policy.ne create mode 100644 src/syntax/policy.spec.ts diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index b1e2c70..5073faf 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -37,6 +37,7 @@ export interface IAstPartialMapper { dropConstraint?: (change: a.TableAlterationDropConstraint, table: a.QNameAliased) => a.TableAlteration | nil renameConstraint?: (change: a.TableAlterationRenameConstraint, table: a.QNameAliased) => a.TableAlteration | nil setTableOwner?: (change: a.TableAlterationOwner, table: a.QNameAliased) => a.TableAlteration | nil + setRowLevelSecurity?: (change: a.TableAlterationRowLevelSecurity, table: a.QNameAliased) => a.TableAlteration | nil renameColumn?: (change: a.TableAlterationRenameColumn, table: a.QNameAliased) => a.TableAlteration | nil renameTable?: (change: a.TableAlterationRename, table: a.QNameAliased) => a.TableAlteration | nil alterColumn?: (change: a.TableAlterationAlterColumn, inTable: a.QNameAliased) => a.TableAlteration | nil @@ -87,6 +88,8 @@ export interface IAstPartialMapper { createRole?(val: a.CreateRoleStatement): a.Statement | nil setRole?(val: a.SetRoleStatement): a.Statement | nil reset?(val: a.ResetStatement): a.Statement | nil + createPolicy?(val: a.CreatePolicyStatement): a.Statement | nil + dropPolicy?(val: a.DropPolicyStatement): a.Statement | nil setGlobal?(val: a.SetGlobalStatement): a.Statement | nil setTimezone?(val: a.SetTimezone): a.Statement | nil setNames?(val: a.SetNames): a.Statement | nil @@ -265,6 +268,10 @@ export class AstDefaultMapper implements IAstMapper { return this.setRole(val); case 'reset': return this.reset(val); + case 'create policy': + return this.createPolicy(val); + case 'drop policy': + return this.dropPolicy(val); case 'create sequence': return this.createSequence(val); case 'alter sequence': @@ -423,6 +430,16 @@ export class AstDefaultMapper implements IAstMapper { return val; } + createPolicy(val: a.CreatePolicyStatement): a.Statement | nil { + const using = this.expr(val.using); + const withCheck = this.expr(val.withCheck); + return assignChanged(val, { using, withCheck }); + } + + dropPolicy(val: a.DropPolicyStatement): a.Statement | nil { + return val; + } + createEnum(val: a.CreateEnumType): a.Statement | nil { return val; } @@ -809,6 +826,8 @@ export class AstDefaultMapper implements IAstMapper { return this.dropConstraint(change, table); case 'owner': return this.setTableOwner(change, table); + case 'row level security': + return this.setRowLevelSecurity(change, table); default: throw NotSupported.never(change); } @@ -826,6 +845,10 @@ export class AstDefaultMapper implements IAstMapper { return change; } + setRowLevelSecurity(change: a.TableAlterationRowLevelSecurity, table: a.QNameAliased): a.TableAlteration | nil { + return change; + } + renameConstraint(change: a.TableAlterationRenameConstraint, table: a.QNameAliased): a.TableAlteration | nil { return change; } diff --git a/src/syntax/alter-table.ne b/src/syntax/alter-table.ne index 46ec502..382143c 100644 --- a/src/syntax/alter-table.ne +++ b/src/syntax/alter-table.ne @@ -28,6 +28,7 @@ altertable_action | altertable_add_constraint | altertable_drop_constraint | altertable_owner + | altertable_row_security altertable_rename_table -> kw_rename %kw_to word {% x => track(x, { @@ -35,6 +36,12 @@ altertable_rename_table -> kw_rename %kw_to word {% x => track(x, { to: asName(last(x)), }) %} +altertable_row_security -> (kw_enable | kw_disable | kw_force | kw_no kw_force {% () => 'no force' %}) + kw_row kw_level kw_security {% x => track(x, { + type: 'row level security', + action: (() => { const v = unwrap(x[0]); return typeof v === 'string' ? v : toStr(v); })(), +}) %} + altertable_rename_column -> kw_rename kw_column:? ident %kw_to ident {% x => track(x, { type: 'rename column', column: asName(x[2]), diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index f8826c1..4047e1a 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -38,6 +38,8 @@ export type Statement = SelectStatement | CreateRoleStatement | SetRoleStatement | ResetStatement + | CreatePolicyStatement + | DropPolicyStatement | CreateEnumType | CreateCompositeType | AlterEnumType @@ -383,6 +385,7 @@ export type TableAlteration = TableAlterationRename | TableAlterationAddConstraint | TableAlterationOwner | TableAlterationDropConstraint + | TableAlterationRowLevelSecurity export interface TableAlterationOwner extends PGNode { @@ -390,6 +393,11 @@ export interface TableAlterationOwner extends PGNode { to: Name; } +export interface TableAlterationRowLevelSecurity extends PGNode { + type: 'row level security'; + action: 'enable' | 'disable' | 'force' | 'no force'; +} + export interface AlterColumnSetType extends PGNode { type: 'set type'; dataType: DataTypeDef; @@ -1071,6 +1079,27 @@ export interface ResetStatement extends PGNode { /** 'all', or the config parameter / 'role' being reset */ identifier: 'all' | Name; } + +export type PolicyCommand = 'all' | 'select' | 'insert' | 'update' | 'delete'; + +export interface CreatePolicyStatement extends PGNode { + type: 'create policy'; + name: Name; + table: QName; + /** true = PERMISSIVE (default), false = RESTRICTIVE */ + permissive?: boolean; + for?: PolicyCommand; + roles?: Name[]; + using?: Expr; + withCheck?: Expr; +} + +export interface DropPolicyStatement extends PGNode { + type: 'drop policy'; + name: Name; + table: QName; + ifExists?: boolean; +} export interface SetTimezone extends PGNode { type: 'set timezone', to: SetTimezoneValue; diff --git a/src/syntax/base.ne b/src/syntax/base.ne index ef08edd..300d677 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -157,6 +157,14 @@ kw_read -> %word {% notReservedKw('read') %} kw_write -> %word {% notReservedKw('write') %} kw_isolation -> %word {% notReservedKw('isolation') %} kw_level -> %word {% notReservedKw('level') %} +kw_policy -> %word {% notReservedKw('policy') %} +kw_permissive -> %word {% notReservedKw('permissive') %} +kw_restrictive -> %word {% notReservedKw('restrictive') %} +kw_force -> %word {% notReservedKw('force') %} +kw_security -> %word {% notReservedKw('security') %} +kw_enable -> %word {% notReservedKw('enable') %} +kw_disable -> %word {% notReservedKw('disable') %} +kw_public -> %word {% notReservedKw('public') %} kw_serializable -> %word {% notReservedKw('serializable') %} kw_rollback -> %word {% notReservedKw('rollback') %} kw_insert -> %word {% notReservedKw('insert') %} diff --git a/src/syntax/main.ne b/src/syntax/main.ne index a73e07b..92d2cdc 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -11,6 +11,7 @@ import {lexerAny} from '../lexer'; @include "create-index.ne" @include "create-extension.ne" @include "create-role.ne" +@include "policy.ne" @include "simple-statements.ne" @include "insert.ne" @include "update.ne" @@ -50,6 +51,8 @@ statement_noprep | createtable_statement | createextension_statement | createrole_statement + | createpolicy_statement + | droppolicy_statement | createindex_statement | simplestatements_all | insert_statement diff --git a/src/syntax/policy.ne b/src/syntax/policy.ne new file mode 100644 index 0000000..5942b79 --- /dev/null +++ b/src/syntax/policy.ne @@ -0,0 +1,44 @@ +@lexer lexerAny +@include "base.ne" +@include "expr.ne" + +# https://www.postgresql.org/docs/current/sql-createpolicy.html +createpolicy_statement -> %kw_create kw_policy ident %kw_on qualified_name + (%kw_as (kw_permissive | kw_restrictive) {% x => toStr(x[1]) %}):? + (%kw_for policy_command {% last %}):? + (%kw_to policy_role_list {% last %}):? + (%kw_using lparen expr rparen {% x => x[2] %}):? + (%kw_with %kw_check lparen expr rparen {% x => x[3] %}):? + {% x => track(x, { + type: 'create policy', + name: asName(x[2]), + table: x[4], + ...(x[5] ? { permissive: x[5].toLowerCase() === 'permissive' } : {}), + ...(x[6] ? { for: x[6] } : {}), + ...(x[7] ? { roles: x[7] } : {}), + ...(x[8] ? { using: unwrap(x[8]) } : {}), + ...(x[9] ? { withCheck: unwrap(x[9]) } : {}), + }) %} + +policy_command + -> %kw_all {% () => 'all' %} + | %kw_select {% () => 'select' %} + | kw_insert {% () => 'insert' %} + | kw_update {% () => 'update' %} + | kw_delete {% () => 'delete' %} + +policy_role_list -> policy_role (comma policy_role {% last %}):* {% ([head, tail]) => [head, ...(tail || [])] %} + +policy_role + -> ident {% x => asName(unwrap(x)) %} + | %kw_current_user {% x => track(x, { name: 'current_user' }) %} + | %kw_current_role {% x => track(x, { name: 'current_role' }) %} + | %kw_session_user {% x => track(x, { name: 'session_user' }) %} + +# https://www.postgresql.org/docs/current/sql-droppolicy.html +droppolicy_statement -> kw_drop kw_policy kw_ifexists:? ident %kw_on qualified_name (kw_cascade | kw_restrict):? {% x => track(x, { + type: 'drop policy', + name: asName(x[3]), + table: x[5], + ...(x[2] ? { ifExists: true } : {}), +}) %} diff --git a/src/syntax/policy.spec.ts b/src/syntax/policy.spec.ts new file mode 100644 index 0000000..613ab0f --- /dev/null +++ b/src/syntax/policy.spec.ts @@ -0,0 +1,79 @@ +import 'mocha'; +import 'chai'; +import { checkStatement, ref, binary } from './spec-utils'; + +describe('Row-level security', () => { + + checkStatement([`create policy p on t using (owner = current_user)`], { + type: 'create policy', + name: { name: 'p' }, + table: { name: 't' }, + using: binary(ref('owner'), '=', { type: 'keyword', keyword: 'current_user' } as any), + }); + + checkStatement([`create policy p on t as restrictive for select to alice, bob using (a)`], { + type: 'create policy', + name: { name: 'p' }, + table: { name: 't' }, + permissive: false, + for: 'select', + roles: [{ name: 'alice' }, { name: 'bob' }], + using: ref('a'), + }); + + checkStatement([`create policy p on t for insert to public with check (a)`], { + type: 'create policy', + name: { name: 'p' }, + table: { name: 't' }, + for: 'insert', + roles: [{ name: 'public' }], + withCheck: ref('a'), + }); + + checkStatement([`create policy p on s.t as permissive for update using (a) with check (b)`], { + type: 'create policy', + name: { name: 'p' }, + table: { name: 't', schema: 's' }, + permissive: true, + for: 'update', + using: ref('a'), + withCheck: ref('b'), + }); + + checkStatement([`drop policy p on t`], { + type: 'drop policy', + name: { name: 'p' }, + table: { name: 't' }, + }); + + checkStatement([`drop policy if exists p on t`], { + type: 'drop policy', + name: { name: 'p' }, + table: { name: 't' }, + ifExists: true, + }); + + checkStatement([`alter table t enable row level security`], { + type: 'alter table', + table: { name: 't' }, + changes: [{ type: 'row level security', action: 'enable' }], + }); + + checkStatement([`alter table t disable row level security`], { + type: 'alter table', + table: { name: 't' }, + changes: [{ type: 'row level security', action: 'disable' }], + }); + + checkStatement([`alter table t force row level security`], { + type: 'alter table', + table: { name: 't' }, + changes: [{ type: 'row level security', action: 'force' }], + }); + + checkStatement([`alter table t no force row level security`], { + type: 'alter table', + table: { name: 't' }, + changes: [{ type: 'row level security', action: 'no force' }], + }); +}); diff --git a/src/to-sql.ts b/src/to-sql.ts index 6d55412..52b2026 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -356,6 +356,10 @@ const visitor = astVisitor(m => ({ ret.push(' OWNER TO ', name(o.to)); }, + setRowLevelSecurity: c => { + ret.push(' ', c.action.toUpperCase(), ' ROW LEVEL SECURITY'); + }, + alterColumnSimple: c => ret.push(c.type), @@ -425,6 +429,8 @@ const visitor = astVisitor(m => ({ return m.dropConstraint(change, table); case 'owner': return m.setTableOwner(change, table); + case 'row level security': + return m.setRowLevelSecurity(change, table); default: throw NotSupported.never(change); } @@ -1460,6 +1466,40 @@ const visitor = astVisitor(m => ({ ret.push('RESET ', r.identifier === 'all' ? 'ALL' : name(r.identifier)); }, + createPolicy: p => { + ret.push('CREATE POLICY ', name(p.name), ' ON '); + visitQualifiedName(p.table); + if (p.permissive !== undefined) { + ret.push(' AS ', p.permissive ? 'PERMISSIVE' : 'RESTRICTIVE'); + } + if (p.for) { + ret.push(' FOR ', p.for.toUpperCase()); + } + if (p.roles?.length) { + ret.push(' TO '); + list(p.roles, r => ret.push(name(r)), false); + } + if (p.using) { + ret.push(' USING ('); + m.expr(p.using); + ret.push(')'); + } + if (p.withCheck) { + ret.push(' WITH CHECK ('); + m.expr(p.withCheck); + ret.push(')'); + } + }, + + dropPolicy: p => { + ret.push('DROP POLICY '); + if (p.ifExists) { + ret.push('IF EXISTS '); + } + ret.push(name(p.name), ' ON '); + visitQualifiedName(p.table); + }, + prepare: s => { ret.push('PREPARE ', name(s.name)); if (s.args?.length) { From a6b1217279fec9e9d9b8f4272c7ed42a8ec937af Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Wed, 8 Jul 2026 16:54:20 +0530 Subject: [PATCH 06/23] Parse GRANT / REVOKE statements Table/sequence GRANT and REVOKE (privileges | ALL, TO/FROM roles, WITH GRANT OPTION). New GrantStatement / RevokeStatement AST nodes emitted by toSql, covered by specs. Enables loading dumps and RLS setup scripts (pg-mem treats them as no-ops - no privilege system). Co-Authored-By: Claude Fable 5 --- src/ast-mapper.ts | 14 ++++++++++++ src/syntax/ast.ts | 23 ++++++++++++++++++++ src/syntax/base.ne | 5 +++++ src/syntax/grant.ne | 47 ++++++++++++++++++++++++++++++++++++++++ src/syntax/grant.spec.ts | 42 +++++++++++++++++++++++++++++++++++ src/syntax/main.ne | 3 +++ src/to-sql.ts | 21 ++++++++++++++++++ 7 files changed, 155 insertions(+) create mode 100644 src/syntax/grant.ne create mode 100644 src/syntax/grant.spec.ts diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 5073faf..377a3e1 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -90,6 +90,8 @@ export interface IAstPartialMapper { reset?(val: a.ResetStatement): a.Statement | nil createPolicy?(val: a.CreatePolicyStatement): a.Statement | nil dropPolicy?(val: a.DropPolicyStatement): a.Statement | nil + grant?(val: a.GrantStatement): a.Statement | nil + revoke?(val: a.RevokeStatement): a.Statement | nil setGlobal?(val: a.SetGlobalStatement): a.Statement | nil setTimezone?(val: a.SetTimezone): a.Statement | nil setNames?(val: a.SetNames): a.Statement | nil @@ -272,6 +274,10 @@ export class AstDefaultMapper implements IAstMapper { return this.createPolicy(val); case 'drop policy': return this.dropPolicy(val); + case 'grant': + return this.grant(val); + case 'revoke': + return this.revoke(val); case 'create sequence': return this.createSequence(val); case 'alter sequence': @@ -440,6 +446,14 @@ export class AstDefaultMapper implements IAstMapper { return val; } + grant(val: a.GrantStatement): a.Statement | nil { + return val; + } + + revoke(val: a.RevokeStatement): a.Statement | nil { + return val; + } + createEnum(val: a.CreateEnumType): a.Statement | nil { return val; } diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 4047e1a..d60189f 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -40,6 +40,8 @@ export type Statement = SelectStatement | ResetStatement | CreatePolicyStatement | DropPolicyStatement + | GrantStatement + | RevokeStatement | CreateEnumType | CreateCompositeType | AlterEnumType @@ -1100,6 +1102,27 @@ export interface DropPolicyStatement extends PGNode { table: QName; ifExists?: boolean; } + +export interface GrantOnTarget extends PGNode { + type: 'table'; + names: QName[]; +} + +export interface GrantStatement extends PGNode { + type: 'grant'; + privileges: 'all' | string[]; + on: GrantOnTarget; + to: Name[]; + withGrantOption?: boolean; +} + +export interface RevokeStatement extends PGNode { + type: 'revoke'; + privileges: 'all' | string[]; + on: GrantOnTarget; + from: Name[]; + grantOptionFor?: boolean; +} export interface SetTimezone extends PGNode { type: 'set timezone', to: SetTimezoneValue; diff --git a/src/syntax/base.ne b/src/syntax/base.ne index 300d677..2162ff9 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -165,6 +165,11 @@ kw_security -> %word {% notReservedKw('security') %} kw_enable -> %word {% notReservedKw('enable') %} kw_disable -> %word {% notReservedKw('disable') %} kw_public -> %word {% notReservedKw('public') %} +kw_revoke -> %word {% notReservedKw('revoke') %} +kw_privileges -> %word {% notReservedKw('privileges') %} +kw_usage -> %word {% notReservedKw('usage') %} +kw_execute -> %word {% notReservedKw('execute') %} +kw_connect -> %word {% notReservedKw('connect') %} kw_serializable -> %word {% notReservedKw('serializable') %} kw_rollback -> %word {% notReservedKw('rollback') %} kw_insert -> %word {% notReservedKw('insert') %} diff --git a/src/syntax/grant.ne b/src/syntax/grant.ne new file mode 100644 index 0000000..408a1ba --- /dev/null +++ b/src/syntax/grant.ne @@ -0,0 +1,47 @@ +@lexer lexerAny +@include "base.ne" + +# https://www.postgresql.org/docs/current/sql-grant.html +# Parsed but semantically a no-op in pg-mem (no privilege system) - kept so dumps and +# RLS setup scripts load. +grant_statement -> %kw_grant grant_privileges grant_on_target %kw_to grant_grantees + (%kw_with %kw_grant kw_option {% () => true %}):? + {% x => track(x, { + type: 'grant', + privileges: x[1], + on: x[2], + to: x[4], + ...(x[5] ? { withGrantOption: true } : {}), + }) %} + +revoke_statement -> kw_revoke (%kw_grant kw_option %kw_for {% () => true %}):? + grant_privileges grant_on_target %kw_from grant_grantees + (kw_cascade | kw_restrict):? + {% x => track(x, { + type: 'revoke', + privileges: x[2], + on: x[3], + from: x[5], + ...(x[1] ? { grantOptionFor: true } : {}), + }) %} + +grant_privileges + -> %kw_all kw_privileges:? {% () => 'all' %} + | grant_priv (comma grant_priv {% last %}):* {% ([head, tail]) => [head, ...(tail || [])] %} + +grant_priv -> (%kw_select | %kw_references | kw_insert | kw_update | kw_delete | kw_truncate | kw_trigger | kw_usage | kw_execute | kw_connect | kw_temporary | kw_temp) {% x => toStr(unwrap(x)).toLowerCase() %} + +# only the "[TABLE] name[, ...]" object form is modelled; other object types are ignored +grant_on_target -> %kw_on (%kw_table | kw_sequence):? grant_name_list {% x => track(x, { + type: 'table', + names: x[2], +}) %} + +grant_name_list -> qualified_name (comma qualified_name {% last %}):* {% ([head, tail]) => [head, ...(tail || [])] %} + +grant_grantees -> grant_grantee (comma grant_grantee {% last %}):* {% ([head, tail]) => [head, ...(tail || [])] %} + +grant_grantee + -> (%kw_group {% () => null %}):? ident {% x => asName(x[1]) %} + | %kw_current_user {% x => track(x, { name: 'current_user' }) %} + | %kw_session_user {% x => track(x, { name: 'session_user' }) %} diff --git a/src/syntax/grant.spec.ts b/src/syntax/grant.spec.ts new file mode 100644 index 0000000..0405d11 --- /dev/null +++ b/src/syntax/grant.spec.ts @@ -0,0 +1,42 @@ +import 'mocha'; +import 'chai'; +import { checkStatement } from './spec-utils'; + +describe('Grant / revoke', () => { + + checkStatement([`grant select on docs to alice`], { + type: 'grant', + privileges: ['select'], + on: { type: 'table', names: [{ name: 'docs' }] }, + to: [{ name: 'alice' }], + }); + + checkStatement([`grant select, insert, update on table docs to alice, bob`], { + type: 'grant', + privileges: ['select', 'insert', 'update'], + on: { type: 'table', names: [{ name: 'docs' }] }, + to: [{ name: 'alice' }, { name: 'bob' }], + }); + + checkStatement([`grant all on docs to public`], { + type: 'grant', + privileges: 'all', + on: { type: 'table', names: [{ name: 'docs' }] }, + to: [{ name: 'public' }], + }); + + checkStatement([`grant all privileges on docs to alice with grant option`], { + type: 'grant', + privileges: 'all', + on: { type: 'table', names: [{ name: 'docs' }] }, + to: [{ name: 'alice' }], + withGrantOption: true, + }); + + checkStatement([`revoke select on docs from alice`], { + type: 'revoke', + privileges: ['select'], + on: { type: 'table', names: [{ name: 'docs' }] }, + from: [{ name: 'alice' }], + }); +}); diff --git a/src/syntax/main.ne b/src/syntax/main.ne index 92d2cdc..3c78e21 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -12,6 +12,7 @@ import {lexerAny} from '../lexer'; @include "create-extension.ne" @include "create-role.ne" @include "policy.ne" +@include "grant.ne" @include "simple-statements.ne" @include "insert.ne" @include "update.ne" @@ -53,6 +54,8 @@ statement_noprep | createrole_statement | createpolicy_statement | droppolicy_statement + | grant_statement + | revoke_statement | createindex_statement | simplestatements_all | insert_statement diff --git a/src/to-sql.ts b/src/to-sql.ts index 52b2026..f01e3a5 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1500,6 +1500,27 @@ const visitor = astVisitor(m => ({ visitQualifiedName(p.table); }, + grant: g => { + ret.push('GRANT ', g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' ON '); + list(g.on.names, n => visitQualifiedName(n), false); + ret.push(' TO '); + list(g.to, r => ret.push(name(r)), false); + if (g.withGrantOption) { + ret.push(' WITH GRANT OPTION'); + } + }, + + revoke: g => { + ret.push('REVOKE '); + if (g.grantOptionFor) { + ret.push('GRANT OPTION FOR '); + } + ret.push(g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' ON '); + list(g.on.names, n => visitQualifiedName(n), false); + ret.push(' FROM '); + list(g.from, r => ret.push(name(r)), false); + }, + prepare: s => { ret.push('PREPARE ', name(s.name)); if (s.args?.length) { From 17353b716c4eeeef4a553ea7a21622b0a4aaab20 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Wed, 8 Jul 2026 19:12:23 +0530 Subject: [PATCH 07/23] Parse DEFERRABLE / INITIALLY DEFERRED on foreign keys Adds DEFERRABLE / NOT DEFERRABLE and INITIALLY DEFERRED / IMMEDIATE to the FK reference grammar (column- and table-level), surfaced on TableReference as deferrable / initiallyDeferred and emitted by toSql. Co-Authored-By: Claude Fable 5 --- src/syntax/ast.ts | 2 ++ src/syntax/base.ne | 2 ++ src/syntax/create-table.ne | 2 ++ src/syntax/create-table.spec.ts | 20 +++++++++++++++++++- src/to-sql.ts | 6 ++++++ 5 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index d60189f..b3f6fdf 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -621,6 +621,8 @@ export interface TableReference { onDelete?: ConstraintAction; onUpdate?: ConstraintAction; match?: 'full' | 'partial' | 'simple'; + deferrable?: boolean; + initiallyDeferred?: boolean; } diff --git a/src/syntax/base.ne b/src/syntax/base.ne index 2162ff9..3d7c6e8 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -170,6 +170,8 @@ kw_privileges -> %word {% notReservedKw('privileges') %} kw_usage -> %word {% notReservedKw('usage') %} kw_execute -> %word {% notReservedKw('execute') %} kw_connect -> %word {% notReservedKw('connect') %} +kw_deferred -> %word {% notReservedKw('deferred') %} +kw_immediate -> %word {% notReservedKw('immediate') %} kw_serializable -> %word {% notReservedKw('serializable') %} kw_rollback -> %word {% notReservedKw('rollback') %} kw_insert -> %word {% notReservedKw('insert') %} diff --git a/src/syntax/create-table.ne b/src/syntax/create-table.ne index 441b422..c6beec5 100644 --- a/src/syntax/create-table.ne +++ b/src/syntax/create-table.ne @@ -106,6 +106,8 @@ createtable_constraint_foreignkey_onsometing -> %kw_on kw_delete createtable_constraint_on_action {% x => track(x, {onDelete: last(x)}) %} | %kw_on kw_update createtable_constraint_on_action {% x => track(x, {onUpdate: last(x)}) %} | kw_match (%kw_full | kw_partial | kw_simple) {% x => track(x, {match: toStr(last(x))}) %} + | %kw_not:? %kw_deferrable {% x => track(x, {deferrable: !x[0]}) %} + | %kw_initially (kw_deferred | kw_immediate) {% x => track(x, {initiallyDeferred: toStr(last(x)).toLowerCase() === 'deferred'}) %} createtable_constraint_on_action -> (kw_cascade diff --git a/src/syntax/create-table.spec.ts b/src/syntax/create-table.spec.ts index 5b07a41..e564a64 100644 --- a/src/syntax/create-table.spec.ts +++ b/src/syntax/create-table.spec.ts @@ -758,4 +758,22 @@ describe('Create table', () => { }, ] }) -}); \ No newline at end of file +}); +describe('Create table (deferrable FK)', () => { + checkCreateTable([`create table b (id int references a(id) deferrable initially deferred)`], { + type: 'create table', + name: { name: 'b' }, + columns: [{ + kind: 'column', + name: { name: 'id' }, + dataType: { name: 'int' }, + constraints: [{ + type: 'reference', + foreignTable: { name: 'a' }, + foreignColumns: [{ name: 'id' }], + deferrable: true, + initiallyDeferred: true, + }], + }], + }); +}); diff --git a/src/to-sql.ts b/src/to-sql.ts index f01e3a5..64c99a7 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -70,6 +70,12 @@ function addConstraint(c: ColumnConstraint | TableConstraint, m: IAstVisitor) { if (c.onUpdate) { ret.push(' ON UPDATE ', c.onUpdate); } + if (c.deferrable !== undefined) { + ret.push(c.deferrable ? ' DEFERRABLE' : ' NOT DEFERRABLE'); + } + if (c.initiallyDeferred !== undefined) { + ret.push(' INITIALLY ', c.initiallyDeferred ? 'DEFERRED' : 'IMMEDIATE'); + } break; case 'primary key': case 'unique': From 5f8c876d9e8ee807650e395f82a33a79f2fd2391 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Wed, 8 Jul 2026 23:43:36 +0530 Subject: [PATCH 08/23] Preserve exact literal precision on integer/numeric AST nodes JS numbers lose precision for large integers (>2^53) and can't exactly represent many decimals, corrupting literals at parse time. Integer and numeric AST nodes now carry an optional valueText with the exact source digits - integers only when the value isn't a safe JS integer, numerics for any fractional/exponent literal (canonicalized so equivalent forms like .5 and 0.5 match). toSql emits valueText when present. This is the groundwork for arbitrary-precision bigint/numeric in consumers. Co-Authored-By: Claude Fable 5 --- src/syntax/ast.ts | 4 ++++ src/syntax/base.ne | 33 +++++++++++++++++++++++++++++++++ src/syntax/expr.ne | 4 ++-- src/syntax/expr.spec.ts | 8 ++++++++ src/syntax/spec-utils.ts | 5 ++++- src/to-sql.ts | 7 ++++++- 6 files changed, 57 insertions(+), 4 deletions(-) diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index b3f6fdf..da7b385 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -1019,6 +1019,8 @@ export interface ExprNull extends PGNode { export interface ExprInteger extends PGNode { type: 'integer'; value: number; + /** exact source digits, present only when `value` (a JS number) loses precision */ + valueText?: string; } export interface ExprDefault extends PGNode { @@ -1028,6 +1030,8 @@ export interface ExprDefault extends PGNode { export interface ExprNumeric extends PGNode { type: 'numeric'; value: number; + /** exact source text, present for fractional/exponent literals */ + valueText?: string; } export interface ExprString extends PGNode { diff --git a/src/syntax/base.ne b/src/syntax/base.ne index 3d7c6e8..12a78e9 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -73,6 +73,39 @@ return flattenStr(e).join(join || ''); } + function mkInteger(tok: any) { + const text = String(tok?.value ?? tok); + const n = parseInt(text, 10); + // preserve exact digits when the value can't be represented as a safe JS integer + return Number.isSafeInteger(n) + ? { type: 'integer', value: n } + : { type: 'integer', value: n, valueText: text }; + } + function canonNumeric(text: string): string { + // canonical decimal form (equivalent literals -> same text), precision preserved + let t = text.trim(); + if (/[eE]/.test(t)) { + return t; // leave exponent forms as-is + } + let sign = ''; + if (t[0] === '+' || t[0] === '-') { sign = t[0] === '-' ? '-' : ''; t = t.slice(1); } + if (t.startsWith('.')) { t = '0' + t; } // .5 -> 0.5 + if (t.includes('.')) { + t = t.replace(/0+$/, ''); // 1.50 -> 1.5, 42.0 -> 42. + // keep the trailing '.' so it re-parses as numeric (not integer) + } + return (sign && parseFloat(t) !== 0 ? sign : '') + t; + } + function mkNumeric(tok: any) { + const text = String(tok?.value ?? tok); + const n = parseFloat(text); + // a fractional/exponent literal may not round-trip through a JS double, so keep + // the exact (canonical) source text for arbitrary-precision numeric consumers + return /[.eE]/.test(text) + ? { type: 'numeric', value: n, valueText: canonNumeric(text) } + : { type: 'numeric', value: n }; + } + function fromEntries(vals: [string, any][]): any { const ret = {} as any; for (const [k, v] of vals) { diff --git a/src/syntax/expr.ne b/src/syntax/expr.ne index a7a7ad6..3e96571 100644 --- a/src/syntax/expr.ne +++ b/src/syntax/expr.ne @@ -276,8 +276,8 @@ expr_extract -> (word {% kw('extract') %}) lparen word %kw_from expr rparen {% x }) %} expr_primary - -> float {% x => track(x, { type: 'numeric', value: unbox(x[0]) }) %} - | int {% x => track(x, { type: 'integer', value: unbox(x[0]) }) %} + -> %float {% x => track(x, mkNumeric(x[0])) %} + | %int {% x => track(x, mkInteger(x[0])) %} | string {% x => track(x, { type: 'string', value: unbox(x[0]) }) %} | %kw_true {% x => track(x, { type: 'boolean', value: true }) %} | %kw_false {% x => track(x, { type: 'boolean', value: false }) %} diff --git a/src/syntax/expr.spec.ts b/src/syntax/expr.spec.ts index 3807897..f9e28df 100644 --- a/src/syntax/expr.spec.ts +++ b/src/syntax/expr.spec.ts @@ -43,16 +43,19 @@ describe('Expressions', () => { checkTreeExpr(['0.5', '.5'], { type: 'numeric', value: 0.5, + valueText: '0.5', }); checkTreeExpr(['-0.5', '-.5'], { type: 'numeric', value: -0.5, + valueText: '-0.5', }); checkTreeExpr(['-42.', '-42.0'], { type: 'numeric', value: -42, + valueText: '-42.', }); checkInvalidExpr('42. 51'); @@ -393,11 +396,13 @@ line`, checkTreeExpr(['42.', '42.0'], { type: 'numeric', value: 42, + valueText: '42.', }); checkTreeExpr(['.42', '0.42'], { type: 'numeric', value: .42, + valueText: '0.42', }); checkTreeExpr(['42+51', '42 + 51'], { @@ -502,15 +507,18 @@ line`, left: { type: 'numeric', value: 2, + valueText: '2.', }, right: { type: 'numeric', value: 0.3, + valueText: '0.3', } }, right: { type: 'numeric', value: 4.5, + valueText: '4.5', }, }); diff --git a/src/syntax/spec-utils.ts b/src/syntax/spec-utils.ts index 4dc800a..f841b2b 100644 --- a/src/syntax/spec-utils.ts +++ b/src/syntax/spec-utils.ts @@ -329,5 +329,8 @@ export function tbl(nm: string): FromTable { }; } export function numeric(value: number): ExprNumeric { - return { type: 'numeric', value }; + // mirror the parser: fractional numeric literals carry their canonical text + return Number.isInteger(value) + ? { type: 'numeric', value } + : { type: 'numeric', value, valueText: String(value) }; } \ No newline at end of file diff --git a/src/to-sql.ts b/src/to-sql.ts index 64c99a7..def662a 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -603,9 +603,14 @@ const visitor = astVisitor(m => ({ ret.push(c.value ? 'true' : 'false'); break; case 'integer': - ret.push(c.value.toString(10)); + // prefer the exact source digits when the JS number would lose precision + ret.push(c.valueText ?? c.value.toString(10)); break; case 'numeric': + if (c.valueText) { + ret.push(c.valueText); + break; + } ret.push(c.value.toString()); if (Number.isInteger(c.value)) { ret.push('.'); From 1c9013c0e51618bf6204084885906d659accbe7c Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Thu, 9 Jul 2026 00:54:07 +0530 Subject: [PATCH 09/23] Parse CREATE TRIGGER CREATE [CONSTRAINT] TRIGGER name {BEFORE|AFTER|INSTEAD OF} {INSERT|UPDATE [OF cols]|DELETE|TRUNCATE [OR ...]} ON table [FOR EACH {ROW|STATEMENT}] [WHEN (cond)] EXECUTE {FUNCTION|PROCEDURE} f(args). New CreateTriggerStatement / TriggerEvent AST, emitted by toSql, specs. Co-Authored-By: Claude Fable 5 --- src/ast-mapper.ts | 9 ++++++ src/syntax/ast.ts | 22 +++++++++++++ src/syntax/base.ne | 7 +++++ src/syntax/create-trigger.ne | 42 +++++++++++++++++++++++++ src/syntax/create-trigger.spec.ts | 51 +++++++++++++++++++++++++++++++ src/syntax/main.ne | 2 ++ src/to-sql.ts | 14 +++++++++ 7 files changed, 147 insertions(+) create mode 100644 src/syntax/create-trigger.ne create mode 100644 src/syntax/create-trigger.spec.ts diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 377a3e1..027d8bf 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -90,6 +90,7 @@ export interface IAstPartialMapper { reset?(val: a.ResetStatement): a.Statement | nil createPolicy?(val: a.CreatePolicyStatement): a.Statement | nil dropPolicy?(val: a.DropPolicyStatement): a.Statement | nil + createTrigger?(val: a.CreateTriggerStatement): a.Statement | nil grant?(val: a.GrantStatement): a.Statement | nil revoke?(val: a.RevokeStatement): a.Statement | nil setGlobal?(val: a.SetGlobalStatement): a.Statement | nil @@ -274,6 +275,8 @@ export class AstDefaultMapper implements IAstMapper { return this.createPolicy(val); case 'drop policy': return this.dropPolicy(val); + case 'create trigger': + return this.createTrigger(val); case 'grant': return this.grant(val); case 'revoke': @@ -446,6 +449,12 @@ export class AstDefaultMapper implements IAstMapper { return val; } + createTrigger(val: a.CreateTriggerStatement): a.Statement | nil { + const when = this.expr(val.when); + const args = arrayNilMap(val.execute.arguments, a => this.expr(a)); + return assignChanged(val, { when, execute: assignChanged(val.execute, { arguments: args }) }); + } + grant(val: a.GrantStatement): a.Statement | nil { return val; } diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index da7b385..b31deb4 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -40,6 +40,7 @@ export type Statement = SelectStatement | ResetStatement | CreatePolicyStatement | DropPolicyStatement + | CreateTriggerStatement | GrantStatement | RevokeStatement | CreateEnumType @@ -1109,6 +1110,27 @@ export interface DropPolicyStatement extends PGNode { ifExists?: boolean; } +export interface TriggerEvent { + event: 'insert' | 'update' | 'delete' | 'truncate'; + /** only for UPDATE OF (col, ...) */ + columns?: Name[]; +} + +export interface CreateTriggerStatement extends PGNode { + type: 'create trigger'; + name: Name; + constraint?: boolean; + timing: 'before' | 'after' | 'instead of'; + events: TriggerEvent[]; + table: QName; + forEach: 'row' | 'statement'; + when?: Expr; + execute: { + function: QName; + arguments: Expr[]; + }; +} + export interface GrantOnTarget extends PGNode { type: 'table'; names: QName[]; diff --git a/src/syntax/base.ne b/src/syntax/base.ne index 12a78e9..1959105 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -202,6 +202,13 @@ kw_revoke -> %word {% notReservedKw('revoke') %} kw_privileges -> %word {% notReservedKw('privileges') %} kw_usage -> %word {% notReservedKw('usage') %} kw_execute -> %word {% notReservedKw('execute') %} +kw_before -> %word {% notReservedKw('before') %} +kw_after -> %word {% notReservedKw('after') %} +kw_instead -> %word {% notReservedKw('instead') %} +kw_of -> %word {% notReservedKw('of') %} +kw_each -> %word {% notReservedKw('each') %} +kw_statement -> %word {% notReservedKw('statement') %} +kw_procedure -> %word {% notReservedKw('procedure') %} kw_connect -> %word {% notReservedKw('connect') %} kw_deferred -> %word {% notReservedKw('deferred') %} kw_immediate -> %word {% notReservedKw('immediate') %} diff --git a/src/syntax/create-trigger.ne b/src/syntax/create-trigger.ne new file mode 100644 index 0000000..f2a9ced --- /dev/null +++ b/src/syntax/create-trigger.ne @@ -0,0 +1,42 @@ +@lexer lexerAny +@include "base.ne" +@include "expr.ne" + +# https://www.postgresql.org/docs/current/sql-createtrigger.html +createtrigger_statement -> %kw_create (%kw_constraint {% () => true %}):? kw_trigger ident + trigger_timing + trigger_events + %kw_on qualified_name + (%kw_for kw_each:? (kw_row | kw_statement) {% x => toStr(last(x)).toLowerCase() %}):? + (%kw_when lparen expr rparen {% x => x[2] %}):? + kw_execute (kw_function | kw_procedure) qualified_name lparen expr_list_raw:? rparen + {% x => track(x, { + type: 'create trigger', + ...(x[1] ? { constraint: true } : {}), + name: asName(x[3]), + timing: x[4], + events: x[5], + table: x[7], + forEach: x[8] ?? 'statement', + ...(x[9] ? { when: unwrap(x[9]) } : {}), + execute: { + function: x[12], + arguments: x[14] ?? [], + }, + }) %} + +trigger_timing + -> kw_before {% () => 'before' %} + | kw_after {% () => 'after' %} + | kw_instead kw_of {% () => 'instead of' %} + +trigger_events -> trigger_event (%kw_or trigger_event {% last %}):* {% ([head, tail]) => [head, ...(tail || [])] %} + +trigger_event + -> kw_insert {% x => track(x, { event: 'insert' }) %} + | kw_delete {% x => track(x, { event: 'delete' }) %} + | kw_truncate {% x => track(x, { event: 'truncate' }) %} + | kw_update (kw_of collist {% last %}):? {% x => track(x, { + event: 'update', + ...(x[1] ? { columns: x[1].map(asName) } : {}), + }) %} diff --git a/src/syntax/create-trigger.spec.ts b/src/syntax/create-trigger.spec.ts new file mode 100644 index 0000000..36a5d0d --- /dev/null +++ b/src/syntax/create-trigger.spec.ts @@ -0,0 +1,51 @@ +import 'mocha'; +import 'chai'; +import { checkStatement, ref } from './spec-utils'; + +describe('Create trigger', () => { + checkStatement([`create trigger t_touch before update on t for each row execute function touch()`], { + type: 'create trigger', + name: { name: 't_touch' }, + timing: 'before', + events: [{ event: 'update' }], + table: { name: 't' }, + forEach: 'row', + execute: { function: { name: 'touch' }, arguments: [] }, + }); + + checkStatement([`create trigger t2 after insert or delete on public.t for each statement execute procedure f()`], { + type: 'create trigger', + name: { name: 't2' }, + timing: 'after', + events: [{ event: 'insert' }, { event: 'delete' }], + table: { name: 't', schema: 'public' }, + forEach: 'statement', + execute: { function: { name: 'f' }, arguments: [] }, + }); + + checkStatement([`create trigger t3 before update of a, b on t for each row when (new.a > 0) execute function f()`], { + type: 'create trigger', + name: { name: 't3' }, + timing: 'before', + events: [{ event: 'update', columns: [{ name: 'a' }, { name: 'b' }] }], + table: { name: 't' }, + forEach: 'row', + when: { + type: 'binary', op: '>', + left: { type: 'ref', name: 'a', table: { name: 'new' } }, + right: { type: 'integer', value: 0 }, + }, + execute: { function: { name: 'f' }, arguments: [] }, + }); + + checkStatement([`create constraint trigger tc after insert on t for each row execute function f()`], { + type: 'create trigger', + name: { name: 'tc' }, + constraint: true, + timing: 'after', + events: [{ event: 'insert' }], + table: { name: 't' }, + forEach: 'row', + execute: { function: { name: 'f' }, arguments: [] }, + }); +}); diff --git a/src/syntax/main.ne b/src/syntax/main.ne index 3c78e21..652fc9c 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -13,6 +13,7 @@ import {lexerAny} from '../lexer'; @include "create-role.ne" @include "policy.ne" @include "grant.ne" +@include "create-trigger.ne" @include "simple-statements.ne" @include "insert.ne" @include "update.ne" @@ -56,6 +57,7 @@ statement_noprep | droppolicy_statement | grant_statement | revoke_statement + | createtrigger_statement | createindex_statement | simplestatements_all | insert_statement diff --git a/src/to-sql.ts b/src/to-sql.ts index def662a..8fde142 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1502,6 +1502,20 @@ const visitor = astVisitor(m => ({ } }, + createTrigger: t => { + ret.push('CREATE ', t.constraint ? 'CONSTRAINT ' : '', 'TRIGGER ', name(t.name), ' ', t.timing.toUpperCase(), ' '); + ret.push(t.events.map(e => e.event.toUpperCase() + (e.columns ? ' OF ' + e.columns.map(name).join(', ') : '')).join(' OR ')); + ret.push(' ON '); + visitQualifiedName(t.table); + ret.push(' FOR EACH ', t.forEach.toUpperCase()); + if (t.when) { ret.push(' WHEN ('); m.expr(t.when); ret.push(')'); } + ret.push(' EXECUTE FUNCTION '); + visitQualifiedName(t.execute.function); + ret.push('('); + list(t.execute.arguments, a => m.expr(a), false); + ret.push(')'); + }, + dropPolicy: p => { ret.push('DROP POLICY '); if (p.ifExists) { From a19ed490028543edfc0f5fa3dc804935e62982ef Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Thu, 9 Jul 2026 01:20:48 +0530 Subject: [PATCH 10/23] Support DROP TRIGGER ... ON table DROP TRIGGER in postgres requires the owning table: DROP TRIGGER [IF EXISTS] name ON table [CASCADE|RESTRICT] The generic drop rule modelled it like DROP TABLE (a bare name list), which rejected the ON clause. Add a dedicated DropTriggerStatement (name + onTable) with its own grammar rule, mapper and to-sql visitor, and drop 'drop trigger' from the generic DropStatement union. Companion to the CREATE TRIGGER support; needed by pg-mem's trigger execution engine (oguimbal/pg-mem). Co-Authored-By: Claude Opus 4.8 --- src/ast-mapper.ts | 8 +++++++- src/syntax/ast.ts | 11 ++++++++++- src/syntax/drop.ne | 10 +++++++++- src/syntax/drop.spec.ts | 13 +++++++++++-- src/syntax/main.ne | 1 + src/to-sql.ts | 12 ++++++++++++ 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 027d8bf..a467501 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -18,6 +18,7 @@ export interface IAstPartialMapper { alterEnum?(val: a.AlterEnumType): a.Statement | nil createCompositeType?(val: a.CreateCompositeType): a.Statement | nil drop?: (val: a.DropStatement) => a.Statement | nil + dropTrigger?: (val: a.DropTriggerStatement) => a.Statement | nil show?: (val: a.ShowStatement) => a.Statement | nil createTable?: (val: a.CreateTableStatement) => a.Statement | nil truncateTable?: (val: a.TruncateTableStatement) => a.Statement | nil @@ -291,9 +292,10 @@ export class AstDefaultMapper implements IAstMapper { case 'drop index': case 'drop sequence': case 'drop type': - case 'drop trigger': case 'drop role': return this.drop(val); + case 'drop trigger': + return this.dropTrigger(val); case 'create enum': return this.createEnum(val); case 'alter enum': @@ -483,6 +485,10 @@ export class AstDefaultMapper implements IAstMapper { return val; } + dropTrigger(val: a.DropTriggerStatement): a.Statement | nil { + return val; + } + alterSequence(seq: a.AlterSequenceStatement): a.Statement | nil { if (seq.change.type === 'set options') { if (seq.change.as) { diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index b31deb4..b881cf3 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -48,6 +48,7 @@ export type Statement = SelectStatement | AlterEnumType | TruncateTableStatement | DropStatement + | DropTriggerStatement | CommentStatement | CreateSchemaStatement | WithRecursiveStatement @@ -227,13 +228,21 @@ export interface TruncateTableStatement extends PGNode { } export interface DropStatement extends PGNode { - type: 'drop table' | 'drop sequence' | 'drop index' | 'drop type' | 'drop trigger' | 'drop role'; + type: 'drop table' | 'drop sequence' | 'drop index' | 'drop type' | 'drop role'; names: QName[]; ifExists?: boolean; cascade?: 'cascade' | 'restrict'; concurrently?: boolean; } +export interface DropTriggerStatement extends PGNode { + type: 'drop trigger'; + name: Name; + onTable: QName; + ifExists?: boolean; + cascade?: 'cascade' | 'restrict'; +} + export interface NodeLocation { /** Location of the last ";" prior to this statement */ start: number; diff --git a/src/syntax/drop.ne b/src/syntax/drop.ne index 63f95e8..da896dc 100644 --- a/src/syntax/drop.ne +++ b/src/syntax/drop.ne @@ -17,11 +17,19 @@ drop_statement -> kw_drop drop_what kw_ifexists:? array_of[qualified_name] (kw_c }); }%} +# https://www.postgresql.org/docs/current/sql-droptrigger.html +drop_trigger_statement -> kw_drop kw_trigger kw_ifexists:? ident %kw_on qualified_name (kw_cascade | kw_restrict):? {% (x: any) => track(x, { + type: 'drop trigger', + ...x[2] && { ifExists: true }, + name: asName(x[3]), + onTable: x[5], + ...x[6] && { cascade: toStr(x[6]) }, +}) %} + drop_what -> %kw_table {% x => track(x, { type: 'drop table' }) %} | kw_sequence {% x => track(x, { type: 'drop sequence' }) %} | kw_type {% x => track(x, { type: 'drop type' }) %} - | kw_trigger {% x => track(x, { type: 'drop trigger' }) %} | (kw_role | %kw_user) {% x => track(x, { type: 'drop role' }) %} | kw_index %kw_concurrently:? {% x => track(x, { type: 'drop index', diff --git a/src/syntax/drop.spec.ts b/src/syntax/drop.spec.ts index d2c7322..548f97c 100644 --- a/src/syntax/drop.spec.ts +++ b/src/syntax/drop.spec.ts @@ -62,9 +62,18 @@ describe('Drop', () => { names: [{ name: 'test' }], }); - checkStatement([`DROP TRIGGER test`], { + checkStatement([`DROP TRIGGER test ON my_table`], { type: 'drop trigger', - names: [{ name: 'test' }], + name: { name: 'test' }, + onTable: { name: 'my_table' }, + }); + + checkStatement([`DROP TRIGGER IF EXISTS test ON pub.my_table CASCADE`], { + type: 'drop trigger', + ifExists: true, + name: { name: 'test' }, + onTable: { name: 'my_table', schema: 'pub' }, + cascade: 'cascade', }); checkStatement([`drop index concurrently if exists test`], { diff --git a/src/syntax/main.ne b/src/syntax/main.ne index 652fc9c..15a0441 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -68,6 +68,7 @@ statement_noprep | create_sequence_statement | alter_sequence_statement | drop_statement + | drop_trigger_statement | createtype_statement | altertype_statement | create_view_statements diff --git a/src/to-sql.ts b/src/to-sql.ts index 8fde142..454978a 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1525,6 +1525,18 @@ const visitor = astVisitor(m => ({ visitQualifiedName(p.table); }, + dropTrigger: t => { + ret.push('DROP TRIGGER '); + if (t.ifExists) { + ret.push('IF EXISTS '); + } + ret.push(name(t.name), ' ON '); + visitQualifiedName(t.onTable); + if (t.cascade) { + ret.push(' ', t.cascade.toUpperCase()); + } + }, + grant: g => { ret.push('GRANT ', g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' ON '); list(g.on.names, n => visitQualifiedName(n), false); From c8da12c0373d7b943f88f903f12c2a579ec91122 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Thu, 9 Jul 2026 11:58:00 +0530 Subject: [PATCH 11/23] Add EXECUTE statement and CREATE TABLE ... TABLESPACE - EXECUTE [(args)] to run a PREPAREd statement (new ExecuteStatement node, grammar, mapper, to-sql). PREPARE and DEALLOCATE already parsed; EXECUTE was the missing piece. - optional TABLESPACE clause on CREATE TABLE (parsed into the existing `tablespace` shape; CREATE INDEX already supported it). Consumed by pg-mem's SQL-level PREPARE/EXECUTE and its tablespace no-op handling (oguimbal/pg-mem). Co-Authored-By: Claude Opus 4.8 --- src/ast-mapper.ts | 9 +++++++++ src/syntax/ast.ts | 8 ++++++++ src/syntax/create-table.ne | 6 +++++- src/syntax/create-table.spec.ts | 11 +++++++++++ src/syntax/execute.ne | 8 ++++++++ src/syntax/main.ne | 3 ++- src/syntax/prepare.spec.ts | 14 ++++++++++++++ src/to-sql.ts | 10 ++++++++++ 8 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/syntax/execute.ne diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index a467501..44e6273 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -27,6 +27,7 @@ export interface IAstPartialMapper { dataType?: (dataType: a.DataTypeDef) => a.DataTypeDef prepare?: (st: a.PrepareStatement) => a.Statement | nil deallocate?: (st: a.DeallocateStatement) => a.Statement | nil + execute?: (st: a.ExecuteStatement) => a.Statement | nil parameter?: (st: a.ExprParameter) => a.Expr | nil tableRef?: (st: a.QNameAliased) => a.QNameAliased | nil transaction?: (val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement | a.SavepointStatement | a.ReleaseSavepointStatement) => a.Statement | nil @@ -311,6 +312,8 @@ export class AstDefaultMapper implements IAstMapper { return this.prepare(val); case 'deallocate': return this.deallocate(val); + case 'execute': + return this.execute(val); case 'create view': return this.createView(val); case 'create materialized view': @@ -789,6 +792,12 @@ export class AstDefaultMapper implements IAstMapper { return st; } + execute(st: a.ExecuteStatement): a.Statement | nil { + return assignChanged(st, { + args: arrayNilMap(st.args, a => this.expr(a)), + }); + } + // ========================================= // ============== ALTER INDEX ============== // ========================================= diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index b881cf3..01d204d 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -20,6 +20,7 @@ export type Statement = SelectStatement | ShowStatement | PrepareStatement | DeallocateStatement + | ExecuteStatement | DeleteStatement | WithStatement | RollbackStatement @@ -167,6 +168,12 @@ export interface DeallocateStatement extends PGNode { target: Name | DeallocateStatementOpt; } +export interface ExecuteStatement extends PGNode { + type: 'execute'; + name: Name; + args?: Expr[]; +} + export interface DeallocateStatementOpt extends PGNode { option: 'all'; } @@ -540,6 +547,7 @@ export interface CreateTableStatement extends PGNode { /** Constraints not defined inline */ constraints?: TableConstraint[]; inherits?: QName[]; + tablespace?: Name; } export interface CreateColumnsLikeTable extends PGNode { diff --git a/src/syntax/create-table.ne b/src/syntax/create-table.ne index c6beec5..2ada8fb 100644 --- a/src/syntax/create-table.ne +++ b/src/syntax/create-table.ne @@ -16,6 +16,7 @@ createtable_statement -> %kw_create createtable_declarationlist rparen createtable_opts:? + createtable_tablespace:? {% x => { const cols = x[6].filter((v: any) => 'kind' in v); @@ -28,10 +29,13 @@ createtable_statement -> %kw_create columns: cols, ...unwrap(x[1]), ...constraints.length ? { constraints } : {}, - ...last(x), + ...x[8], + ...x[9] ? { tablespace: x[9] } : {}, }); } %} +createtable_tablespace -> kw_tablespace ident {% x => asName(last(x)) %} + createtable_modifiers -> kw_unlogged {% x => x[0] ? { unlogged: true } : {} %} diff --git a/src/syntax/create-table.spec.ts b/src/syntax/create-table.spec.ts index e564a64..2252f1b 100644 --- a/src/syntax/create-table.spec.ts +++ b/src/syntax/create-table.spec.ts @@ -26,6 +26,17 @@ describe('Create table', () => { }], }); + checkCreateTable(['create table test(value text) TABLESPACE fast'], { + type: 'create table', + name: { name: 'test' }, + columns: [{ + kind: 'column', + name: { name: 'value' }, + dataType: { name: 'text' }, + }], + tablespace: { name: 'fast' }, + }); + checkCreateTable(['create table test(value pg_catalog.text)'], { type: 'create table', name: { name: 'test', }, diff --git a/src/syntax/execute.ne b/src/syntax/execute.ne new file mode 100644 index 0000000..b70486a --- /dev/null +++ b/src/syntax/execute.ne @@ -0,0 +1,8 @@ +@lexer lexerAny + +# https://www.postgresql.org/docs/current/sql-execute.html +execute_statement -> kw_execute ident (lparen expr_list_raw rparen {% x => x[1] %}):? {% x => track(x, { + type: 'execute', + name: asName(x[1]), + ...x[2] && { args: x[2] }, + }) %} diff --git a/src/syntax/main.ne b/src/syntax/main.ne index 15a0441..c1cd231 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -28,6 +28,7 @@ import {lexerAny} from '../lexer'; @include "union.ne" @include "prepare.ne" @include "deallocate.ne" +@include "execute.ne" @include "create-view.ne" @include "refresh-materialized-view.ne" @include "functions.ne" @@ -46,7 +47,7 @@ main -> statement_separator:* statement (statement_separator:+ statement):* stat statement_separator -> %semicolon -statement -> statement_noprep | prepare | deallocate +statement -> statement_noprep | prepare | deallocate | execute_statement statement_noprep -> selection diff --git a/src/syntax/prepare.spec.ts b/src/syntax/prepare.spec.ts index b33b105..1dd2831 100644 --- a/src/syntax/prepare.spec.ts +++ b/src/syntax/prepare.spec.ts @@ -41,4 +41,18 @@ describe('Prepare', () => { columns: [{ expr: { type: 'ref', name: 'c' } }], }, }); + + checkStatement(`execute st`, { + type: 'execute', + name: { name: 'st' }, + }); + + checkStatement(`execute st(1, 'foo')`, { + type: 'execute', + name: { name: 'st' }, + args: [ + { type: 'integer', value: 1 }, + { type: 'string', value: 'foo' }, + ], + }); }); diff --git a/src/to-sql.ts b/src/to-sql.ts index 454978a..46c5652 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1041,6 +1041,9 @@ const visitor = astVisitor(m => ({ ret.push(' INHERITS '); list(t.inherits, i => visitQualifiedName(i), true); } + if (t.tablespace) { + ret.push(' TABLESPACE ', name(t.tablespace)); + } }, likeTable: l => { @@ -1576,6 +1579,13 @@ const visitor = astVisitor(m => ({ ret.push('ALL') }, + execute: s => { + ret.push('EXECUTE ', name(s.name)); + if (s.args?.length) { + list(s.args, a => m.expr(a), true); + } + }, + arraySelect: s => { ret.push('array('); m.select(s.select); From a7d07d297842953d3b6fb35f70546fe58e22460f Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Thu, 9 Jul 2026 12:32:41 +0530 Subject: [PATCH 12/23] Add CREATE DOMAIN CREATE DOMAIN name [AS] type [COLLATE c] [DEFAULT expr] [ [CONSTRAINT n] { NOT NULL | NULL | CHECK (expr) } ]* New CreateDomainStatement / DomainConstraint AST, grammar, mapper and to-sql. Consumed by pg-mem's domain type (oguimbal/pg-mem). Co-Authored-By: Claude Opus 4.8 --- src/ast-mapper.ts | 11 +++++++++++ src/syntax/ast.ts | 29 +++++++++++++++++++++++++++++ src/syntax/base.ne | 1 + src/syntax/create-domain.ne | 30 ++++++++++++++++++++++++++++++ src/syntax/create-type.spec.ts | 23 +++++++++++++++++++++++ src/syntax/main.ne | 2 ++ src/to-sql.ts | 32 ++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+) create mode 100644 src/syntax/create-domain.ne diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 44e6273..86ca497 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -17,6 +17,7 @@ export interface IAstPartialMapper { createEnum?(val: a.CreateEnumType): a.Statement | nil alterEnum?(val: a.AlterEnumType): a.Statement | nil createCompositeType?(val: a.CreateCompositeType): a.Statement | nil + createDomain?(val: a.CreateDomainStatement): a.Statement | nil drop?: (val: a.DropStatement) => a.Statement | nil dropTrigger?: (val: a.DropTriggerStatement) => a.Statement | nil show?: (val: a.ShowStatement) => a.Statement | nil @@ -303,6 +304,8 @@ export class AstDefaultMapper implements IAstMapper { return this.alterEnum(val); case 'create composite type': return this.createCompositeType(val); + case 'create domain': + return this.createDomain(val); case 'union': case 'union all': return this.union(val); @@ -483,6 +486,14 @@ export class AstDefaultMapper implements IAstMapper { return assignChanged(val, { attributes }); } + createDomain(val: a.CreateDomainStatement): a.Statement | nil { + const dataType = this.dataType(val.dataType); + const def = val.default && this.expr(val.default); + const constraints = arrayNilMap(val.constraints, c => + c.type === 'check' ? assignChanged(c, { expr: this.expr(c.expr) }) : c); + return assignChanged(val, { dataType, default: def, constraints }); + } + drop(val: a.DropStatement): a.Statement | nil { return val; diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 01d204d..7394d4f 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -46,6 +46,7 @@ export type Statement = SelectStatement | RevokeStatement | CreateEnumType | CreateCompositeType + | CreateDomainStatement | AlterEnumType | TruncateTableStatement | DropStatement @@ -190,6 +191,34 @@ export interface CreateCompositeType extends PGNode { attributes: CompositeTypeAttribute[]; } +export interface CreateDomainStatement extends PGNode { + type: 'create domain'; + name: QName; + dataType: DataTypeDef; + collate?: Name; + constraints?: DomainConstraint[]; + default?: Expr; +} + +export type DomainConstraint + = DomainConstraintNotNull + | DomainConstraintNull + | DomainConstraintCheck; + +export interface DomainConstraintNotNull extends PGNode { + type: 'not null'; + constraintName?: Name; +} +export interface DomainConstraintNull extends PGNode { + type: 'null'; + constraintName?: Name; +} +export interface DomainConstraintCheck extends PGNode { + type: 'check'; + constraintName?: Name; + expr: Expr; +} + export interface AlterEnumType extends PGNode { type: 'alter enum', name: QName, diff --git a/src/syntax/base.ne b/src/syntax/base.ne index 1959105..9f16cfe 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -238,6 +238,7 @@ kw_minvalue -> %word {% notReservedKw('minvalue') %} kw_maxvalue -> %word {% notReservedKw('maxvalue') %} kw_data -> %word {% notReservedKw('data') %} kw_type -> %word {% notReservedKw('type') %} +kw_domain -> %word {% notReservedKw('domain') %} kw_trigger -> %word {% notReservedKw('trigger') %} kw_delete -> %word {% notReservedKw('delete') %} kw_cache -> %word {% notReservedKw('cache') %} diff --git a/src/syntax/create-domain.ne b/src/syntax/create-domain.ne new file mode 100644 index 0000000..fa6b3a2 --- /dev/null +++ b/src/syntax/create-domain.ne @@ -0,0 +1,30 @@ +@lexer lexerAny + +# https://www.postgresql.org/docs/current/sql-createdomain.html +createdomain_statement -> %kw_create kw_domain qualified_name %kw_as:? data_type + createtable_collate:? + domain_item:* + {% x => { + const items = x[6] || []; + const constraints = items.filter((i: any) => i.type !== 'default'); + const def = items.find((i: any) => i.type === 'default'); + return track(x, { + type: 'create domain', + name: x[2], + dataType: x[4], + ...(x[5] ? { collate: x[5][1] } : {}), + ...(constraints.length ? { constraints } : {}), + ...(def ? { default: def.default } : {}), + }); + } %} + +domain_item -> (%kw_constraint word {% x => asName(x[1]) %}):? domain_item_def {% x => track(x, { + ...(x[0] ? { constraintName: x[0] } : {}), + ...unwrap(x[1]), + }) %} + +domain_item_def + -> kw_not_null {% () => ({ type: 'not null' }) %} + | %kw_null {% () => ({ type: 'null' }) %} + | %kw_check expr_paren {% x => ({ type: 'check', expr: unwrap(x[1]) }) %} + | %kw_default expr {% x => ({ type: 'default', default: unwrap(x[1]) }) %} diff --git a/src/syntax/create-type.spec.ts b/src/syntax/create-type.spec.ts index 4777fa2..76bc412 100644 --- a/src/syntax/create-type.spec.ts +++ b/src/syntax/create-type.spec.ts @@ -29,4 +29,27 @@ describe('Create types', () => { }, ], }); + + checkStatement([`create domain posint as int check (value > 0)`], { + type: 'create domain', + name: { name: 'posint' }, + dataType: { name: 'int' }, + constraints: [{ + type: 'check', + expr: { + type: 'binary', + op: '>', + left: { type: 'ref', name: 'value' }, + right: { type: 'integer', value: 0 }, + }, + }], + }); + + checkStatement([`create domain us_postal as text not null default '00000'`], { + type: 'create domain', + name: { name: 'us_postal' }, + dataType: { name: 'text' }, + constraints: [{ type: 'not null' }], + default: { type: 'string', value: '00000' }, + }); }); diff --git a/src/syntax/main.ne b/src/syntax/main.ne index c1cd231..5544a0d 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -24,6 +24,7 @@ import {lexerAny} from '../lexer'; @include "drop.ne" @include "with.ne" @include "create-type.ne" +@include "create-domain.ne" @include "alter-type.ne" @include "union.ne" @include "prepare.ne" @@ -71,6 +72,7 @@ statement_noprep | drop_statement | drop_trigger_statement | createtype_statement + | createdomain_statement | altertype_statement | create_view_statements | refresh_view_statements diff --git a/src/to-sql.ts b/src/to-sql.ts index 46c5652..423bbe2 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -358,6 +358,38 @@ const visitor = astVisitor(m => ({ ret.push(' '); }, + createDomain: c => { + ret.push('CREATE DOMAIN '); + visitQualifiedName(c.name); + ret.push(' AS '); + m.dataType(c.dataType); + if (c.collate) { + ret.push(' COLLATE ', name(c.collate)); + } + if (c.default) { + ret.push(' DEFAULT '); + m.expr(c.default); + } + for (const cst of c.constraints ?? []) { + if (cst.constraintName) { + ret.push(' CONSTRAINT ', name(cst.constraintName)); + } + switch (cst.type) { + case 'not null': + ret.push(' NOT NULL'); + break; + case 'null': + ret.push(' NULL'); + break; + case 'check': + ret.push(' CHECK ('); + m.expr(cst.expr); + ret.push(')'); + break; + } + } + }, + setTableOwner: o => { ret.push(' OWNER TO ', name(o.to)); }, From b373fdf60071c9f51c1d8b3cdf9ad23773ca3a1f Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Thu, 9 Jul 2026 14:39:14 +0530 Subject: [PATCH 13/23] Support RETURNS SETOF CREATE FUNCTION ... RETURNS SETOF now parses (a set-returning function). Adds a `setof` flag on CreateFunctionStatement + to-sql; the element type is carried in `returns`. Consumed by pg-mem's plpgsql set-returning functions (oguimbal/pg-mem). Co-Authored-By: Claude Opus 4.8 --- src/syntax/ast.ts | 2 ++ src/syntax/base.ne | 1 + src/syntax/functions.ne | 8 +++++++- src/syntax/functions.spec.ts | 10 ++++++++++ src/to-sql.ts | 2 +- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 7394d4f..f7694a2 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -91,6 +91,8 @@ export interface CreateFunctionStatement extends PGNode { language?: Name; arguments: FunctionArgument[]; returns?: DataTypeDef | ReturnsTable; + /** RETURNS SETOF : the function returns a set of `returns` */ + setof?: boolean; purity?: 'immutable' | 'stable' | 'volatile'; leakproof?: boolean; onNullInput?: 'call' | 'null' | 'strict'; diff --git a/src/syntax/base.ne b/src/syntax/base.ne index 9f16cfe..f846dbd 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -248,6 +248,7 @@ kw_timestamp -> %word {% notReservedKw('timestamp') %} kw_cycle -> %word {% notReservedKw('cycle') %} kw_function -> %word {% notReservedKw('function') %} kw_returns -> %word {% notReservedKw('returns') %} +kw_setof -> %word {% notReservedKw('setof') %} kw_language -> %word {% notReservedKw('language') %} kw_out -> %word {% notReservedKw('out') %} kw_inout -> %word {% notReservedKw('inout') %} diff --git a/src/syntax/functions.ne b/src/syntax/functions.ne index da92d39..bc131e5 100644 --- a/src/syntax/functions.ne +++ b/src/syntax/functions.ne @@ -66,7 +66,12 @@ func_spec -> kw_language word {% x => track(x, { language: asName(last(x)) }) %} | func_purity {% x => track(x, {purity: toStr(x)}) %} | %kw_as (%codeblock | string) {% x =>({code: toStr(last(x))}) %} | %kw_not:? (word {% kw('leakproof') %}) {% x => track(x, { leakproof: !x[0] })%} - | func_returns {% x => track(x, { returns: unwrap(x) }) %} + | func_returns {% x => { + const r = unwrap(x); + return r && r.__setof + ? track(x, { returns: r.__setof, setof: true }) + : track(x, { returns: r }); + } %} | (word {%kw('called')%}) oninp {% () => ({ onNullInput: 'call' }) %} | (word {%kw('returns')%}) %kw_null oninp {% () => ({ onNullInput: 'null' }) %} | (word {%kw('strict')%}) {% () => ({ onNullInput: 'strict' }) %} @@ -78,6 +83,7 @@ func_purity -> word {%kw('immutable')%} oninp -> %kw_on %kw_null (word {%kw('input')%}) func_returns -> kw_returns data_type {% last %} + | kw_returns kw_setof data_type {% x => ({ __setof: last(x) }) %} | kw_returns %kw_table lparen array_of[func_ret_table_col] rparen {% x => track(x, { kind: 'table', columns: x[3], diff --git a/src/syntax/functions.spec.ts b/src/syntax/functions.spec.ts index 4f7f032..0922fa5 100644 --- a/src/syntax/functions.spec.ts +++ b/src/syntax/functions.spec.ts @@ -26,6 +26,16 @@ describe('Create function', () => { returns: integer, }); + checkStatement(`CREATE FUNCTION gen() RETURNS SETOF integer AS 'x' LANGUAGE plpgsql`, { + type: 'create function', + name: { name: 'gen' }, + arguments: [], + code: 'x', + language: { name: 'plpgsql' }, + returns: integer, + setof: true, + }); + // modifiers BEFORE code block checkStatement(`CREATE FUNCTION add(integer, integer) RETURNS integer stable LANGUAGE SQL RETURNS NULL ON NULL INPUT diff --git a/src/to-sql.ts b/src/to-sql.ts index 423bbe2..176d4dc 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -814,7 +814,7 @@ const visitor = astVisitor(m => ({ case undefined: case null: case 'array': - ret.push(' RETURNS '); + ret.push(c.setof ? ' RETURNS SETOF ' : ' RETURNS '); m.dataType(c.returns); break; default: From 6085f2219fd9b5956e202fe25288d28cd8cfffe3 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 02:09:36 +0530 Subject: [PATCH 14/23] Support composite-type field access: (expr).field Adds a `.` member operator so a parenthesized expression can have a field read off it, e.g. `(center).x` or `(row(1,2)).f1`. This is the standard PostgreSQL syntax for accessing a field of a composite/row value. - expr.ne: new `expr_paren %dot word` production in expr_member - ast.ts: ExprMember.op widened to include '.' - to-sql.ts: member visitor emits `(operand).field` for op '.' 799 parser tests pass; no grammar ambiguity introduced. Co-Authored-By: Claude Opus 4.8 --- src/syntax/ast.ts | 2 +- src/syntax/expr.ne | 6 ++++++ src/to-sql.ts | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index f7694a2..dfb90ea 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -974,7 +974,7 @@ export interface ExprParameter extends PGNode { export interface ExprMember extends PGNode { type: 'member'; operand: Expr; - op: '->' | '->>'; + op: '->' | '->>' | '.'; // '.' is composite-type field access: (expr).field member: string | number; } diff --git a/src/syntax/expr.ne b/src/syntax/expr.ne index 3e96571..e445324 100644 --- a/src/syntax/expr.ne +++ b/src/syntax/expr.ne @@ -118,6 +118,12 @@ expr_member operand: unwrap(x[0]), to: x[2], }) %} + | expr_paren %dot word {% x => track(x, { + type: 'member', + operand: unwrap(x[0]), + op: '.', + member: toStr(x[2]), + }) %} | %kw_cast lparen expr_nostar %kw_as data_type rparen {% x => track(x, { type: 'cast', operand: unwrap(x[2]), diff --git a/src/to-sql.ts b/src/to-sql.ts index 176d4dc..bb45df6 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1313,6 +1313,13 @@ const visitor = astVisitor(m => ({ }, member: e => { + if (e.op === '.') { + // composite field access: (operand).field + ret.push('('); + m.expr(e.operand); + ret.push(').', ident(e.member as string)); + return; + } m.expr(e.operand); ret.push(e.op); ret.push(typeof e.member === 'number' From 392db18cbdb6dbe5fd3ae9c40d2f5f916238a879 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 02:09:49 +0530 Subject: [PATCH 15/23] Build deno [autogenerated commit] --- .deno/ast-mapper.ts | 112 ++++++++- .deno/lexer.ts | 2 +- .deno/syntax/ast.ts | 202 ++++++++++++++- .deno/syntax/main.ne.ts | 543 ++++++++++++++++++++++++++++++++++++++-- .deno/to-sql.ts | 218 +++++++++++++++- 5 files changed, 1037 insertions(+), 40 deletions(-) diff --git a/.deno/ast-mapper.ts b/.deno/ast-mapper.ts index 2498086..26a3e80 100644 --- a/.deno/ast-mapper.ts +++ b/.deno/ast-mapper.ts @@ -17,7 +17,9 @@ export interface IAstPartialMapper { createEnum?(val: a.CreateEnumType): a.Statement | nil alterEnum?(val: a.AlterEnumType): a.Statement | nil createCompositeType?(val: a.CreateCompositeType): a.Statement | nil + createDomain?(val: a.CreateDomainStatement): a.Statement | nil drop?: (val: a.DropStatement) => a.Statement | nil + dropTrigger?: (val: a.DropTriggerStatement) => a.Statement | nil show?: (val: a.ShowStatement) => a.Statement | nil createTable?: (val: a.CreateTableStatement) => a.Statement | nil truncateTable?: (val: a.TruncateTableStatement) => a.Statement | nil @@ -26,9 +28,10 @@ export interface IAstPartialMapper { dataType?: (dataType: a.DataTypeDef) => a.DataTypeDef prepare?: (st: a.PrepareStatement) => a.Statement | nil deallocate?: (st: a.DeallocateStatement) => a.Statement | nil + execute?: (st: a.ExecuteStatement) => a.Statement | nil parameter?: (st: a.ExprParameter) => a.Expr | nil tableRef?: (st: a.QNameAliased) => a.QNameAliased | nil - transaction?: (val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement) => a.Statement | nil + transaction?: (val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement | a.SavepointStatement | a.ReleaseSavepointStatement) => a.Statement | nil createIndex?: (val: a.CreateIndexStatement) => a.Statement | nil alterTable?: (st: a.AlterTableStatement) => a.Statement | nil alterIndex?: (st: a.AlterIndexStatement) => a.Statement | nil @@ -37,6 +40,7 @@ export interface IAstPartialMapper { dropConstraint?: (change: a.TableAlterationDropConstraint, table: a.QNameAliased) => a.TableAlteration | nil renameConstraint?: (change: a.TableAlterationRenameConstraint, table: a.QNameAliased) => a.TableAlteration | nil setTableOwner?: (change: a.TableAlterationOwner, table: a.QNameAliased) => a.TableAlteration | nil + setRowLevelSecurity?: (change: a.TableAlterationRowLevelSecurity, table: a.QNameAliased) => a.TableAlteration | nil renameColumn?: (change: a.TableAlterationRenameColumn, table: a.QNameAliased) => a.TableAlteration | nil renameTable?: (change: a.TableAlterationRename, table: a.QNameAliased) => a.TableAlteration | nil alterColumn?: (change: a.TableAlterationAlterColumn, inTable: a.QNameAliased) => a.TableAlteration | nil @@ -72,6 +76,7 @@ export interface IAstPartialMapper { cast?: (val: a.ExprCast) => a.Expr | nil call?: (val: a.ExprCall) => a.Expr | nil callSubstring?: (val: a.ExprSubstring) => a.Expr | nil + callPosition?: (val: a.ExprPosition) => a.Expr | nil callOverlay?: (val: a.ExprOverlay) => a.Expr | nil array?: (val: a.ExprList) => a.Expr | nil constant?: (value: a.ExprLiteral) => a.Expr | nil @@ -83,6 +88,14 @@ export interface IAstPartialMapper { constraint?: (constraint: a.ColumnConstraint) => a.ColumnConstraint | nil valueKeyword?(val: a.ExprValueKeyword): a.Expr | nil tablespace?(val: a.TablespaceStatement): a.Statement | nil + createRole?(val: a.CreateRoleStatement): a.Statement | nil + setRole?(val: a.SetRoleStatement): a.Statement | nil + reset?(val: a.ResetStatement): a.Statement | nil + createPolicy?(val: a.CreatePolicyStatement): a.Statement | nil + dropPolicy?(val: a.DropPolicyStatement): a.Statement | nil + createTrigger?(val: a.CreateTriggerStatement): a.Statement | nil + grant?(val: a.GrantStatement): a.Statement | nil + revoke?(val: a.RevokeStatement): a.Statement | nil setGlobal?(val: a.SetGlobalStatement): a.Statement | nil setTimezone?(val: a.SetTimezone): a.Statement | nil setNames?(val: a.SetNames): a.Statement | nil @@ -224,6 +237,8 @@ export class AstDefaultMapper implements IAstMapper { case 'commit': case 'start transaction': case 'rollback': + case 'savepoint': + case 'release savepoint': return this.transaction(val); case 'create index': return this.createIndex(val); @@ -253,6 +268,22 @@ export class AstDefaultMapper implements IAstMapper { return this.setTimezone(val); case 'set names': return this.setNames(val); + case 'create role': + return this.createRole(val); + case 'set role': + return this.setRole(val); + case 'reset': + return this.reset(val); + case 'create policy': + return this.createPolicy(val); + case 'drop policy': + return this.dropPolicy(val); + case 'create trigger': + return this.createTrigger(val); + case 'grant': + return this.grant(val); + case 'revoke': + return this.revoke(val); case 'create sequence': return this.createSequence(val); case 'alter sequence': @@ -263,14 +294,18 @@ export class AstDefaultMapper implements IAstMapper { case 'drop index': case 'drop sequence': case 'drop type': - case 'drop trigger': + case 'drop role': return this.drop(val); + case 'drop trigger': + return this.dropTrigger(val); case 'create enum': return this.createEnum(val); case 'alter enum': return this.alterEnum(val); case 'create composite type': return this.createCompositeType(val); + case 'create domain': + return this.createDomain(val); case 'union': case 'union all': return this.union(val); @@ -280,6 +315,8 @@ export class AstDefaultMapper implements IAstMapper { return this.prepare(val); case 'deallocate': return this.deallocate(val); + case 'execute': + return this.execute(val); case 'create view': return this.createView(val); case 'create materialized view': @@ -398,6 +435,42 @@ export class AstDefaultMapper implements IAstMapper { return val; } + createRole(val: a.CreateRoleStatement): a.Statement | nil { + return val; + } + + setRole(val: a.SetRoleStatement): a.Statement | nil { + return val; + } + + reset(val: a.ResetStatement): a.Statement | nil { + return val; + } + + createPolicy(val: a.CreatePolicyStatement): a.Statement | nil { + const using = this.expr(val.using); + const withCheck = this.expr(val.withCheck); + return assignChanged(val, { using, withCheck }); + } + + dropPolicy(val: a.DropPolicyStatement): a.Statement | nil { + return val; + } + + createTrigger(val: a.CreateTriggerStatement): a.Statement | nil { + const when = this.expr(val.when); + const args = arrayNilMap(val.execute.arguments, a => this.expr(a)); + return assignChanged(val, { when, execute: assignChanged(val.execute, { arguments: args }) }); + } + + grant(val: a.GrantStatement): a.Statement | nil { + return val; + } + + revoke(val: a.RevokeStatement): a.Statement | nil { + return val; + } + createEnum(val: a.CreateEnumType): a.Statement | nil { return val; } @@ -413,11 +486,23 @@ export class AstDefaultMapper implements IAstMapper { return assignChanged(val, { attributes }); } + createDomain(val: a.CreateDomainStatement): a.Statement | nil { + const dataType = this.dataType(val.dataType); + const def = val.default && this.expr(val.default); + const constraints = arrayNilMap(val.constraints, c => + c.type === 'check' ? assignChanged(c, { expr: this.expr(c.expr) }) : c); + return assignChanged(val, { dataType, default: def, constraints }); + } + drop(val: a.DropStatement): a.Statement | nil { return val; } + dropTrigger(val: a.DropTriggerStatement): a.Statement | nil { + return val; + } + alterSequence(seq: a.AlterSequenceStatement): a.Statement | nil { if (seq.change.type === 'set options') { if (seq.change.as) { @@ -673,7 +758,7 @@ export class AstDefaultMapper implements IAstMapper { return st; } - transaction(val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement): a.Statement | nil { + transaction(val: a.CommitStatement | a.RollbackStatement | a.StartTransactionStatement | a.SavepointStatement | a.ReleaseSavepointStatement): a.Statement | nil { return val; } @@ -718,6 +803,12 @@ export class AstDefaultMapper implements IAstMapper { return st; } + execute(st: a.ExecuteStatement): a.Statement | nil { + return assignChanged(st, { + args: arrayNilMap(st.args, a => this.expr(a)), + }); + } + // ========================================= // ============== ALTER INDEX ============== // ========================================= @@ -784,6 +875,8 @@ export class AstDefaultMapper implements IAstMapper { return this.dropConstraint(change, table); case 'owner': return this.setTableOwner(change, table); + case 'row level security': + return this.setRowLevelSecurity(change, table); default: throw NotSupported.never(change); } @@ -801,6 +894,10 @@ export class AstDefaultMapper implements IAstMapper { return change; } + setRowLevelSecurity(change: a.TableAlterationRowLevelSecurity, table: a.QNameAliased): a.TableAlteration | nil { + return change; + } + renameConstraint(change: a.TableAlterationRenameConstraint, table: a.QNameAliased): a.TableAlteration | nil { return change; } @@ -1144,6 +1241,8 @@ export class AstDefaultMapper implements IAstMapper { return this.callOverlay(val); case 'substring': return this.callSubstring(val); + case 'position': + return this.callPosition(val); case 'values': return this.values(val); case 'default': @@ -1273,6 +1372,13 @@ export class AstDefaultMapper implements IAstMapper { for: this.expr(val.for), }) } + + callPosition(val: a.ExprPosition): a.Expr | nil { + return assignChanged(val, { + substring: this.expr(val.substring), + string: this.expr(val.string), + }) + } callOverlay(val: a.ExprOverlay): a.Expr | nil { return assignChanged(val, { value: this.expr(val.value), diff --git a/.deno/lexer.ts b/.deno/lexer.ts index 5a1e71e..c67727e 100644 --- a/.deno/lexer.ts +++ b/.deno/lexer.ts @@ -84,7 +84,7 @@ export const lexer = compile({ op_compare: { // group other comparison operators // ... to add: "IN" and "NOT IN" that are matched by keywords - match: ['>', '>=', '<', '<=', '@>', '<@', '?', '?|', '?&', '#>>', '>>', '<<', '~', '~*', '!~', '!~*', '@@'], + match: ['>', '>=', '<', '<=', '@>', '<@', '?', '?|', '?&', '#>>', '#>', '>>', '<<', '~', '~*', '!~', '!~*', '@@'], }, ops_others: { // referenced as (any other operator) in https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-PRECEDENCE diff --git a/.deno/syntax/ast.ts b/.deno/syntax/ast.ts index 488bc3c..1ad3ca3 100644 --- a/.deno/syntax/ast.ts +++ b/.deno/syntax/ast.ts @@ -20,9 +20,12 @@ export type Statement = SelectStatement | ShowStatement | PrepareStatement | DeallocateStatement + | ExecuteStatement | DeleteStatement | WithStatement | RollbackStatement + | SavepointStatement + | ReleaseSavepointStatement | TablespaceStatement | CreateViewStatement | CreateMaterializedViewStatement @@ -33,11 +36,21 @@ export type Statement = SelectStatement | SetGlobalStatement | SetTimezone | SetNames + | CreateRoleStatement + | SetRoleStatement + | ResetStatement + | CreatePolicyStatement + | DropPolicyStatement + | CreateTriggerStatement + | GrantStatement + | RevokeStatement | CreateEnumType | CreateCompositeType + | CreateDomainStatement | AlterEnumType | TruncateTableStatement | DropStatement + | DropTriggerStatement | CommentStatement | CreateSchemaStatement | WithRecursiveStatement @@ -78,6 +91,8 @@ export interface CreateFunctionStatement extends PGNode { language?: Name; arguments: FunctionArgument[]; returns?: DataTypeDef | ReturnsTable; + /** RETURNS SETOF : the function returns a set of `returns` */ + setof?: boolean; purity?: 'immutable' | 'stable' | 'volatile'; leakproof?: boolean; onNullInput?: 'call' | 'null' | 'strict'; @@ -156,6 +171,12 @@ export interface DeallocateStatement extends PGNode { target: Name | DeallocateStatementOpt; } +export interface ExecuteStatement extends PGNode { + type: 'execute'; + name: Name; + args?: Expr[]; +} + export interface DeallocateStatementOpt extends PGNode { option: 'all'; } @@ -172,6 +193,34 @@ export interface CreateCompositeType extends PGNode { attributes: CompositeTypeAttribute[]; } +export interface CreateDomainStatement extends PGNode { + type: 'create domain'; + name: QName; + dataType: DataTypeDef; + collate?: Name; + constraints?: DomainConstraint[]; + default?: Expr; +} + +export type DomainConstraint + = DomainConstraintNotNull + | DomainConstraintNull + | DomainConstraintCheck; + +export interface DomainConstraintNotNull extends PGNode { + type: 'not null'; + constraintName?: Name; +} +export interface DomainConstraintNull extends PGNode { + type: 'null'; + constraintName?: Name; +} +export interface DomainConstraintCheck extends PGNode { + type: 'check'; + constraintName?: Name; + expr: Expr; +} + export interface AlterEnumType extends PGNode { type: 'alter enum', name: QName, @@ -217,13 +266,21 @@ export interface TruncateTableStatement extends PGNode { } export interface DropStatement extends PGNode { - type: 'drop table' | 'drop sequence' | 'drop index' | 'drop type' | 'drop trigger'; + type: 'drop table' | 'drop sequence' | 'drop index' | 'drop type' | 'drop role'; names: QName[]; ifExists?: boolean; cascade?: 'cascade' | 'restrict'; concurrently?: boolean; } +export interface DropTriggerStatement extends PGNode { + type: 'drop trigger'; + name: Name; + onTable: QName; + ifExists?: boolean; + cascade?: 'cascade' | 'restrict'; +} + export interface NodeLocation { /** Location of the last ";" prior to this statement */ start: number; @@ -239,6 +296,18 @@ export interface CommitStatement extends PGNode { } export interface RollbackStatement extends PGNode { type: 'rollback'; + /** rollback to a savepoint */ + to?: Name | nil; +} + +export interface SavepointStatement extends PGNode { + type: 'savepoint'; + name: Name; +} + +export interface ReleaseSavepointStatement extends PGNode { + type: 'release savepoint'; + name: Name; } export interface TablespaceStatement extends PGNode { @@ -366,6 +435,7 @@ export type TableAlteration = TableAlterationRename | TableAlterationAddConstraint | TableAlterationOwner | TableAlterationDropConstraint + | TableAlterationRowLevelSecurity export interface TableAlterationOwner extends PGNode { @@ -373,6 +443,11 @@ export interface TableAlterationOwner extends PGNode { to: Name; } +export interface TableAlterationRowLevelSecurity extends PGNode { + type: 'row level security'; + action: 'enable' | 'disable' | 'force' | 'no force'; +} + export interface AlterColumnSetType extends PGNode { type: 'set type'; dataType: DataTypeDef; @@ -503,6 +578,7 @@ export interface CreateTableStatement extends PGNode { /** Constraints not defined inline */ constraints?: TableConstraint[]; inherits?: QName[]; + tablespace?: Name; } export interface CreateColumnsLikeTable extends PGNode { @@ -594,6 +670,8 @@ export interface TableReference { onDelete?: ConstraintAction; onUpdate?: ConstraintAction; match?: 'full' | 'partial' | 'simple'; + deferrable?: boolean; + initiallyDeferred?: boolean; } @@ -640,7 +718,8 @@ export interface WithStatement extends PGNode { export interface WithRecursiveStatement extends PGNode { type: 'with recursive'; alias: Name; - columnNames: Name[]; + /** column names are optional (inferred from the seed query when absent) */ + columnNames?: Name[] | nil; bind: SelectFromUnion; in: WithStatementBinding; } @@ -792,7 +871,8 @@ export type Expr = ExprRef | ExprConstant | ExprTernary | ExprOverlay - | ExprSubstring; + | ExprSubstring + | ExprPosition; /** @@ -815,12 +895,19 @@ export interface ExprSubstring extends PGNode { for?: Expr | nil; } +/** Handle special syntax: position('om' in 'Thomas') */ +export interface ExprPosition extends PGNode { + type: 'position'; + substring: Expr; + string: Expr; +} + // === https://www.postgresql.org/docs/12/functions.html export type LogicOperator = 'OR' | 'AND'; export type EqualityOperator = 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE' | '=' | '!='; // see https://www.postgresql.org/docs/12/functions-math.html export type MathOpsBinary = '|' | '&' | '>>' | '^' | '#' | '<<' | '>>'; -export type ComparisonOperator = '>' | '>=' | '<' | '<=' | '@>' | '<@' | '?' | '?|' | '?&' | '#>>' | '~' | '~*' | '!~' | '!~*' | '@@'; +export type ComparisonOperator = '>' | '>=' | '<' | '<=' | '@>' | '<@' | '?' | '?|' | '?&' | '#>' | '#>>' | '~' | '~*' | '!~' | '!~*' | '@@'; export type AdditiveOperator = '||' | '-' | '#-' | '&&' | '+'; export type MultiplicativeOperator = '*' | '%' | '/'; export type ConstructOperator = 'AT TIME ZONE'; @@ -887,7 +974,7 @@ export interface ExprParameter extends PGNode { export interface ExprMember extends PGNode { type: 'member'; operand: Expr; - op: '->' | '->>'; + op: '->' | '->>' | '.'; // '.' is composite-type field access: (expr).field member: string | number; } @@ -936,6 +1023,19 @@ export interface ExprCall extends PGNode { export interface CallOver extends PGNode { orderBy?: OrderByStatement[] | nil; partitionBy?: Expr[] | nil; + frame?: CallOverFrame | nil; +} + +export interface CallOverFrame extends PGNode { + unit: 'rows' | 'range' | 'groups'; + start: FrameBound; + end?: FrameBound | nil; +} + +export interface FrameBound extends PGNode { + type: 'unbounded preceding' | 'unbounded following' | 'current row' | 'preceding' | 'following'; + /** only set for 'preceding' & 'following' bound types */ + value?: Expr | nil; } @@ -968,6 +1068,8 @@ export interface ExprNull extends PGNode { export interface ExprInteger extends PGNode { type: 'integer'; value: number; + /** exact source digits, present only when `value` (a JS number) loses precision */ + valueText?: string; } export interface ExprDefault extends PGNode { @@ -977,6 +1079,8 @@ export interface ExprDefault extends PGNode { export interface ExprNumeric extends PGNode { type: 'numeric'; value: number; + /** exact source text, present for fractional/exponent literals */ + valueText?: string; } export interface ExprString extends PGNode { @@ -1007,6 +1111,94 @@ export interface SetGlobalStatement extends PGNode { scope?: string; set: SetGlobalValue; } + +export interface RoleOptions { + superuser?: boolean; + login?: boolean; + bypassRls?: boolean; +} + +export interface CreateRoleStatement extends PGNode { + type: 'create role'; + name: Name; + options: RoleOptions; +} + +export interface SetRoleStatement extends PGNode { + type: 'set role'; + scope?: string; + /** absent means "NONE" (reset to the session role) */ + role?: Name | nil; +} + +export interface ResetStatement extends PGNode { + type: 'reset'; + /** 'all', or the config parameter / 'role' being reset */ + identifier: 'all' | Name; +} + +export type PolicyCommand = 'all' | 'select' | 'insert' | 'update' | 'delete'; + +export interface CreatePolicyStatement extends PGNode { + type: 'create policy'; + name: Name; + table: QName; + /** true = PERMISSIVE (default), false = RESTRICTIVE */ + permissive?: boolean; + for?: PolicyCommand; + roles?: Name[]; + using?: Expr; + withCheck?: Expr; +} + +export interface DropPolicyStatement extends PGNode { + type: 'drop policy'; + name: Name; + table: QName; + ifExists?: boolean; +} + +export interface TriggerEvent { + event: 'insert' | 'update' | 'delete' | 'truncate'; + /** only for UPDATE OF (col, ...) */ + columns?: Name[]; +} + +export interface CreateTriggerStatement extends PGNode { + type: 'create trigger'; + name: Name; + constraint?: boolean; + timing: 'before' | 'after' | 'instead of'; + events: TriggerEvent[]; + table: QName; + forEach: 'row' | 'statement'; + when?: Expr; + execute: { + function: QName; + arguments: Expr[]; + }; +} + +export interface GrantOnTarget extends PGNode { + type: 'table'; + names: QName[]; +} + +export interface GrantStatement extends PGNode { + type: 'grant'; + privileges: 'all' | string[]; + on: GrantOnTarget; + to: Name[]; + withGrantOption?: boolean; +} + +export interface RevokeStatement extends PGNode { + type: 'revoke'; + privileges: 'all' | string[]; + on: GrantOnTarget; + from: Name[]; + grantOptionFor?: boolean; +} export interface SetTimezone extends PGNode { type: 'set timezone', to: SetTimezoneValue; diff --git a/.deno/syntax/main.ne.ts b/.deno/syntax/main.ne.ts index 9a7d5d6..ea64c9d 100644 --- a/.deno/syntax/main.ne.ts +++ b/.deno/syntax/main.ne.ts @@ -166,10 +166,12 @@ declare var op_exp: any; declare var lbracket: any; declare var rbracket: any; declare var op_cast: any; -declare var kw_cast: any; declare var dot: any; +declare var kw_cast: any; declare var kw_array: any; declare var qparam: any; +declare var float: any; +declare var int: any; declare var kw_default: any; declare var kw_like: any; declare var kw_ilike: any; @@ -210,6 +212,9 @@ declare var kw_foreign: any; declare var kw_references: any; declare var kw_on: any; declare var kw_full: any; +declare var kw_not: any; +declare var kw_deferrable: any; +declare var kw_initially: any; declare var kw_null: any; declare var kw_default: any; declare var kw_like: any; @@ -231,14 +236,50 @@ declare var op_eq: any; declare var kw_create: any; declare var kw_with: any; declare var kw_from: any; -declare var kw_default: any; +declare var kw_create: any; +declare var kw_user: any; +declare var kw_with: any; +declare var kw_create: any; +declare var kw_on: any; +declare var kw_as: any; +declare var kw_for: any; +declare var kw_to: any; +declare var kw_using: any; +declare var kw_with: any; +declare var kw_check: any; +declare var kw_all: any; +declare var kw_select: any; +declare var kw_current_user: any; +declare var kw_current_role: any; +declare var kw_session_user: any; +declare var kw_grant: any; declare var kw_to: any; +declare var kw_with: any; +declare var kw_for: any; +declare var kw_from: any; +declare var kw_all: any; +declare var kw_select: any; +declare var kw_references: any; +declare var kw_on: any; +declare var kw_table: any; +declare var kw_group: any; +declare var kw_current_user: any; +declare var kw_session_user: any; +declare var kw_create: any; +declare var kw_constraint: any; +declare var kw_on: any; +declare var kw_for: any; +declare var kw_when: any; +declare var kw_or: any; +declare var kw_to: any; +declare var kw_default: any; declare var op_eq: any; declare var word: any; declare var kw_on: any; declare var kw_true: any; declare var kw_false: any; declare var quoted_word: any; +declare var kw_all: any; declare var kw_create: any; declare var kw_using: any; declare var comma: any; @@ -275,13 +316,21 @@ declare var kw_to: any; declare var kw_session_user: any; declare var kw_current_user: any; declare var comma: any; +declare var kw_on: any; declare var kw_table: any; +declare var kw_user: any; declare var kw_concurrently: any; declare var kw_with: any; declare var kw_as: any; declare var kw_create: any; declare var kw_as: any; declare var comma: any; +declare var kw_create: any; +declare var kw_as: any; +declare var kw_constraint: any; +declare var kw_null: any; +declare var kw_check: any; +declare var kw_default: any; declare var kw_to: any; declare var kw_union: any; declare var kw_all: any; @@ -384,6 +433,39 @@ import {track, box, unbox, doubleQuoted} from '../lexer.ts'; return flattenStr(e).join(join || ''); } + function mkInteger(tok: any) { + const text = String(tok?.value ?? tok); + const n = parseInt(text, 10); + // preserve exact digits when the value can't be represented as a safe JS integer + return Number.isSafeInteger(n) + ? { type: 'integer', value: n } + : { type: 'integer', value: n, valueText: text }; + } + function canonNumeric(text: string): string { + // canonical decimal form (equivalent literals -> same text), precision preserved + let t = text.trim(); + if (/[eE]/.test(t)) { + return t; // leave exponent forms as-is + } + let sign = ''; + if (t[0] === '+' || t[0] === '-') { sign = t[0] === '-' ? '-' : ''; t = t.slice(1); } + if (t.startsWith('.')) { t = '0' + t; } // .5 -> 0.5 + if (t.includes('.')) { + t = t.replace(/0+$/, ''); // 1.50 -> 1.5, 42.0 -> 42. + // keep the trailing '.' so it re-parses as numeric (not integer) + } + return (sign && parseFloat(t) !== 0 ? sign : '') + t; + } + function mkNumeric(tok: any) { + const text = String(tok?.value ?? tok); + const n = parseFloat(text); + // a fractional/exponent literal may not round-trip through a JS double, so keep + // the exact (canonical) source text for arbitrary-precision numeric consumers + return /[.eE]/.test(text) + ? { type: 'numeric', value: n, valueText: canonNumeric(text) } + : { type: 'numeric', value: n }; + } + function fromEntries(vals: [string, any][]): any { const ret = {} as any; for (const [k, v] of vals) { @@ -413,6 +495,11 @@ import {track, box, unbox, doubleQuoted} from '../lexer.ts'; } +function mergeRoleOptions(opts: any[]) { + return Object.assign({}, ...opts); +} + + function setSeqOpts(ret: any, opts: any) { const defs = new Set(); const unboxed = opts.map(unbox); @@ -504,6 +591,28 @@ const grammar: Grammar = { {"name": "kw_write", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('write')}, {"name": "kw_isolation", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('isolation')}, {"name": "kw_level", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('level')}, + {"name": "kw_policy", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('policy')}, + {"name": "kw_permissive", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('permissive')}, + {"name": "kw_restrictive", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('restrictive')}, + {"name": "kw_force", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('force')}, + {"name": "kw_security", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('security')}, + {"name": "kw_enable", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('enable')}, + {"name": "kw_disable", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('disable')}, + {"name": "kw_public", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('public')}, + {"name": "kw_revoke", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('revoke')}, + {"name": "kw_privileges", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('privileges')}, + {"name": "kw_usage", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('usage')}, + {"name": "kw_execute", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('execute')}, + {"name": "kw_before", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('before')}, + {"name": "kw_after", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('after')}, + {"name": "kw_instead", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('instead')}, + {"name": "kw_of", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('of')}, + {"name": "kw_each", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('each')}, + {"name": "kw_statement", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('statement')}, + {"name": "kw_procedure", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('procedure')}, + {"name": "kw_connect", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('connect')}, + {"name": "kw_deferred", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('deferred')}, + {"name": "kw_immediate", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('immediate')}, {"name": "kw_serializable", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('serializable')}, {"name": "kw_rollback", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('rollback')}, {"name": "kw_insert", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('insert')}, @@ -530,6 +639,7 @@ const grammar: Grammar = { {"name": "kw_maxvalue", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('maxvalue')}, {"name": "kw_data", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('data')}, {"name": "kw_type", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('type')}, + {"name": "kw_domain", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('domain')}, {"name": "kw_trigger", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('trigger')}, {"name": "kw_delete", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('delete')}, {"name": "kw_cache", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('cache')}, @@ -539,6 +649,7 @@ const grammar: Grammar = { {"name": "kw_cycle", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('cycle')}, {"name": "kw_function", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('function')}, {"name": "kw_returns", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('returns')}, + {"name": "kw_setof", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('setof')}, {"name": "kw_language", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('language')}, {"name": "kw_out", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('out')}, {"name": "kw_inout", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('inout')}, @@ -550,6 +661,29 @@ const grammar: Grammar = { {"name": "kw_by", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('by')}, {"name": "kw_row", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('row')}, {"name": "kw_rows", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('rows')}, + {"name": "kw_savepoint", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('savepoint')}, + {"name": "kw_release", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('release')}, + {"name": "kw_role", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('role')}, + {"name": "kw_reset", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('reset')}, + {"name": "kw_login", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('login')}, + {"name": "kw_nologin", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('nologin')}, + {"name": "kw_superuser", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('superuser')}, + {"name": "kw_nosuperuser", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('nosuperuser')}, + {"name": "kw_bypassrls", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('bypassrls')}, + {"name": "kw_nobypassrls", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('nobypassrls')}, + {"name": "kw_password", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('password')}, + {"name": "kw_createdb", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('createdb')}, + {"name": "kw_nocreatedb", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('nocreatedb')}, + {"name": "kw_createrole", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('createrole')}, + {"name": "kw_nocreaterole", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('nocreaterole')}, + {"name": "kw_inherit", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('inherit')}, + {"name": "kw_noinherit", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('noinherit')}, + {"name": "kw_range", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('range')}, + {"name": "kw_groups", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('groups')}, + {"name": "kw_unbounded", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('unbounded')}, + {"name": "kw_preceding", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('preceding')}, + {"name": "kw_following", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('following')}, + {"name": "kw_current", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('current')}, {"name": "kw_next", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('next')}, {"name": "kw_match", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('match')}, {"name": "kw_replace", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('replace')}, @@ -1435,6 +1569,12 @@ const grammar: Grammar = { operand: unwrap(x[0]), to: x[2], }) }, + {"name": "expr_member", "symbols": ["expr_paren", (lexerAny.has("dot") ? {type: "dot"} : dot), "word"], "postprocess": x => track(x, { + type: 'member', + operand: unwrap(x[0]), + op: '.', + member: toStr(x[2]), + }) }, {"name": "expr_member", "symbols": [(lexerAny.has("kw_cast") ? {type: "kw_cast"} : kw_cast), "lparen", "expr_nostar", (lexerAny.has("kw_as") ? {type: "kw_as"} : kw_as), "data_type", "rparen"], "postprocess": x => track(x, { type: 'cast', operand: unwrap(x[2]), @@ -1526,25 +1666,54 @@ const grammar: Grammar = { {"name": "expr_call$ebnf$5", "symbols": [], "postprocess": () => null}, {"name": "expr_call$ebnf$6", "symbols": ["expr_call_over"], "postprocess": id}, {"name": "expr_call$ebnf$6", "symbols": [], "postprocess": () => null}, - {"name": "expr_call", "symbols": ["expr_fn_name", "lparen", "expr_call$ebnf$1", "expr_call$ebnf$2", "expr_call$ebnf$3", "rparen", "expr_call$ebnf$4", "expr_call$ebnf$5", "expr_call$ebnf$6"], "postprocess": x => track(x, { - type: 'call', - function: unwrap(x[0]), - ...x[2] && {distinct: toStr(x[2])}, - args: x[3] || [], - ...x[4] && {orderBy: x[4]}, - ...x[6] && {filter: unwrap(x[6])}, - ...x[7] && {withinGroup: x[7]}, - ...x[8] && {over: unwrap(x[8])}, - }) }, + {"name": "expr_call", "symbols": ["expr_fn_name", "lparen", "expr_call$ebnf$1", "expr_call$ebnf$2", "expr_call$ebnf$3", "rparen", "expr_call$ebnf$4", "expr_call$ebnf$5", "expr_call$ebnf$6"], "postprocess": (x, _loc, reject) => { + const fn = unwrap(x[0]); + // "position" has no generic call form in postgres - only the special + // "position(x in y)" syntax (spe_position). Reject the generic parse to + // avoid an ambiguity, since "x in y" is also a valid boolean argument. + if (fn && !fn.schema && typeof fn.name === 'string' && fn.name.toLowerCase() === 'position') { + return reject; + } + return track(x, { + type: 'call', + function: fn, + ...x[2] && {distinct: toStr(x[2])}, + args: x[3] || [], + ...x[4] && {orderBy: x[4]}, + ...x[6] && {filter: unwrap(x[6])}, + ...x[7] && {withinGroup: x[7]}, + ...x[8] && {over: unwrap(x[8])}, + }); + } }, {"name": "expr_call_over$ebnf$1$subexpression$1", "symbols": ["kw_partition", "kw_by", "expr_list_raw"], "postprocess": last}, {"name": "expr_call_over$ebnf$1", "symbols": ["expr_call_over$ebnf$1$subexpression$1"], "postprocess": id}, {"name": "expr_call_over$ebnf$1", "symbols": [], "postprocess": () => null}, {"name": "expr_call_over$ebnf$2", "symbols": ["select_order_by"], "postprocess": id}, {"name": "expr_call_over$ebnf$2", "symbols": [], "postprocess": () => null}, - {"name": "expr_call_over", "symbols": ["kw_over", "lparen", "expr_call_over$ebnf$1", "expr_call_over$ebnf$2", "rparen"], "postprocess": x => track(x, { + {"name": "expr_call_over$ebnf$3", "symbols": ["expr_call_over_frame"], "postprocess": id}, + {"name": "expr_call_over$ebnf$3", "symbols": [], "postprocess": () => null}, + {"name": "expr_call_over", "symbols": ["kw_over", "lparen", "expr_call_over$ebnf$1", "expr_call_over$ebnf$2", "expr_call_over$ebnf$3", "rparen"], "postprocess": x => track(x, { ...x[2] && { partitionBy: x[2] }, ...x[3] && { orderBy: x[3] }, + ...x[4] && { frame: unwrap(x[4]) }, }) }, + {"name": "expr_call_over_frame$subexpression$1", "symbols": ["kw_rows"]}, + {"name": "expr_call_over_frame$subexpression$1", "symbols": ["kw_range"]}, + {"name": "expr_call_over_frame$subexpression$1", "symbols": ["kw_groups"]}, + {"name": "expr_call_over_frame", "symbols": ["expr_call_over_frame$subexpression$1", "expr_call_over_frame_bounds"], "postprocess": x => track(x, { + unit: toStr(x[0]), + ...x[1], + }) }, + {"name": "expr_call_over_frame_bounds", "symbols": ["kw_between", "expr_call_over_frame_bound", (lexerAny.has("kw_and") ? {type: "kw_and"} : kw_and), "expr_call_over_frame_bound"], "postprocess": x => ({ start: unwrap(x[1]), end: unwrap(x[3]) })}, + {"name": "expr_call_over_frame_bounds", "symbols": ["expr_call_over_frame_bound"], "postprocess": x => ({ start: unwrap(x[0]) })}, + {"name": "expr_call_over_frame_bound", "symbols": ["kw_unbounded", "kw_preceding"], "postprocess": x => track(x, { type: 'unbounded preceding' })}, + {"name": "expr_call_over_frame_bound", "symbols": ["kw_unbounded", "kw_following"], "postprocess": x => track(x, { type: 'unbounded following' })}, + {"name": "expr_call_over_frame_bound", "symbols": ["kw_current", "kw_row"], "postprocess": x => track(x, { type: 'current row' })}, + {"name": "expr_call_over_frame_bound", "symbols": ["expr_call_over_frame_value", "kw_preceding"], "postprocess": x => track(x, { type: 'preceding', value: unwrap(x[0]) })}, + {"name": "expr_call_over_frame_bound", "symbols": ["expr_call_over_frame_value", "kw_following"], "postprocess": x => track(x, { type: 'following', value: unwrap(x[0]) })}, + {"name": "expr_call_over_frame_value", "symbols": ["int"], "postprocess": x => track(x, { type: 'integer', value: unbox(x[0]) })}, + {"name": "expr_call_over_frame_value", "symbols": [(lexerAny.has("qparam") ? {type: "qparam"} : qparam)], "postprocess": x => track(x, { type: 'parameter', name: toStr(x[0]) })}, + {"name": "expr_call_over_frame_value", "symbols": ["expr_paren"], "postprocess": unwrap}, {"name": "expr_call_within_group$subexpression$1", "symbols": ["kw_within", (lexerAny.has("kw_group") ? {type: "kw_group"} : kw_group)]}, {"name": "expr_call_within_group$subexpression$2", "symbols": [(lexerAny.has("kw_order") ? {type: "kw_order"} : kw_order), "kw_by"]}, {"name": "expr_call_within_group", "symbols": ["expr_call_within_group$subexpression$1", "lparen", "expr_call_within_group$subexpression$2", "select_order_by_expr", "rparen"], "postprocess": x => track(x, x[3])}, @@ -1554,8 +1723,8 @@ const grammar: Grammar = { field: asName(x[2]), from: x[4], }) }, - {"name": "expr_primary", "symbols": ["float"], "postprocess": x => track(x, { type: 'numeric', value: unbox(x[0]) })}, - {"name": "expr_primary", "symbols": ["int"], "postprocess": x => track(x, { type: 'integer', value: unbox(x[0]) })}, + {"name": "expr_primary", "symbols": [(lexerAny.has("float") ? {type: "float"} : float)], "postprocess": x => track(x, mkNumeric(x[0]))}, + {"name": "expr_primary", "symbols": [(lexerAny.has("int") ? {type: "int"} : int)], "postprocess": x => track(x, mkInteger(x[0]))}, {"name": "expr_primary", "symbols": ["string"], "postprocess": x => track(x, { type: 'string', value: unbox(x[0]) })}, {"name": "expr_primary", "symbols": [(lexerAny.has("kw_true") ? {type: "kw_true"} : kw_true)], "postprocess": x => track(x, { type: 'boolean', value: true })}, {"name": "expr_primary", "symbols": [(lexerAny.has("kw_false") ? {type: "kw_false"} : kw_false)], "postprocess": x => track(x, { type: 'boolean', value: false })}, @@ -1661,6 +1830,7 @@ const grammar: Grammar = { {"name": "value_keyword", "symbols": [(lexerAny.has("kw_current_user") ? {type: "kw_current_user"} : kw_current_user)]}, {"name": "expr_special_calls", "symbols": ["spe_overlay"]}, {"name": "expr_special_calls", "symbols": ["spe_substring"]}, + {"name": "expr_special_calls", "symbols": ["spe_position"]}, {"name": "spe_overlay$subexpression$1", "symbols": ["word"], "postprocess": kw('overlay')}, {"name": "spe_overlay$subexpression$2", "symbols": [(lexerAny.has("lparen") ? {type: "lparen"} : lparen), "expr_nostar"]}, {"name": "spe_overlay$subexpression$3", "symbols": [(lexerAny.has("kw_placing") ? {type: "kw_placing"} : kw_placing), "expr_nostar"]}, @@ -1689,6 +1859,14 @@ const grammar: Grammar = { ...x[2] && {from: x[2][1]}, ...x[3] && {for: x[3][1]}, }) }, + {"name": "spe_position$subexpression$1", "symbols": ["word"], "postprocess": kw('position')}, + {"name": "spe_position$subexpression$2", "symbols": [(lexerAny.has("lparen") ? {type: "lparen"} : lparen), "expr_nostar"]}, + {"name": "spe_position$subexpression$3", "symbols": [(lexerAny.has("kw_in") ? {type: "kw_in"} : kw_in), "expr_nostar"]}, + {"name": "spe_position", "symbols": ["spe_position$subexpression$1", "spe_position$subexpression$2", "spe_position$subexpression$3", (lexerAny.has("rparen") ? {type: "rparen"} : rparen)], "postprocess": x => track(x, { + type: 'position', + substring: x[1][1], + string: x[2][1], + }) }, {"name": "various_binaries", "symbols": ["kw_at", "kw_time", "kw_zone"], "postprocess": () => 'AT TIME ZONE'}, {"name": "createtable_statement$ebnf$1", "symbols": ["createtable_modifiers"], "postprocess": id}, {"name": "createtable_statement$ebnf$1", "symbols": [], "postprocess": () => null}, @@ -1696,7 +1874,9 @@ const grammar: Grammar = { {"name": "createtable_statement$ebnf$2", "symbols": [], "postprocess": () => null}, {"name": "createtable_statement$ebnf$3", "symbols": ["createtable_opts"], "postprocess": id}, {"name": "createtable_statement$ebnf$3", "symbols": [], "postprocess": () => null}, - {"name": "createtable_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "createtable_statement$ebnf$1", (lexerAny.has("kw_table") ? {type: "kw_table"} : kw_table), "createtable_statement$ebnf$2", "qname", "lparen", "createtable_declarationlist", "rparen", "createtable_statement$ebnf$3"], "postprocess": x => { + {"name": "createtable_statement$ebnf$4", "symbols": ["createtable_tablespace"], "postprocess": id}, + {"name": "createtable_statement$ebnf$4", "symbols": [], "postprocess": () => null}, + {"name": "createtable_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "createtable_statement$ebnf$1", (lexerAny.has("kw_table") ? {type: "kw_table"} : kw_table), "createtable_statement$ebnf$2", "qname", "lparen", "createtable_declarationlist", "rparen", "createtable_statement$ebnf$3", "createtable_statement$ebnf$4"], "postprocess": x => { const cols = x[6].filter((v: any) => 'kind' in v); const constraints = x[6].filter((v: any) => !('kind' in v)); @@ -1708,9 +1888,11 @@ const grammar: Grammar = { columns: cols, ...unwrap(x[1]), ...constraints.length ? { constraints } : {}, - ...last(x), + ...x[8], + ...x[9] ? { tablespace: x[9] } : {}, }); } }, + {"name": "createtable_tablespace", "symbols": ["kw_tablespace", "ident"], "postprocess": x => asName(last(x))}, {"name": "createtable_modifiers", "symbols": ["kw_unlogged"], "postprocess": x => x[0] ? { unlogged: true } : {}}, {"name": "createtable_modifiers", "symbols": ["m_locglob"]}, {"name": "createtable_modifiers", "symbols": ["m_tmp"]}, @@ -1781,6 +1963,12 @@ const grammar: Grammar = { {"name": "createtable_constraint_foreignkey_onsometing$subexpression$1", "symbols": ["kw_partial"]}, {"name": "createtable_constraint_foreignkey_onsometing$subexpression$1", "symbols": ["kw_simple"]}, {"name": "createtable_constraint_foreignkey_onsometing", "symbols": ["kw_match", "createtable_constraint_foreignkey_onsometing$subexpression$1"], "postprocess": x => track(x, {match: toStr(last(x))})}, + {"name": "createtable_constraint_foreignkey_onsometing$ebnf$1", "symbols": [(lexerAny.has("kw_not") ? {type: "kw_not"} : kw_not)], "postprocess": id}, + {"name": "createtable_constraint_foreignkey_onsometing$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "createtable_constraint_foreignkey_onsometing", "symbols": ["createtable_constraint_foreignkey_onsometing$ebnf$1", (lexerAny.has("kw_deferrable") ? {type: "kw_deferrable"} : kw_deferrable)], "postprocess": x => track(x, {deferrable: !x[0]})}, + {"name": "createtable_constraint_foreignkey_onsometing$subexpression$2", "symbols": ["kw_deferred"]}, + {"name": "createtable_constraint_foreignkey_onsometing$subexpression$2", "symbols": ["kw_immediate"]}, + {"name": "createtable_constraint_foreignkey_onsometing", "symbols": [(lexerAny.has("kw_initially") ? {type: "kw_initially"} : kw_initially), "createtable_constraint_foreignkey_onsometing$subexpression$2"], "postprocess": x => track(x, {initiallyDeferred: toStr(last(x)).toLowerCase() === 'deferred'})}, {"name": "createtable_constraint_on_action$subexpression$1", "symbols": ["kw_cascade"]}, {"name": "createtable_constraint_on_action$subexpression$1$subexpression$1", "symbols": ["kw_no", "kw_action"]}, {"name": "createtable_constraint_on_action$subexpression$1", "symbols": ["createtable_constraint_on_action$subexpression$1$subexpression$1"]}, @@ -1949,17 +2137,231 @@ const grammar: Grammar = { ... !!x[6] ? { version: asLit(x[6]) } : {}, ... !!x[7] ? { from: asLit(x[7]) } : {}, }) }, + {"name": "createrole_statement$subexpression$1", "symbols": ["kw_role"]}, + {"name": "createrole_statement$subexpression$1", "symbols": [(lexerAny.has("kw_user") ? {type: "kw_user"} : kw_user)]}, + {"name": "createrole_statement$ebnf$1", "symbols": [(lexerAny.has("kw_with") ? {type: "kw_with"} : kw_with)], "postprocess": id}, + {"name": "createrole_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "createrole_statement$ebnf$2", "symbols": []}, + {"name": "createrole_statement$ebnf$2", "symbols": ["createrole_statement$ebnf$2", "role_option"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "createrole_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "createrole_statement$subexpression$1", "ident", "createrole_statement$ebnf$1", "createrole_statement$ebnf$2"], "postprocess": x => track(x, { + type: 'create role', + name: asName(x[2]), + // "user" (the keyword token) implies LOGIN + ...(toStr(unwrap(x[1])).toLowerCase() === 'user' ? { options: mergeRoleOptions([{ login: true }, ...(x[4] || [])]) } : { options: mergeRoleOptions(x[4] || []) }), + }) }, + {"name": "role_option", "symbols": ["kw_superuser"], "postprocess": () => ({ superuser: true })}, + {"name": "role_option", "symbols": ["kw_nosuperuser"], "postprocess": () => ({ superuser: false })}, + {"name": "role_option", "symbols": ["kw_login"], "postprocess": () => ({ login: true })}, + {"name": "role_option", "symbols": ["kw_nologin"], "postprocess": () => ({ login: false })}, + {"name": "role_option", "symbols": ["kw_bypassrls"], "postprocess": () => ({ bypassRls: true })}, + {"name": "role_option", "symbols": ["kw_nobypassrls"], "postprocess": () => ({ bypassRls: false })}, + {"name": "role_option$subexpression$1", "symbols": ["kw_password", "string"]}, + {"name": "role_option", "symbols": ["role_option$subexpression$1"], "postprocess": () => ({})}, + {"name": "role_option", "symbols": ["kw_createdb"], "postprocess": () => ({})}, + {"name": "role_option", "symbols": ["kw_nocreatedb"], "postprocess": () => ({})}, + {"name": "role_option", "symbols": ["kw_createrole"], "postprocess": () => ({})}, + {"name": "role_option", "symbols": ["kw_nocreaterole"], "postprocess": () => ({})}, + {"name": "role_option", "symbols": ["kw_inherit"], "postprocess": () => ({})}, + {"name": "role_option", "symbols": ["kw_noinherit"], "postprocess": () => ({})}, + {"name": "createpolicy_statement$ebnf$1$subexpression$1$subexpression$1", "symbols": ["kw_permissive"]}, + {"name": "createpolicy_statement$ebnf$1$subexpression$1$subexpression$1", "symbols": ["kw_restrictive"]}, + {"name": "createpolicy_statement$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_as") ? {type: "kw_as"} : kw_as), "createpolicy_statement$ebnf$1$subexpression$1$subexpression$1"], "postprocess": x => toStr(x[1])}, + {"name": "createpolicy_statement$ebnf$1", "symbols": ["createpolicy_statement$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "createpolicy_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "createpolicy_statement$ebnf$2$subexpression$1", "symbols": [(lexerAny.has("kw_for") ? {type: "kw_for"} : kw_for), "policy_command"], "postprocess": last}, + {"name": "createpolicy_statement$ebnf$2", "symbols": ["createpolicy_statement$ebnf$2$subexpression$1"], "postprocess": id}, + {"name": "createpolicy_statement$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "createpolicy_statement$ebnf$3$subexpression$1", "symbols": [(lexerAny.has("kw_to") ? {type: "kw_to"} : kw_to), "policy_role_list"], "postprocess": last}, + {"name": "createpolicy_statement$ebnf$3", "symbols": ["createpolicy_statement$ebnf$3$subexpression$1"], "postprocess": id}, + {"name": "createpolicy_statement$ebnf$3", "symbols": [], "postprocess": () => null}, + {"name": "createpolicy_statement$ebnf$4$subexpression$1", "symbols": [(lexerAny.has("kw_using") ? {type: "kw_using"} : kw_using), "lparen", "expr", "rparen"], "postprocess": x => x[2]}, + {"name": "createpolicy_statement$ebnf$4", "symbols": ["createpolicy_statement$ebnf$4$subexpression$1"], "postprocess": id}, + {"name": "createpolicy_statement$ebnf$4", "symbols": [], "postprocess": () => null}, + {"name": "createpolicy_statement$ebnf$5$subexpression$1", "symbols": [(lexerAny.has("kw_with") ? {type: "kw_with"} : kw_with), (lexerAny.has("kw_check") ? {type: "kw_check"} : kw_check), "lparen", "expr", "rparen"], "postprocess": x => x[3]}, + {"name": "createpolicy_statement$ebnf$5", "symbols": ["createpolicy_statement$ebnf$5$subexpression$1"], "postprocess": id}, + {"name": "createpolicy_statement$ebnf$5", "symbols": [], "postprocess": () => null}, + {"name": "createpolicy_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "kw_policy", "ident", (lexerAny.has("kw_on") ? {type: "kw_on"} : kw_on), "qualified_name", "createpolicy_statement$ebnf$1", "createpolicy_statement$ebnf$2", "createpolicy_statement$ebnf$3", "createpolicy_statement$ebnf$4", "createpolicy_statement$ebnf$5"], "postprocess": x => track(x, { + type: 'create policy', + name: asName(x[2]), + table: x[4], + ...(x[5] ? { permissive: x[5].toLowerCase() === 'permissive' } : {}), + ...(x[6] ? { for: x[6] } : {}), + ...(x[7] ? { roles: x[7] } : {}), + ...(x[8] ? { using: unwrap(x[8]) } : {}), + ...(x[9] ? { withCheck: unwrap(x[9]) } : {}), + }) }, + {"name": "policy_command", "symbols": [(lexerAny.has("kw_all") ? {type: "kw_all"} : kw_all)], "postprocess": () => 'all'}, + {"name": "policy_command", "symbols": [(lexerAny.has("kw_select") ? {type: "kw_select"} : kw_select)], "postprocess": () => 'select'}, + {"name": "policy_command", "symbols": ["kw_insert"], "postprocess": () => 'insert'}, + {"name": "policy_command", "symbols": ["kw_update"], "postprocess": () => 'update'}, + {"name": "policy_command", "symbols": ["kw_delete"], "postprocess": () => 'delete'}, + {"name": "policy_role_list$ebnf$1", "symbols": []}, + {"name": "policy_role_list$ebnf$1$subexpression$1", "symbols": ["comma", "policy_role"], "postprocess": last}, + {"name": "policy_role_list$ebnf$1", "symbols": ["policy_role_list$ebnf$1", "policy_role_list$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "policy_role_list", "symbols": ["policy_role", "policy_role_list$ebnf$1"], "postprocess": ([head, tail]) => [head, ...(tail || [])]}, + {"name": "policy_role", "symbols": ["ident"], "postprocess": x => asName(unwrap(x))}, + {"name": "policy_role", "symbols": [(lexerAny.has("kw_current_user") ? {type: "kw_current_user"} : kw_current_user)], "postprocess": x => track(x, { name: 'current_user' })}, + {"name": "policy_role", "symbols": [(lexerAny.has("kw_current_role") ? {type: "kw_current_role"} : kw_current_role)], "postprocess": x => track(x, { name: 'current_role' })}, + {"name": "policy_role", "symbols": [(lexerAny.has("kw_session_user") ? {type: "kw_session_user"} : kw_session_user)], "postprocess": x => track(x, { name: 'session_user' })}, + {"name": "droppolicy_statement$ebnf$1", "symbols": ["kw_ifexists"], "postprocess": id}, + {"name": "droppolicy_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "droppolicy_statement$ebnf$2$subexpression$1", "symbols": ["kw_cascade"]}, + {"name": "droppolicy_statement$ebnf$2$subexpression$1", "symbols": ["kw_restrict"]}, + {"name": "droppolicy_statement$ebnf$2", "symbols": ["droppolicy_statement$ebnf$2$subexpression$1"], "postprocess": id}, + {"name": "droppolicy_statement$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "droppolicy_statement", "symbols": ["kw_drop", "kw_policy", "droppolicy_statement$ebnf$1", "ident", (lexerAny.has("kw_on") ? {type: "kw_on"} : kw_on), "qualified_name", "droppolicy_statement$ebnf$2"], "postprocess": x => track(x, { + type: 'drop policy', + name: asName(x[3]), + table: x[5], + ...(x[2] ? { ifExists: true } : {}), + }) }, + {"name": "grant_statement$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_with") ? {type: "kw_with"} : kw_with), (lexerAny.has("kw_grant") ? {type: "kw_grant"} : kw_grant), "kw_option"], "postprocess": () => true}, + {"name": "grant_statement$ebnf$1", "symbols": ["grant_statement$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "grant_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "grant_statement", "symbols": [(lexerAny.has("kw_grant") ? {type: "kw_grant"} : kw_grant), "grant_privileges", "grant_on_target", (lexerAny.has("kw_to") ? {type: "kw_to"} : kw_to), "grant_grantees", "grant_statement$ebnf$1"], "postprocess": x => track(x, { + type: 'grant', + privileges: x[1], + on: x[2], + to: x[4], + ...(x[5] ? { withGrantOption: true } : {}), + }) }, + {"name": "revoke_statement$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_grant") ? {type: "kw_grant"} : kw_grant), "kw_option", (lexerAny.has("kw_for") ? {type: "kw_for"} : kw_for)], "postprocess": () => true}, + {"name": "revoke_statement$ebnf$1", "symbols": ["revoke_statement$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "revoke_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "revoke_statement$ebnf$2$subexpression$1", "symbols": ["kw_cascade"]}, + {"name": "revoke_statement$ebnf$2$subexpression$1", "symbols": ["kw_restrict"]}, + {"name": "revoke_statement$ebnf$2", "symbols": ["revoke_statement$ebnf$2$subexpression$1"], "postprocess": id}, + {"name": "revoke_statement$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "revoke_statement", "symbols": ["kw_revoke", "revoke_statement$ebnf$1", "grant_privileges", "grant_on_target", (lexerAny.has("kw_from") ? {type: "kw_from"} : kw_from), "grant_grantees", "revoke_statement$ebnf$2"], "postprocess": x => track(x, { + type: 'revoke', + privileges: x[2], + on: x[3], + from: x[5], + ...(x[1] ? { grantOptionFor: true } : {}), + }) }, + {"name": "grant_privileges$ebnf$1", "symbols": ["kw_privileges"], "postprocess": id}, + {"name": "grant_privileges$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "grant_privileges", "symbols": [(lexerAny.has("kw_all") ? {type: "kw_all"} : kw_all), "grant_privileges$ebnf$1"], "postprocess": () => 'all'}, + {"name": "grant_privileges$ebnf$2", "symbols": []}, + {"name": "grant_privileges$ebnf$2$subexpression$1", "symbols": ["comma", "grant_priv"], "postprocess": last}, + {"name": "grant_privileges$ebnf$2", "symbols": ["grant_privileges$ebnf$2", "grant_privileges$ebnf$2$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "grant_privileges", "symbols": ["grant_priv", "grant_privileges$ebnf$2"], "postprocess": ([head, tail]) => [head, ...(tail || [])]}, + {"name": "grant_priv$subexpression$1", "symbols": [(lexerAny.has("kw_select") ? {type: "kw_select"} : kw_select)]}, + {"name": "grant_priv$subexpression$1", "symbols": [(lexerAny.has("kw_references") ? {type: "kw_references"} : kw_references)]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_insert"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_update"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_delete"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_truncate"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_trigger"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_usage"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_execute"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_connect"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_temporary"]}, + {"name": "grant_priv$subexpression$1", "symbols": ["kw_temp"]}, + {"name": "grant_priv", "symbols": ["grant_priv$subexpression$1"], "postprocess": x => toStr(unwrap(x)).toLowerCase()}, + {"name": "grant_on_target$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_table") ? {type: "kw_table"} : kw_table)]}, + {"name": "grant_on_target$ebnf$1$subexpression$1", "symbols": ["kw_sequence"]}, + {"name": "grant_on_target$ebnf$1", "symbols": ["grant_on_target$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "grant_on_target$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "grant_on_target", "symbols": [(lexerAny.has("kw_on") ? {type: "kw_on"} : kw_on), "grant_on_target$ebnf$1", "grant_name_list"], "postprocess": x => track(x, { + type: 'table', + names: x[2], + }) }, + {"name": "grant_name_list$ebnf$1", "symbols": []}, + {"name": "grant_name_list$ebnf$1$subexpression$1", "symbols": ["comma", "qualified_name"], "postprocess": last}, + {"name": "grant_name_list$ebnf$1", "symbols": ["grant_name_list$ebnf$1", "grant_name_list$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "grant_name_list", "symbols": ["qualified_name", "grant_name_list$ebnf$1"], "postprocess": ([head, tail]) => [head, ...(tail || [])]}, + {"name": "grant_grantees$ebnf$1", "symbols": []}, + {"name": "grant_grantees$ebnf$1$subexpression$1", "symbols": ["comma", "grant_grantee"], "postprocess": last}, + {"name": "grant_grantees$ebnf$1", "symbols": ["grant_grantees$ebnf$1", "grant_grantees$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "grant_grantees", "symbols": ["grant_grantee", "grant_grantees$ebnf$1"], "postprocess": ([head, tail]) => [head, ...(tail || [])]}, + {"name": "grant_grantee$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_group") ? {type: "kw_group"} : kw_group)], "postprocess": () => null}, + {"name": "grant_grantee$ebnf$1", "symbols": ["grant_grantee$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "grant_grantee$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "grant_grantee", "symbols": ["grant_grantee$ebnf$1", "ident"], "postprocess": x => asName(x[1])}, + {"name": "grant_grantee", "symbols": [(lexerAny.has("kw_current_user") ? {type: "kw_current_user"} : kw_current_user)], "postprocess": x => track(x, { name: 'current_user' })}, + {"name": "grant_grantee", "symbols": [(lexerAny.has("kw_session_user") ? {type: "kw_session_user"} : kw_session_user)], "postprocess": x => track(x, { name: 'session_user' })}, + {"name": "createtrigger_statement$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_constraint") ? {type: "kw_constraint"} : kw_constraint)], "postprocess": () => true}, + {"name": "createtrigger_statement$ebnf$1", "symbols": ["createtrigger_statement$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "createtrigger_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "createtrigger_statement$ebnf$2$subexpression$1$ebnf$1", "symbols": ["kw_each"], "postprocess": id}, + {"name": "createtrigger_statement$ebnf$2$subexpression$1$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "createtrigger_statement$ebnf$2$subexpression$1$subexpression$1", "symbols": ["kw_row"]}, + {"name": "createtrigger_statement$ebnf$2$subexpression$1$subexpression$1", "symbols": ["kw_statement"]}, + {"name": "createtrigger_statement$ebnf$2$subexpression$1", "symbols": [(lexerAny.has("kw_for") ? {type: "kw_for"} : kw_for), "createtrigger_statement$ebnf$2$subexpression$1$ebnf$1", "createtrigger_statement$ebnf$2$subexpression$1$subexpression$1"], "postprocess": x => toStr(last(x)).toLowerCase()}, + {"name": "createtrigger_statement$ebnf$2", "symbols": ["createtrigger_statement$ebnf$2$subexpression$1"], "postprocess": id}, + {"name": "createtrigger_statement$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "createtrigger_statement$ebnf$3$subexpression$1", "symbols": [(lexerAny.has("kw_when") ? {type: "kw_when"} : kw_when), "lparen", "expr", "rparen"], "postprocess": x => x[2]}, + {"name": "createtrigger_statement$ebnf$3", "symbols": ["createtrigger_statement$ebnf$3$subexpression$1"], "postprocess": id}, + {"name": "createtrigger_statement$ebnf$3", "symbols": [], "postprocess": () => null}, + {"name": "createtrigger_statement$subexpression$1", "symbols": ["kw_function"]}, + {"name": "createtrigger_statement$subexpression$1", "symbols": ["kw_procedure"]}, + {"name": "createtrigger_statement$ebnf$4", "symbols": ["expr_list_raw"], "postprocess": id}, + {"name": "createtrigger_statement$ebnf$4", "symbols": [], "postprocess": () => null}, + {"name": "createtrigger_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "createtrigger_statement$ebnf$1", "kw_trigger", "ident", "trigger_timing", "trigger_events", (lexerAny.has("kw_on") ? {type: "kw_on"} : kw_on), "qualified_name", "createtrigger_statement$ebnf$2", "createtrigger_statement$ebnf$3", "kw_execute", "createtrigger_statement$subexpression$1", "qualified_name", "lparen", "createtrigger_statement$ebnf$4", "rparen"], "postprocess": x => track(x, { + type: 'create trigger', + ...(x[1] ? { constraint: true } : {}), + name: asName(x[3]), + timing: x[4], + events: x[5], + table: x[7], + forEach: x[8] ?? 'statement', + ...(x[9] ? { when: unwrap(x[9]) } : {}), + execute: { + function: x[12], + arguments: x[14] ?? [], + }, + }) }, + {"name": "trigger_timing", "symbols": ["kw_before"], "postprocess": () => 'before'}, + {"name": "trigger_timing", "symbols": ["kw_after"], "postprocess": () => 'after'}, + {"name": "trigger_timing", "symbols": ["kw_instead", "kw_of"], "postprocess": () => 'instead of'}, + {"name": "trigger_events$ebnf$1", "symbols": []}, + {"name": "trigger_events$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_or") ? {type: "kw_or"} : kw_or), "trigger_event"], "postprocess": last}, + {"name": "trigger_events$ebnf$1", "symbols": ["trigger_events$ebnf$1", "trigger_events$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "trigger_events", "symbols": ["trigger_event", "trigger_events$ebnf$1"], "postprocess": ([head, tail]) => [head, ...(tail || [])]}, + {"name": "trigger_event", "symbols": ["kw_insert"], "postprocess": x => track(x, { event: 'insert' })}, + {"name": "trigger_event", "symbols": ["kw_delete"], "postprocess": x => track(x, { event: 'delete' })}, + {"name": "trigger_event", "symbols": ["kw_truncate"], "postprocess": x => track(x, { event: 'truncate' })}, + {"name": "trigger_event$ebnf$1$subexpression$1", "symbols": ["kw_of", "collist"], "postprocess": last}, + {"name": "trigger_event$ebnf$1", "symbols": ["trigger_event$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "trigger_event$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "trigger_event", "symbols": ["kw_update", "trigger_event$ebnf$1"], "postprocess": x => track(x, { + event: 'update', + ...(x[1] ? { columns: x[1].map(asName) } : {}), + }) }, {"name": "simplestatements_all", "symbols": ["simplestatements_start_transaction"]}, {"name": "simplestatements_all", "symbols": ["simplestatements_commit"]}, {"name": "simplestatements_all", "symbols": ["simplestatements_rollback"]}, + {"name": "simplestatements_all", "symbols": ["simplestatements_savepoint"]}, + {"name": "simplestatements_all", "symbols": ["simplestatements_release"]}, {"name": "simplestatements_all", "symbols": ["simplestatements_tablespace"]}, {"name": "simplestatements_all", "symbols": ["simplestatements_set"]}, + {"name": "simplestatements_all", "symbols": ["simplestatements_set_role"]}, + {"name": "simplestatements_all", "symbols": ["simplestatements_reset"]}, {"name": "simplestatements_all", "symbols": ["simplestatements_show"]}, {"name": "simplestatements_all", "symbols": ["simplestatements_begin"]}, {"name": "simplestatements_start_transaction$subexpression$1", "symbols": ["kw_start", "kw_transaction"]}, {"name": "simplestatements_start_transaction", "symbols": ["simplestatements_start_transaction$subexpression$1"], "postprocess": x => track(x, { type: 'start transaction' })}, {"name": "simplestatements_commit", "symbols": ["kw_commit"], "postprocess": x => track(x, { type: 'commit' })}, - {"name": "simplestatements_rollback", "symbols": ["kw_rollback"], "postprocess": x => track(x, { type: 'rollback' })}, + {"name": "simplestatements_rollback$ebnf$1$subexpression$1$ebnf$1", "symbols": ["kw_savepoint"], "postprocess": id}, + {"name": "simplestatements_rollback$ebnf$1$subexpression$1$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "simplestatements_rollback$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_to") ? {type: "kw_to"} : kw_to), "simplestatements_rollback$ebnf$1$subexpression$1$ebnf$1", "ident"], "postprocess": last}, + {"name": "simplestatements_rollback$ebnf$1", "symbols": ["simplestatements_rollback$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "simplestatements_rollback$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "simplestatements_rollback", "symbols": ["kw_rollback", "simplestatements_rollback$ebnf$1"], "postprocess": x => track(x, { + type: 'rollback', + ...x[1] && { to: asName(unwrap(x[1])) }, + }) }, + {"name": "simplestatements_savepoint", "symbols": ["kw_savepoint", "ident"], "postprocess": x => track(x, { + type: 'savepoint', + name: asName(x[1]), + }) }, + {"name": "simplestatements_release$ebnf$1", "symbols": ["kw_savepoint"], "postprocess": id}, + {"name": "simplestatements_release$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "simplestatements_release", "symbols": ["kw_release", "simplestatements_release$ebnf$1", "ident"], "postprocess": x => track(x, { + type: 'release savepoint', + name: asName(x[2]), + }) }, {"name": "simplestatements_tablespace", "symbols": ["kw_tablespace", "word"], "postprocess": x => track(x, { type: 'tablespace', tablespace: asName(x[1]), @@ -2010,6 +2412,24 @@ const grammar: Grammar = { {"name": "simplestatements_set_val_raw", "symbols": ["simplestatements_set_val_raw$subexpression$2"], "postprocess": x => track(x, { type: 'identifier', name: unwrap(x).value })}, {"name": "simplestatements_set_val_raw", "symbols": [(lexerAny.has("quoted_word") ? {type: "quoted_word"} : quoted_word)], "postprocess": x => track(x, { type: 'identifier', doubleQuoted: true, name: unwrap(x).value })}, {"name": "simplestatements_show", "symbols": ["kw_show", "ident"], "postprocess": x => track(x, { type: 'show', variable: asName(x[1]) })}, + {"name": "simplestatements_set_role$ebnf$1$subexpression$1", "symbols": ["kw_session"]}, + {"name": "simplestatements_set_role$ebnf$1$subexpression$1", "symbols": ["kw_local"]}, + {"name": "simplestatements_set_role$ebnf$1", "symbols": ["simplestatements_set_role$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "simplestatements_set_role$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "simplestatements_set_role", "symbols": ["kw_set", "simplestatements_set_role$ebnf$1", "kw_role", "ident"], "postprocess": x => { + const r = asName(x[3]); + return track(x, { + type: 'set role', + scope: unwrap(x[1])?.toLowerCase(), + ...(r.name.toLowerCase() === 'none' ? {} : { role: r }), + }); + } }, + {"name": "simplestatements_reset$subexpression$1", "symbols": [(lexerAny.has("kw_all") ? {type: "kw_all"} : kw_all)], "postprocess": () => 'all'}, + {"name": "simplestatements_reset$subexpression$1", "symbols": ["ident"]}, + {"name": "simplestatements_reset", "symbols": ["kw_reset", "simplestatements_reset$subexpression$1"], "postprocess": x => track(x, { + type: 'reset', + identifier: unwrap(x[1]) === 'all' ? 'all' : asName(unwrap(x[1])), + }) }, {"name": "create_schema$subexpression$1", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "kw_schema"]}, {"name": "create_schema$ebnf$1", "symbols": ["kw_ifnotexists"], "postprocess": id}, {"name": "create_schema$ebnf$1", "symbols": [], "postprocess": () => null}, @@ -2258,10 +2678,19 @@ const grammar: Grammar = { {"name": "altertable_action", "symbols": ["altertable_add_constraint"]}, {"name": "altertable_action", "symbols": ["altertable_drop_constraint"]}, {"name": "altertable_action", "symbols": ["altertable_owner"]}, + {"name": "altertable_action", "symbols": ["altertable_row_security"]}, {"name": "altertable_rename_table", "symbols": ["kw_rename", (lexerAny.has("kw_to") ? {type: "kw_to"} : kw_to), "word"], "postprocess": x => track(x, { type: 'rename', to: asName(last(x)), }) }, + {"name": "altertable_row_security$subexpression$1", "symbols": ["kw_enable"]}, + {"name": "altertable_row_security$subexpression$1", "symbols": ["kw_disable"]}, + {"name": "altertable_row_security$subexpression$1", "symbols": ["kw_force"]}, + {"name": "altertable_row_security$subexpression$1", "symbols": ["kw_no", "kw_force"], "postprocess": () => 'no force'}, + {"name": "altertable_row_security", "symbols": ["altertable_row_security$subexpression$1", "kw_row", "kw_level", "kw_security"], "postprocess": x => track(x, { + type: 'row level security', + action: (() => { const v = unwrap(x[0]); return typeof v === 'string' ? v : toStr(v); })(), + }) }, {"name": "altertable_rename_column$ebnf$1", "symbols": ["kw_column"], "postprocess": id}, {"name": "altertable_rename_column$ebnf$1", "symbols": [], "postprocess": () => null}, {"name": "altertable_rename_column", "symbols": ["kw_rename", "altertable_rename_column$ebnf$1", "ident", (lexerAny.has("kw_to") ? {type: "kw_to"} : kw_to), "ident"], "postprocess": x => track(x, { @@ -2526,10 +2955,25 @@ const grammar: Grammar = { ... x[4] && {cascade: toStr(x[4]) }, }); }}, + {"name": "drop_trigger_statement$ebnf$1", "symbols": ["kw_ifexists"], "postprocess": id}, + {"name": "drop_trigger_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "drop_trigger_statement$ebnf$2$subexpression$1", "symbols": ["kw_cascade"]}, + {"name": "drop_trigger_statement$ebnf$2$subexpression$1", "symbols": ["kw_restrict"]}, + {"name": "drop_trigger_statement$ebnf$2", "symbols": ["drop_trigger_statement$ebnf$2$subexpression$1"], "postprocess": id}, + {"name": "drop_trigger_statement$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "drop_trigger_statement", "symbols": ["kw_drop", "kw_trigger", "drop_trigger_statement$ebnf$1", "ident", (lexerAny.has("kw_on") ? {type: "kw_on"} : kw_on), "qualified_name", "drop_trigger_statement$ebnf$2"], "postprocess": (x: any) => track(x, { + type: 'drop trigger', + ...x[2] && { ifExists: true }, + name: asName(x[3]), + onTable: x[5], + ...x[6] && { cascade: toStr(x[6]) }, + }) }, {"name": "drop_what", "symbols": [(lexerAny.has("kw_table") ? {type: "kw_table"} : kw_table)], "postprocess": x => track(x, { type: 'drop table' })}, {"name": "drop_what", "symbols": ["kw_sequence"], "postprocess": x => track(x, { type: 'drop sequence' })}, {"name": "drop_what", "symbols": ["kw_type"], "postprocess": x => track(x, { type: 'drop type' })}, - {"name": "drop_what", "symbols": ["kw_trigger"], "postprocess": x => track(x, { type: 'drop trigger' })}, + {"name": "drop_what$subexpression$1", "symbols": ["kw_role"]}, + {"name": "drop_what$subexpression$1", "symbols": [(lexerAny.has("kw_user") ? {type: "kw_user"} : kw_user)]}, + {"name": "drop_what", "symbols": ["drop_what$subexpression$1"], "postprocess": x => track(x, { type: 'drop role' })}, {"name": "drop_what$ebnf$1", "symbols": [(lexerAny.has("kw_concurrently") ? {type: "kw_concurrently"} : kw_concurrently)], "postprocess": id}, {"name": "drop_what$ebnf$1", "symbols": [], "postprocess": () => null}, {"name": "drop_what", "symbols": ["kw_index", "drop_what$ebnf$1"], "postprocess": x => track(x, { @@ -2542,10 +2986,12 @@ const grammar: Grammar = { in: unwrap(x[2]), }) }, {"name": "with_recursive_statement$subexpression$1", "symbols": [(lexerAny.has("kw_with") ? {type: "kw_with"} : kw_with), "kw_recursive"]}, - {"name": "with_recursive_statement", "symbols": ["with_recursive_statement$subexpression$1", "ident", "collist_paren", (lexerAny.has("kw_as") ? {type: "kw_as"} : kw_as), "lparen", "union_statement", "rparen", "with_statement_statement"], "postprocess": x => track(x, { + {"name": "with_recursive_statement$ebnf$1", "symbols": ["collist_paren"], "postprocess": id}, + {"name": "with_recursive_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "with_recursive_statement", "symbols": ["with_recursive_statement$subexpression$1", "ident", "with_recursive_statement$ebnf$1", (lexerAny.has("kw_as") ? {type: "kw_as"} : kw_as), "lparen", "union_statement", "rparen", "with_statement_statement"], "postprocess": x => track(x, { type: 'with recursive', alias: asName(x[1]), - columnNames: x[2].map(asName), + ...x[2] && { columnNames: x[2].map(asName) }, bind: x[5], in: unwrap(x[7]), }) }, @@ -2601,6 +3047,36 @@ const grammar: Grammar = { ...x[2] ? { collate: x[2][1] }: {}, }) } }, + {"name": "createdomain_statement$ebnf$1", "symbols": [(lexerAny.has("kw_as") ? {type: "kw_as"} : kw_as)], "postprocess": id}, + {"name": "createdomain_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "createdomain_statement$ebnf$2", "symbols": ["createtable_collate"], "postprocess": id}, + {"name": "createdomain_statement$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "createdomain_statement$ebnf$3", "symbols": []}, + {"name": "createdomain_statement$ebnf$3", "symbols": ["createdomain_statement$ebnf$3", "domain_item"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "createdomain_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "kw_domain", "qualified_name", "createdomain_statement$ebnf$1", "data_type", "createdomain_statement$ebnf$2", "createdomain_statement$ebnf$3"], "postprocess": x => { + const items = x[6] || []; + const constraints = items.filter((i: any) => i.type !== 'default'); + const def = items.find((i: any) => i.type === 'default'); + return track(x, { + type: 'create domain', + name: x[2], + dataType: x[4], + ...(x[5] ? { collate: x[5][1] } : {}), + ...(constraints.length ? { constraints } : {}), + ...(def ? { default: def.default } : {}), + }); + } }, + {"name": "domain_item$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_constraint") ? {type: "kw_constraint"} : kw_constraint), "word"], "postprocess": x => asName(x[1])}, + {"name": "domain_item$ebnf$1", "symbols": ["domain_item$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "domain_item$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "domain_item", "symbols": ["domain_item$ebnf$1", "domain_item_def"], "postprocess": x => track(x, { + ...(x[0] ? { constraintName: x[0] } : {}), + ...unwrap(x[1]), + }) }, + {"name": "domain_item_def", "symbols": ["kw_not_null"], "postprocess": () => ({ type: 'not null' })}, + {"name": "domain_item_def", "symbols": [(lexerAny.has("kw_null") ? {type: "kw_null"} : kw_null)], "postprocess": () => ({ type: 'null' })}, + {"name": "domain_item_def", "symbols": [(lexerAny.has("kw_check") ? {type: "kw_check"} : kw_check), "expr_paren"], "postprocess": x => ({ type: 'check', expr: unwrap(x[1]) })}, + {"name": "domain_item_def", "symbols": [(lexerAny.has("kw_default") ? {type: "kw_default"} : kw_default), "expr"], "postprocess": x => ({ type: 'default', default: unwrap(x[1]) })}, {"name": "altertype_statement$subexpression$1", "symbols": ["altertype_enum_add_value"]}, {"name": "altertype_statement$subexpression$1", "symbols": ["altertype_enum_rename"]}, {"name": "altertype_statement", "symbols": ["kw_alter", "kw_type", "qualified_name", "altertype_statement$subexpression$1"], "postprocess": x => track(x, { @@ -2656,6 +3132,14 @@ const grammar: Grammar = { {"name": "deallocate_target", "symbols": ["deallocate_name"], "postprocess": unwrap}, {"name": "deallocate_name", "symbols": ["ident"], "postprocess": x => track(x, asName(x[0]) )}, {"name": "deallocate_all", "symbols": [(lexerAny.has("kw_all") ? {type: "kw_all"} : kw_all)], "postprocess": x => track(x, { option: 'all' })}, + {"name": "execute_statement$ebnf$1$subexpression$1", "symbols": ["lparen", "expr_list_raw", "rparen"], "postprocess": x => x[1]}, + {"name": "execute_statement$ebnf$1", "symbols": ["execute_statement$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "execute_statement$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "execute_statement", "symbols": ["kw_execute", "ident", "execute_statement$ebnf$1"], "postprocess": x => track(x, { + type: 'execute', + name: asName(x[1]), + ...x[2] && { args: x[2] }, + }) }, {"name": "create_view_statements", "symbols": ["create_view"]}, {"name": "create_view_statements", "symbols": ["create_materialized_view"]}, {"name": "create_view$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_or") ? {type: "kw_or"} : kw_or), "kw_replace"]}, @@ -2829,7 +3313,12 @@ const grammar: Grammar = { {"name": "func_spec$ebnf$1", "symbols": [], "postprocess": () => null}, {"name": "func_spec$subexpression$2", "symbols": ["word"], "postprocess": kw('leakproof')}, {"name": "func_spec", "symbols": ["func_spec$ebnf$1", "func_spec$subexpression$2"], "postprocess": x => track(x, { leakproof: !x[0] })}, - {"name": "func_spec", "symbols": ["func_returns"], "postprocess": x => track(x, { returns: unwrap(x) })}, + {"name": "func_spec", "symbols": ["func_returns"], "postprocess": x => { + const r = unwrap(x); + return r && r.__setof + ? track(x, { returns: r.__setof, setof: true }) + : track(x, { returns: r }); + } }, {"name": "func_spec$subexpression$3", "symbols": ["word"], "postprocess": kw('called')}, {"name": "func_spec", "symbols": ["func_spec$subexpression$3", "oninp"], "postprocess": () => ({ onNullInput: 'call' })}, {"name": "func_spec$subexpression$4", "symbols": ["word"], "postprocess": kw('returns')}, @@ -2842,6 +3331,7 @@ const grammar: Grammar = { {"name": "oninp$subexpression$1", "symbols": ["word"], "postprocess": kw('input')}, {"name": "oninp", "symbols": [(lexerAny.has("kw_on") ? {type: "kw_on"} : kw_on), (lexerAny.has("kw_null") ? {type: "kw_null"} : kw_null), "oninp$subexpression$1"]}, {"name": "func_returns", "symbols": ["kw_returns", "data_type"], "postprocess": last}, + {"name": "func_returns", "symbols": ["kw_returns", "kw_setof", "data_type"], "postprocess": x => ({ __setof: last(x) })}, {"name": "func_returns$macrocall$2", "symbols": ["func_ret_table_col"]}, {"name": "func_returns$macrocall$1$ebnf$1", "symbols": []}, {"name": "func_returns$macrocall$1$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("comma") ? {type: "comma"} : comma), "func_returns$macrocall$2"], "postprocess": last}, @@ -2909,9 +3399,16 @@ const grammar: Grammar = { {"name": "statement", "symbols": ["statement_noprep"]}, {"name": "statement", "symbols": ["prepare"]}, {"name": "statement", "symbols": ["deallocate"]}, + {"name": "statement", "symbols": ["execute_statement"]}, {"name": "statement_noprep", "symbols": ["selection"]}, {"name": "statement_noprep", "symbols": ["createtable_statement"]}, {"name": "statement_noprep", "symbols": ["createextension_statement"]}, + {"name": "statement_noprep", "symbols": ["createrole_statement"]}, + {"name": "statement_noprep", "symbols": ["createpolicy_statement"]}, + {"name": "statement_noprep", "symbols": ["droppolicy_statement"]}, + {"name": "statement_noprep", "symbols": ["grant_statement"]}, + {"name": "statement_noprep", "symbols": ["revoke_statement"]}, + {"name": "statement_noprep", "symbols": ["createtrigger_statement"]}, {"name": "statement_noprep", "symbols": ["createindex_statement"]}, {"name": "statement_noprep", "symbols": ["simplestatements_all"]}, {"name": "statement_noprep", "symbols": ["insert_statement"]}, @@ -2922,7 +3419,9 @@ const grammar: Grammar = { {"name": "statement_noprep", "symbols": ["create_sequence_statement"]}, {"name": "statement_noprep", "symbols": ["alter_sequence_statement"]}, {"name": "statement_noprep", "symbols": ["drop_statement"]}, + {"name": "statement_noprep", "symbols": ["drop_trigger_statement"]}, {"name": "statement_noprep", "symbols": ["createtype_statement"]}, + {"name": "statement_noprep", "symbols": ["createdomain_statement"]}, {"name": "statement_noprep", "symbols": ["altertype_statement"]}, {"name": "statement_noprep", "symbols": ["create_view_statements"]}, {"name": "statement_noprep", "symbols": ["refresh_view_statements"]}, diff --git a/.deno/to-sql.ts b/.deno/to-sql.ts index 55e08e4..1b672c9 100644 --- a/.deno/to-sql.ts +++ b/.deno/to-sql.ts @@ -1,7 +1,7 @@ import { IAstPartialMapper, AstDefaultMapper } from './ast-mapper.ts'; import { astVisitor, IAstVisitor, IAstFullVisitor } from './ast-visitor.ts'; import { NotSupported, nil, ReplaceReturnType, NoExtraProperties } from './utils.ts'; -import { TableConstraint, JoinClause, ColumnConstraint, AlterSequenceStatement, CreateSequenceStatement, AlterSequenceSetOptions, CreateSequenceOptions, QName, SetGlobalValue, AlterColumnAddGenerated, QColumn, Name, OrderByStatement, QNameAliased } from './syntax/ast.ts'; +import { TableConstraint, JoinClause, ColumnConstraint, AlterSequenceStatement, CreateSequenceStatement, AlterSequenceSetOptions, CreateSequenceOptions, QName, SetGlobalValue, AlterColumnAddGenerated, QColumn, Name, OrderByStatement, QNameAliased, FrameBound } from './syntax/ast.ts'; import { literal } from './pg-escape.ts'; import { sqlKeywords } from './keywords.ts'; @@ -70,6 +70,12 @@ function addConstraint(c: ColumnConstraint | TableConstraint, m: IAstVisitor) { if (c.onUpdate) { ret.push(' ON UPDATE ', c.onUpdate); } + if (c.deferrable !== undefined) { + ret.push(c.deferrable ? ' DEFERRABLE' : ' NOT DEFERRABLE'); + } + if (c.initiallyDeferred !== undefined) { + ret.push(' INITIALLY ', c.initiallyDeferred ? 'DEFERRED' : 'IMMEDIATE'); + } break; case 'primary key': case 'unique': @@ -352,10 +358,46 @@ const visitor = astVisitor(m => ({ ret.push(' '); }, + createDomain: c => { + ret.push('CREATE DOMAIN '); + visitQualifiedName(c.name); + ret.push(' AS '); + m.dataType(c.dataType); + if (c.collate) { + ret.push(' COLLATE ', name(c.collate)); + } + if (c.default) { + ret.push(' DEFAULT '); + m.expr(c.default); + } + for (const cst of c.constraints ?? []) { + if (cst.constraintName) { + ret.push(' CONSTRAINT ', name(cst.constraintName)); + } + switch (cst.type) { + case 'not null': + ret.push(' NOT NULL'); + break; + case 'null': + ret.push(' NULL'); + break; + case 'check': + ret.push(' CHECK ('); + m.expr(cst.expr); + ret.push(')'); + break; + } + } + }, + setTableOwner: o => { ret.push(' OWNER TO ', name(o.to)); }, + setRowLevelSecurity: c => { + ret.push(' ', c.action.toUpperCase(), ' ROW LEVEL SECURITY'); + }, + alterColumnSimple: c => ret.push(c.type), @@ -425,6 +467,8 @@ const visitor = astVisitor(m => ({ return m.dropConstraint(change, table); case 'owner': return m.setTableOwner(change, table); + case 'row level security': + return m.setRowLevelSecurity(change, table); default: throw NotSupported.never(change); } @@ -489,6 +533,14 @@ const visitor = astVisitor(m => ({ ret.push(')'); }, + callPosition: p => { + ret.push('POSITION('); + m.expr(p.substring); + ret.push(' IN '); + m.expr(p.string); + ret.push(')'); + }, + binary: v => { m.expr(v.left); visitOp(v); @@ -527,6 +579,26 @@ const visitor = astVisitor(m => ({ visitOrderBy(m, v.over.orderBy); ret.push(' '); } + if (v.over.frame) { + const { unit, start, end } = v.over.frame; + ret.push(unit.toUpperCase(), ' '); + const bound = (b: FrameBound) => { + if (b.value) { + m.expr(b.value); + ret.push(' ', b.type.toUpperCase(), ' '); + } else { + ret.push(b.type.toUpperCase(), ' '); + } + }; + if (end) { + ret.push('BETWEEN '); + bound(start); + ret.push('AND '); + bound(end); + } else { + bound(start); + } + } ret.push(') '); } }, @@ -563,9 +635,14 @@ const visitor = astVisitor(m => ({ ret.push(c.value ? 'true' : 'false'); break; case 'integer': - ret.push(c.value.toString(10)); + // prefer the exact source digits when the JS number would lose precision + ret.push(c.valueText ?? c.value.toString(10)); break; case 'numeric': + if (c.valueText) { + ret.push(c.valueText); + break; + } ret.push(c.value.toString()); if (Number.isInteger(c.value)) { ret.push('.'); @@ -737,7 +814,7 @@ const visitor = astVisitor(m => ({ case undefined: case null: case 'array': - ret.push(' RETURNS '); + ret.push(c.setof ? ' RETURNS SETOF ' : ' RETURNS '); m.dataType(c.returns); break; default: @@ -807,11 +884,11 @@ const visitor = astVisitor(m => ({ }, withRecursive: val => { - ret.push('WITH RECURSIVE ' - , name(val.alias) - , '(' - , ...val.columnNames.map(name).join(', ') - , ') AS ('); + ret.push('WITH RECURSIVE ', name(val.alias)); + if (val.columnNames) { + ret.push('(', ...val.columnNames.map(name).join(', '), ')'); + } + ret.push(' AS ('); m.union(val.bind); ret.push(') '); m.statement(val.in); @@ -996,6 +1073,9 @@ const visitor = astVisitor(m => ({ ret.push(' INHERITS '); list(t.inherits, i => visitQualifiedName(i), true); } + if (t.tablespace) { + ret.push(' TABLESPACE ', name(t.tablespace)); + } }, likeTable: l => { @@ -1233,6 +1313,13 @@ const visitor = astVisitor(m => ({ }, member: e => { + if (e.op === '.') { + // composite field access: (operand).field + ret.push('('); + m.expr(e.operand); + ret.push(').', ident(e.member as string)); + return; + } m.expr(e.operand); ret.push(e.op); ret.push(typeof e.member === 'number' @@ -1414,6 +1501,105 @@ const visitor = astVisitor(m => ({ ret.push('SHOW ', name(s.variable)); }, + createRole: r => { + ret.push('CREATE ROLE ', name(r.name)); + const o = r.options; + if (o.superuser !== undefined) ret.push(o.superuser ? ' SUPERUSER' : ' NOSUPERUSER'); + if (o.login !== undefined) ret.push(o.login ? ' LOGIN' : ' NOLOGIN'); + if (o.bypassRls !== undefined) ret.push(o.bypassRls ? ' BYPASSRLS' : ' NOBYPASSRLS'); + }, + + setRole: r => { + ret.push('SET '); + if (r.scope) ret.push(r.scope.toUpperCase(), ' '); + ret.push('ROLE ', r.role ? name(r.role) : 'NONE'); + }, + + reset: r => { + ret.push('RESET ', r.identifier === 'all' ? 'ALL' : name(r.identifier)); + }, + + createPolicy: p => { + ret.push('CREATE POLICY ', name(p.name), ' ON '); + visitQualifiedName(p.table); + if (p.permissive !== undefined) { + ret.push(' AS ', p.permissive ? 'PERMISSIVE' : 'RESTRICTIVE'); + } + if (p.for) { + ret.push(' FOR ', p.for.toUpperCase()); + } + if (p.roles?.length) { + ret.push(' TO '); + list(p.roles, r => ret.push(name(r)), false); + } + if (p.using) { + ret.push(' USING ('); + m.expr(p.using); + ret.push(')'); + } + if (p.withCheck) { + ret.push(' WITH CHECK ('); + m.expr(p.withCheck); + ret.push(')'); + } + }, + + createTrigger: t => { + ret.push('CREATE ', t.constraint ? 'CONSTRAINT ' : '', 'TRIGGER ', name(t.name), ' ', t.timing.toUpperCase(), ' '); + ret.push(t.events.map(e => e.event.toUpperCase() + (e.columns ? ' OF ' + e.columns.map(name).join(', ') : '')).join(' OR ')); + ret.push(' ON '); + visitQualifiedName(t.table); + ret.push(' FOR EACH ', t.forEach.toUpperCase()); + if (t.when) { ret.push(' WHEN ('); m.expr(t.when); ret.push(')'); } + ret.push(' EXECUTE FUNCTION '); + visitQualifiedName(t.execute.function); + ret.push('('); + list(t.execute.arguments, a => m.expr(a), false); + ret.push(')'); + }, + + dropPolicy: p => { + ret.push('DROP POLICY '); + if (p.ifExists) { + ret.push('IF EXISTS '); + } + ret.push(name(p.name), ' ON '); + visitQualifiedName(p.table); + }, + + dropTrigger: t => { + ret.push('DROP TRIGGER '); + if (t.ifExists) { + ret.push('IF EXISTS '); + } + ret.push(name(t.name), ' ON '); + visitQualifiedName(t.onTable); + if (t.cascade) { + ret.push(' ', t.cascade.toUpperCase()); + } + }, + + grant: g => { + ret.push('GRANT ', g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' ON '); + list(g.on.names, n => visitQualifiedName(n), false); + ret.push(' TO '); + list(g.to, r => ret.push(name(r)), false); + if (g.withGrantOption) { + ret.push(' WITH GRANT OPTION'); + } + }, + + revoke: g => { + ret.push('REVOKE '); + if (g.grantOptionFor) { + ret.push('GRANT OPTION FOR '); + } + ret.push(g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' ON '); + list(g.on.names, n => visitQualifiedName(n), false); + ret.push(' FROM '); + list(g.from, r => ret.push(name(r)), false); + }, + prepare: s => { ret.push('PREPARE ', name(s.name)); if (s.args?.length) { @@ -1432,6 +1618,13 @@ const visitor = astVisitor(m => ({ ret.push('ALL') }, + execute: s => { + ret.push('EXECUTE ', name(s.name)); + if (s.args?.length) { + list(s.args, a => m.expr(a), true); + } + }, + arraySelect: s => { ret.push('array('); m.select(s.select); @@ -1487,7 +1680,14 @@ const visitor = astVisitor(m => ({ }, transaction: t => { - ret.push(t.type); + ret.push(t.type.toUpperCase()); + if (t.type === 'rollback' && t.to) { + ret.push(' TO ', name(t.to)); + } + if (t.type === 'savepoint' || t.type === 'release savepoint') { + ret.push(' ', name(t.name)); + } + ret.push(' '); }, unary: t => { From 467b636e3b283c5ea902db9f203099b66135d3a5 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 02:28:27 +0530 Subject: [PATCH 16/23] Add MERGE statement grammar + AST Parses PostgreSQL MERGE (PG 15+): MERGE INTO target [AS] alias USING source [AS] alias ON join_condition WHEN [NOT] MATCHED [AND cond] THEN { UPDATE SET ... | DELETE | INSERT [(cols)] VALUES (...) | INSERT DEFAULT VALUES | DO NOTHING } [...] - new MergeStatement / MergeAction / MergeAction{Update,Delete,Insert,DoNothing} AST - merge.ne grammar (reuses update_set_list, insert_expr_list_raw, select_from_subject) - kw_merge / kw_matched keywords - to-sql visitor + ast-mapper default recursion (merge) 803 tests pass (+4 merge round-trip specs); no grammar ambiguity introduced. Co-Authored-By: Claude Opus 4.8 --- .deno/ast-mapper.ts | 38 +++++++++++++++ .deno/syntax/ast.ts | 37 ++++++++++++++ .deno/syntax/main.ne.ts | 61 +++++++++++++++++++++++ .deno/to-sql.ts | 49 +++++++++++++++++++ src/ast-mapper.ts | 38 +++++++++++++++ src/syntax/ast.ts | 37 ++++++++++++++ src/syntax/base.ne | 2 + src/syntax/main.ne | 2 + src/syntax/merge.ne | 52 ++++++++++++++++++++ src/syntax/merge.spec.ts | 103 +++++++++++++++++++++++++++++++++++++++ src/to-sql.ts | 49 +++++++++++++++++++ 11 files changed, 468 insertions(+) create mode 100644 src/syntax/merge.ne create mode 100644 src/syntax/merge.spec.ts diff --git a/.deno/ast-mapper.ts b/.deno/ast-mapper.ts index 26a3e80..40f4637 100644 --- a/.deno/ast-mapper.ts +++ b/.deno/ast-mapper.ts @@ -6,6 +6,7 @@ import { nil, NotSupported, trimNullish } from './utils.ts'; export interface IAstPartialMapper { statement?: (val: a.Statement) => a.Statement | nil; update?: (val: a.UpdateStatement) => a.Statement | nil + merge?: (val: a.MergeStatement) => a.Statement | nil insert?: (val: a.InsertStatement) => a.Statement | nil delete?: (val: a.DeleteStatement) => a.Statement | nil comment?: (val: a.CommentStatement) => a.Statement | nil @@ -258,6 +259,8 @@ export class AstDefaultMapper implements IAstMapper { return this.selection(val); case 'update': return this.update(val); + case 'merge': + return this.merge(val); case 'create extension': return this.createExtension(val); case 'tablespace': @@ -568,6 +571,41 @@ export class AstDefaultMapper implements IAstMapper { } + merge(val: a.MergeStatement): a.Statement | nil { + const target = this.tableRef(val.target); + if (!target) { + return null; // nowhere to merge into + } + const source = this.from(val.source); + if (!source) { + return null; // nothing to merge from + } + const on = val.on && this.expr(val.on); + const actions = arrayNilMap(val.actions, a => { + const and = a.and && this.expr(a.and); + const then = a.then; + let newThen = then; + if (then.type === 'update') { + const sets = arrayNilMap(then.sets, x => this.set(x)); + if (!sets?.length) { + return null; // drop an update with no sets + } + newThen = assignChanged(then, { sets }); + } else if (then.type === 'insert' && then.values) { + const values = arrayNilMap(then.values, e => this.expr(e)); + newThen = assignChanged(then, { values }); + } + return assignChanged(a, { and, then: newThen }); + }); + return assignChanged(val, { + target, + source, + on, + actions, + }); + } + + insert(val: a.InsertStatement): a.Statement | nil { const into = this.tableRef(val.into); if (!into) { diff --git a/.deno/syntax/ast.ts b/.deno/syntax/ast.ts index 1ad3ca3..7cc7cc5 100644 --- a/.deno/syntax/ast.ts +++ b/.deno/syntax/ast.ts @@ -17,6 +17,7 @@ export type Statement = SelectStatement | CommitStatement | InsertStatement | UpdateStatement + | MergeStatement | ShowStatement | PrepareStatement | DeallocateStatement @@ -333,6 +334,42 @@ export interface InsertStatement extends PGNode { onConflict?: OnConflictAction | nil; } +export interface MergeStatement extends PGNode { + type: 'merge'; + target: QNameAliased; + source: From; + on: Expr; + actions: MergeAction[]; +} + +export interface MergeAction extends PGNode { + when: 'matched' | 'not matched'; + /** additional predicate after AND (e.g. WHEN MATCHED AND x > 0 THEN ...) */ + and?: Expr | nil; + then: MergeActionUpdate | MergeActionDelete | MergeActionInsert | MergeActionDoNothing; +} + +export interface MergeActionUpdate extends PGNode { + type: 'update'; + sets: SetStatement[]; +} + +export interface MergeActionDelete extends PGNode { + type: 'delete'; +} + +export interface MergeActionInsert extends PGNode { + type: 'insert'; + columns?: Name[] | nil; + /** VALUES (...) expressions; absent means DEFAULT VALUES */ + values?: Expr[] | nil; + overriding?: 'system' | 'user'; +} + +export interface MergeActionDoNothing extends PGNode { + type: 'do nothing'; +} + export interface OnConflictAction extends PGNode { on?: OnConflictOnExpr | OnConflictOnConstraint; do: 'do nothing' | { diff --git a/.deno/syntax/main.ne.ts b/.deno/syntax/main.ne.ts index ea64c9d..2a69f58 100644 --- a/.deno/syntax/main.ne.ts +++ b/.deno/syntax/main.ne.ts @@ -298,6 +298,16 @@ declare var kw_where: any; declare var kw_from: any; declare var kw_returning: any; declare var op_eq: any; +declare var kw_into: any; +declare var kw_using: any; +declare var kw_on: any; +declare var kw_when: any; +declare var kw_and: any; +declare var kw_then: any; +declare var kw_not: any; +declare var kw_do: any; +declare var kw_user: any; +declare var kw_default: any; declare var kw_table: any; declare var kw_only: any; declare var kw_to: any; @@ -570,6 +580,8 @@ const grammar: Grammar = { {"name": "kw_between", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('between')}, {"name": "kw_conflict", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('conflict')}, {"name": "kw_nothing", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('nothing')}, + {"name": "kw_merge", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('merge')}, + {"name": "kw_matched", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('matched')}, {"name": "kw_begin", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('begin')}, {"name": "kw_if", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('if')}, {"name": "kw_exists", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('exists')}, @@ -2652,6 +2664,54 @@ const grammar: Grammar = { value: unwrap(exprs[i]), }))) } }, + {"name": "merge_statement$ebnf$1", "symbols": ["merge_when"]}, + {"name": "merge_statement$ebnf$1", "symbols": ["merge_statement$ebnf$1", "merge_when"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "merge_statement", "symbols": ["kw_merge", (lexerAny.has("kw_into") ? {type: "kw_into"} : kw_into), "table_ref_aliased", (lexerAny.has("kw_using") ? {type: "kw_using"} : kw_using), "select_from_subject", (lexerAny.has("kw_on") ? {type: "kw_on"} : kw_on), "expr", "merge_statement$ebnf$1"], "postprocess": x => track(x, { + type: 'merge', + target: unwrap(x[2]), + source: unwrap(x[4]), + on: unwrap(x[6]), + actions: x[7], + }) }, + {"name": "merge_when$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("kw_and") ? {type: "kw_and"} : kw_and), "expr"], "postprocess": last}, + {"name": "merge_when$ebnf$1", "symbols": ["merge_when$ebnf$1$subexpression$1"], "postprocess": id}, + {"name": "merge_when$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "merge_when", "symbols": [(lexerAny.has("kw_when") ? {type: "kw_when"} : kw_when), "kw_matched", "merge_when$ebnf$1", (lexerAny.has("kw_then") ? {type: "kw_then"} : kw_then), "merge_matched_action"], "postprocess": x => track(x, { + when: 'matched', + ...x[2] ? { and: unwrap(x[2]) } : {}, + then: unwrap(x[4]), + }) }, + {"name": "merge_when$ebnf$2$subexpression$1", "symbols": [(lexerAny.has("kw_and") ? {type: "kw_and"} : kw_and), "expr"], "postprocess": last}, + {"name": "merge_when$ebnf$2", "symbols": ["merge_when$ebnf$2$subexpression$1"], "postprocess": id}, + {"name": "merge_when$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "merge_when", "symbols": [(lexerAny.has("kw_when") ? {type: "kw_when"} : kw_when), (lexerAny.has("kw_not") ? {type: "kw_not"} : kw_not), "kw_matched", "merge_when$ebnf$2", (lexerAny.has("kw_then") ? {type: "kw_then"} : kw_then), "merge_notmatched_action"], "postprocess": x => track(x, { + when: 'not matched', + ...x[3] ? { and: unwrap(x[3]) } : {}, + then: unwrap(x[5]), + }) }, + {"name": "merge_matched_action", "symbols": ["kw_update", "kw_set", "update_set_list"], "postprocess": x => track(x, { type: 'update', sets: x[2] })}, + {"name": "merge_matched_action", "symbols": ["kw_delete"], "postprocess": x => track(x, { type: 'delete' })}, + {"name": "merge_matched_action", "symbols": [(lexerAny.has("kw_do") ? {type: "kw_do"} : kw_do), "kw_nothing"], "postprocess": x => track(x, { type: 'do nothing' })}, + {"name": "merge_notmatched_action$ebnf$1", "symbols": ["collist_paren"], "postprocess": id}, + {"name": "merge_notmatched_action$ebnf$1", "symbols": [], "postprocess": () => null}, + {"name": "merge_notmatched_action$ebnf$2$subexpression$1$subexpression$1", "symbols": ["kw_system"]}, + {"name": "merge_notmatched_action$ebnf$2$subexpression$1$subexpression$1", "symbols": [(lexerAny.has("kw_user") ? {type: "kw_user"} : kw_user)]}, + {"name": "merge_notmatched_action$ebnf$2$subexpression$1", "symbols": ["kw_overriding", "merge_notmatched_action$ebnf$2$subexpression$1$subexpression$1", "kw_value"], "postprocess": get(1)}, + {"name": "merge_notmatched_action$ebnf$2", "symbols": ["merge_notmatched_action$ebnf$2$subexpression$1"], "postprocess": id}, + {"name": "merge_notmatched_action$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "merge_notmatched_action", "symbols": ["kw_insert", "merge_notmatched_action$ebnf$1", "merge_notmatched_action$ebnf$2", "merge_insert_values"], "postprocess": x => { + const columns = x[1] && x[1].map(asName); + const overriding = toStr(x[2]); + return track(x, { + type: 'insert', + ...columns ? { columns } : {}, + ...overriding ? { overriding } : {}, + ...x[3], + }); + } }, + {"name": "merge_notmatched_action", "symbols": [(lexerAny.has("kw_do") ? {type: "kw_do"} : kw_do), "kw_nothing"], "postprocess": x => track(x, { type: 'do nothing' })}, + {"name": "merge_insert_values", "symbols": ["kw_values", "lparen", "insert_expr_list_raw", "rparen"], "postprocess": x => ({ values: x[2] })}, + {"name": "merge_insert_values", "symbols": [(lexerAny.has("kw_default") ? {type: "kw_default"} : kw_default), "kw_values"], "postprocess": x => ({})}, {"name": "altertable_statement$ebnf$1", "symbols": ["kw_ifexists"], "postprocess": id}, {"name": "altertable_statement$ebnf$1", "symbols": [], "postprocess": () => null}, {"name": "altertable_statement$ebnf$2", "symbols": [(lexerAny.has("kw_only") ? {type: "kw_only"} : kw_only)], "postprocess": id}, @@ -3413,6 +3473,7 @@ const grammar: Grammar = { {"name": "statement_noprep", "symbols": ["simplestatements_all"]}, {"name": "statement_noprep", "symbols": ["insert_statement"]}, {"name": "statement_noprep", "symbols": ["update_statement"]}, + {"name": "statement_noprep", "symbols": ["merge_statement"]}, {"name": "statement_noprep", "symbols": ["altertable_statement"]}, {"name": "statement_noprep", "symbols": ["alterindex_statement"]}, {"name": "statement_noprep", "symbols": ["delete_statement"]}, diff --git a/.deno/to-sql.ts b/.deno/to-sql.ts index 1b672c9..d975cb9 100644 --- a/.deno/to-sql.ts +++ b/.deno/to-sql.ts @@ -1712,6 +1712,55 @@ const visitor = astVisitor(m => ({ } }, + merge: mg => { + ret.push('MERGE INTO '); + m.tableRef(mg.target); + ret.push(' USING '); + m.from(mg.source); + ret.push(' ON '); + m.expr(mg.on); + ret.push(' '); + for (const a of mg.actions) { + ret.push('WHEN ', a.when === 'not matched' ? 'NOT MATCHED' : 'MATCHED'); + if (a.and) { + ret.push(' AND '); + m.expr(a.and); + } + ret.push(' THEN '); + const then = a.then; + switch (then.type) { + case 'update': + ret.push('UPDATE SET '); + list(then.sets, s => m.set(s), false); + break; + case 'delete': + ret.push('DELETE'); + break; + case 'do nothing': + ret.push('DO NOTHING'); + break; + case 'insert': + ret.push('INSERT '); + if (then.columns) { + ret.push('(', then.columns.map(name).join(', '), ') '); + } + if (then.overriding) { + ret.push('OVERRIDING ', then.overriding.toUpperCase(), ' VALUE '); + } + if (then.values) { + ret.push('VALUES '); + list(then.values, e => m.expr(e), true); + } else { + ret.push('DEFAULT VALUES'); + } + break; + default: + throw NotSupported.never(then); + } + ret.push(' '); + } + }, + update: u => { ret.push('UPDATE '); m.tableRef(u.table); diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 86ca497..6dba41e 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -6,6 +6,7 @@ import { nil, NotSupported, trimNullish } from './utils'; export interface IAstPartialMapper { statement?: (val: a.Statement) => a.Statement | nil; update?: (val: a.UpdateStatement) => a.Statement | nil + merge?: (val: a.MergeStatement) => a.Statement | nil insert?: (val: a.InsertStatement) => a.Statement | nil delete?: (val: a.DeleteStatement) => a.Statement | nil comment?: (val: a.CommentStatement) => a.Statement | nil @@ -258,6 +259,8 @@ export class AstDefaultMapper implements IAstMapper { return this.selection(val); case 'update': return this.update(val); + case 'merge': + return this.merge(val); case 'create extension': return this.createExtension(val); case 'tablespace': @@ -568,6 +571,41 @@ export class AstDefaultMapper implements IAstMapper { } + merge(val: a.MergeStatement): a.Statement | nil { + const target = this.tableRef(val.target); + if (!target) { + return null; // nowhere to merge into + } + const source = this.from(val.source); + if (!source) { + return null; // nothing to merge from + } + const on = val.on && this.expr(val.on); + const actions = arrayNilMap(val.actions, a => { + const and = a.and && this.expr(a.and); + const then = a.then; + let newThen = then; + if (then.type === 'update') { + const sets = arrayNilMap(then.sets, x => this.set(x)); + if (!sets?.length) { + return null; // drop an update with no sets + } + newThen = assignChanged(then, { sets }); + } else if (then.type === 'insert' && then.values) { + const values = arrayNilMap(then.values, e => this.expr(e)); + newThen = assignChanged(then, { values }); + } + return assignChanged(a, { and, then: newThen }); + }); + return assignChanged(val, { + target, + source, + on, + actions, + }); + } + + insert(val: a.InsertStatement): a.Statement | nil { const into = this.tableRef(val.into); if (!into) { diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index dfb90ea..51367b6 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -17,6 +17,7 @@ export type Statement = SelectStatement | CommitStatement | InsertStatement | UpdateStatement + | MergeStatement | ShowStatement | PrepareStatement | DeallocateStatement @@ -333,6 +334,42 @@ export interface InsertStatement extends PGNode { onConflict?: OnConflictAction | nil; } +export interface MergeStatement extends PGNode { + type: 'merge'; + target: QNameAliased; + source: From; + on: Expr; + actions: MergeAction[]; +} + +export interface MergeAction extends PGNode { + when: 'matched' | 'not matched'; + /** additional predicate after AND (e.g. WHEN MATCHED AND x > 0 THEN ...) */ + and?: Expr | nil; + then: MergeActionUpdate | MergeActionDelete | MergeActionInsert | MergeActionDoNothing; +} + +export interface MergeActionUpdate extends PGNode { + type: 'update'; + sets: SetStatement[]; +} + +export interface MergeActionDelete extends PGNode { + type: 'delete'; +} + +export interface MergeActionInsert extends PGNode { + type: 'insert'; + columns?: Name[] | nil; + /** VALUES (...) expressions; absent means DEFAULT VALUES */ + values?: Expr[] | nil; + overriding?: 'system' | 'user'; +} + +export interface MergeActionDoNothing extends PGNode { + type: 'do nothing'; +} + export interface OnConflictAction extends PGNode { on?: OnConflictOnExpr | OnConflictOnConstraint; do: 'do nothing' | { diff --git a/src/syntax/base.ne b/src/syntax/base.ne index f846dbd..71619e6 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -169,6 +169,8 @@ collist -> ident (comma ident {% last %}):* {% ([head, tail]) => { kw_between -> %word {% notReservedKw('between') %} kw_conflict -> %word {% notReservedKw('conflict') %} kw_nothing -> %word {% notReservedKw('nothing') %} +kw_merge -> %word {% notReservedKw('merge') %} +kw_matched -> %word {% notReservedKw('matched') %} kw_begin -> %word {% notReservedKw('begin') %} kw_if -> %word {% notReservedKw('if') %} kw_exists -> %word {% notReservedKw('exists') %} diff --git a/src/syntax/main.ne b/src/syntax/main.ne index 5544a0d..58ef8e7 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -17,6 +17,7 @@ import {lexerAny} from '../lexer'; @include "simple-statements.ne" @include "insert.ne" @include "update.ne" +@include "merge.ne" @include "alter-table.ne" @include "alter-index.ne" @include "delete.ne" @@ -64,6 +65,7 @@ statement_noprep | simplestatements_all | insert_statement | update_statement + | merge_statement | altertable_statement | alterindex_statement | delete_statement diff --git a/src/syntax/merge.ne b/src/syntax/merge.ne new file mode 100644 index 0000000..c58c6b8 --- /dev/null +++ b/src/syntax/merge.ne @@ -0,0 +1,52 @@ +@lexer lexerAny +@include "base.ne" +@include "expr.ne" +@include "select.ne" +@include "insert.ne" +@include "update.ne" + +merge_statement -> kw_merge %kw_into table_ref_aliased + %kw_using select_from_subject + %kw_on expr + merge_when:+ + {% x => track(x, { + type: 'merge', + target: unwrap(x[2]), + source: unwrap(x[4]), + on: unwrap(x[6]), + actions: x[7], + }) %} + +merge_when + -> %kw_when kw_matched (%kw_and expr {% last %}):? %kw_then merge_matched_action {% x => track(x, { + when: 'matched', + ...x[2] ? { and: unwrap(x[2]) } : {}, + then: unwrap(x[4]), + }) %} + | %kw_when %kw_not kw_matched (%kw_and expr {% last %}):? %kw_then merge_notmatched_action {% x => track(x, { + when: 'not matched', + ...x[3] ? { and: unwrap(x[3]) } : {}, + then: unwrap(x[5]), + }) %} + +merge_matched_action + -> kw_update kw_set update_set_list {% x => track(x, { type: 'update', sets: x[2] }) %} + | kw_delete {% x => track(x, { type: 'delete' }) %} + | %kw_do kw_nothing {% x => track(x, { type: 'do nothing' }) %} + +merge_notmatched_action + -> kw_insert collist_paren:? (kw_overriding (kw_system | %kw_user) kw_value {% get(1) %}):? merge_insert_values {% x => { + const columns = x[1] && x[1].map(asName); + const overriding = toStr(x[2]); + return track(x, { + type: 'insert', + ...columns ? { columns } : {}, + ...overriding ? { overriding } : {}, + ...x[3], + }); + } %} + | %kw_do kw_nothing {% x => track(x, { type: 'do nothing' }) %} + +merge_insert_values + -> kw_values lparen insert_expr_list_raw rparen {% x => ({ values: x[2] }) %} + | %kw_default kw_values {% x => ({}) %} diff --git a/src/syntax/merge.spec.ts b/src/syntax/merge.spec.ts new file mode 100644 index 0000000..e42bfc7 --- /dev/null +++ b/src/syntax/merge.spec.ts @@ -0,0 +1,103 @@ +import 'mocha'; +import 'chai'; +import { checkStatement } from './spec-utils'; + +describe('Merge', () => { + + checkStatement([`merge into target t using source s on t.id = s.id + when matched then update set v = s.v + when not matched then insert (id, v) values (s.id, s.v)`], { + type: 'merge', + target: { name: 'target', alias: 't' }, + source: { type: 'table', name: { name: 'source', alias: 's' } }, + on: { + type: 'binary', + op: '=', + left: { type: 'ref', table: { name: 't' }, name: 'id' }, + right: { type: 'ref', table: { name: 's' }, name: 'id' }, + }, + actions: [{ + when: 'matched', + then: { + type: 'update', + sets: [{ column: { name: 'v' }, value: { type: 'ref', table: { name: 's' }, name: 'v' } }], + }, + }, { + when: 'not matched', + then: { + type: 'insert', + columns: [{ name: 'id' }, { name: 'v' }], + values: [ + { type: 'ref', table: { name: 's' }, name: 'id' }, + { type: 'ref', table: { name: 's' }, name: 'v' }, + ], + }, + }], + }); + + checkStatement([`merge into t using s on t.id = s.id + when matched and s.deleted then delete + when matched then update set v = s.v`], { + type: 'merge', + target: { name: 't' }, + source: { type: 'table', name: { name: 's' } }, + on: { + type: 'binary', + op: '=', + left: { type: 'ref', table: { name: 't' }, name: 'id' }, + right: { type: 'ref', table: { name: 's' }, name: 'id' }, + }, + actions: [{ + when: 'matched', + and: { type: 'ref', table: { name: 's' }, name: 'deleted' }, + then: { type: 'delete' }, + }, { + when: 'matched', + then: { + type: 'update', + sets: [{ column: { name: 'v' }, value: { type: 'ref', table: { name: 's' }, name: 'v' } }], + }, + }], + }); + + checkStatement([`merge into t using (select 1 as id) s on t.id = s.id + when not matched then do nothing`], { + type: 'merge', + target: { name: 't' }, + source: { + type: 'statement', + statement: { + type: 'select', + columns: [{ expr: { type: 'integer', value: 1 }, alias: { name: 'id' } }], + }, + alias: 's', + }, + on: { + type: 'binary', + op: '=', + left: { type: 'ref', table: { name: 't' }, name: 'id' }, + right: { type: 'ref', table: { name: 's' }, name: 'id' }, + }, + actions: [{ + when: 'not matched', + then: { type: 'do nothing' }, + }], + }); + + checkStatement([`merge into t using s on t.a = s.a + when not matched then insert default values`], { + type: 'merge', + target: { name: 't' }, + source: { type: 'table', name: { name: 's' } }, + on: { + type: 'binary', + op: '=', + left: { type: 'ref', table: { name: 't' }, name: 'a' }, + right: { type: 'ref', table: { name: 's' }, name: 'a' }, + }, + actions: [{ + when: 'not matched', + then: { type: 'insert' }, + }], + }); +}); diff --git a/src/to-sql.ts b/src/to-sql.ts index bb45df6..b99391f 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1712,6 +1712,55 @@ const visitor = astVisitor(m => ({ } }, + merge: mg => { + ret.push('MERGE INTO '); + m.tableRef(mg.target); + ret.push(' USING '); + m.from(mg.source); + ret.push(' ON '); + m.expr(mg.on); + ret.push(' '); + for (const a of mg.actions) { + ret.push('WHEN ', a.when === 'not matched' ? 'NOT MATCHED' : 'MATCHED'); + if (a.and) { + ret.push(' AND '); + m.expr(a.and); + } + ret.push(' THEN '); + const then = a.then; + switch (then.type) { + case 'update': + ret.push('UPDATE SET '); + list(then.sets, s => m.set(s), false); + break; + case 'delete': + ret.push('DELETE'); + break; + case 'do nothing': + ret.push('DO NOTHING'); + break; + case 'insert': + ret.push('INSERT '); + if (then.columns) { + ret.push('(', then.columns.map(name).join(', '), ') '); + } + if (then.overriding) { + ret.push('OVERRIDING ', then.overriding.toUpperCase(), ' VALUE '); + } + if (then.values) { + ret.push('VALUES '); + list(then.values, e => m.expr(e), true); + } else { + ret.push('DEFAULT VALUES'); + } + break; + default: + throw NotSupported.never(then); + } + ret.push(' '); + } + }, + update: u => { ret.push('UPDATE '); m.tableRef(u.table); From 2ee2410d19028e742a5a55e8bc3564b61a3545dc Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 03:06:27 +0530 Subject: [PATCH 17/23] Add declarative partitioning grammar (PARTITION BY / PARTITION OF) Parses PostgreSQL declarative partitioning: CREATE TABLE t (...) PARTITION BY {RANGE|LIST|HASH} (cols) CREATE TABLE child PARTITION OF parent FOR VALUES { FROM (..) TO (..) | IN (..) | WITH (MODULUS m, REMAINDER r) } | DEFAULT - new PartitionBy / PartitionOf / PartitionBound* AST on CreateTableStatement - create-table.ne: PARTITION BY clause + a second createtable_statement alternative for PARTITION OF; bare MINVALUE/MAXVALUE in a range bound are recognized in post-processing (avoids grammar ambiguity with column refs) - kw_list / kw_hash / kw_modulus / kw_remainder keywords - to-sql + ast-mapper support (mapper no longer drops a column-less partition child) 810 tests pass (+7 partition round-trip specs); no grammar ambiguity introduced. Co-Authored-By: Claude Opus 4.8 --- .deno/ast-mapper.ts | 4 +- .deno/syntax/ast.ts | 38 +++++++++++++++++ .deno/syntax/main.ne.ts | 66 +++++++++++++++++++++++++---- .deno/to-sql.ts | 76 ++++++++++++++++++++++++--------- src/ast-mapper.ts | 4 +- src/syntax/ast.ts | 38 +++++++++++++++++ src/syntax/base.ne | 4 ++ src/syntax/create-table.ne | 55 +++++++++++++++++++++++- src/syntax/partition.spec.ts | 81 ++++++++++++++++++++++++++++++++++++ src/to-sql.ts | 76 ++++++++++++++++++++++++--------- 10 files changed, 391 insertions(+), 51 deletions(-) create mode 100644 src/syntax/partition.spec.ts diff --git a/.deno/ast-mapper.ts b/.deno/ast-mapper.ts index 40f4637..e396daf 100644 --- a/.deno/ast-mapper.ts +++ b/.deno/ast-mapper.ts @@ -700,11 +700,11 @@ export class AstDefaultMapper implements IAstMapper { throw NotSupported.never(col); } }) - if (!columns?.length) { + if (!columns?.length && !val.partitionOf) { return null; // no column to create } return assignChanged(val, { - columns, + columns: columns ?? [], }); } diff --git a/.deno/syntax/ast.ts b/.deno/syntax/ast.ts index 7cc7cc5..c4c022f 100644 --- a/.deno/syntax/ast.ts +++ b/.deno/syntax/ast.ts @@ -616,6 +616,44 @@ export interface CreateTableStatement extends PGNode { constraints?: TableConstraint[]; inherits?: QName[]; tablespace?: Name; + /** `PARTITION BY {RANGE|LIST|HASH} (cols)` — makes this a partitioned parent */ + partitionBy?: PartitionBy; + /** `PARTITION OF parent FOR VALUES …` — makes this a partition of `parent` */ + partitionOf?: PartitionOf; +} + +export interface PartitionBy extends PGNode { + strategy: 'range' | 'list' | 'hash'; + columns: Expr[]; +} + +export interface PartitionOf extends PGNode { + parent: QName; + bound: PartitionBound; +} + +export type PartitionBound + = PartitionBoundRange + | PartitionBoundList + | PartitionBoundHash + | PartitionBoundDefault; + +export interface PartitionBoundRange extends PGNode { + type: 'range'; + from: (Expr | 'minvalue' | 'maxvalue')[]; + to: (Expr | 'minvalue' | 'maxvalue')[]; +} +export interface PartitionBoundList extends PGNode { + type: 'list'; + values: Expr[]; +} +export interface PartitionBoundHash extends PGNode { + type: 'hash'; + modulus: number; + remainder: number; +} +export interface PartitionBoundDefault extends PGNode { + type: 'default'; } export interface CreateColumnsLikeTable extends PGNode { diff --git a/.deno/syntax/main.ne.ts b/.deno/syntax/main.ne.ts index 2a69f58..e0fc773 100644 --- a/.deno/syntax/main.ne.ts +++ b/.deno/syntax/main.ne.ts @@ -205,6 +205,13 @@ declare var kw_placing: any; declare var rparen: any; declare var kw_create: any; declare var kw_table: any; +declare var comma: any; +declare var kw_for: any; +declare var kw_from: any; +declare var kw_to: any; +declare var kw_in: any; +declare var kw_with: any; +declare var kw_default: any; declare var kw_constraint: any; declare var kw_unique: any; declare var kw_check: any; @@ -216,11 +223,9 @@ declare var kw_not: any; declare var kw_deferrable: any; declare var kw_initially: any; declare var kw_null: any; -declare var kw_default: any; declare var kw_like: any; declare var kw_all: any; declare var kw_collate: any; -declare var comma: any; declare var kw_create: any; declare var kw_unique: any; declare var kw_concurrently: any; @@ -505,6 +510,16 @@ import {track, box, unbox, doubleQuoted} from '../lexer.ts'; } +// bare `minvalue`/`maxvalue` in a range partition bound parse as column refs; +// convert them to the special sentinel strings. +function partitionBoundVal(e: any) { + if (e && e.type === 'ref' && !e.table && (e.name === 'minvalue' || e.name === 'maxvalue')) { + return e.name; + } + return e; +} + + function mergeRoleOptions(opts: any[]) { return Object.assign({}, ...opts); } @@ -709,6 +724,10 @@ const grammar: Grammar = { {"name": "kw_materialized", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('materialized')}, {"name": "kw_partial", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('partial')}, {"name": "kw_partition", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('partition')}, + {"name": "kw_list", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('list')}, + {"name": "kw_hash", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('hash')}, + {"name": "kw_modulus", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('modulus')}, + {"name": "kw_remainder", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('remainder')}, {"name": "kw_simple", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('simple')}, {"name": "kw_generated", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('generated')}, {"name": "kw_always", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('always')}, @@ -1884,11 +1903,13 @@ const grammar: Grammar = { {"name": "createtable_statement$ebnf$1", "symbols": [], "postprocess": () => null}, {"name": "createtable_statement$ebnf$2", "symbols": ["kw_ifnotexists"], "postprocess": id}, {"name": "createtable_statement$ebnf$2", "symbols": [], "postprocess": () => null}, - {"name": "createtable_statement$ebnf$3", "symbols": ["createtable_opts"], "postprocess": id}, + {"name": "createtable_statement$ebnf$3", "symbols": ["createtable_partitionby"], "postprocess": id}, {"name": "createtable_statement$ebnf$3", "symbols": [], "postprocess": () => null}, - {"name": "createtable_statement$ebnf$4", "symbols": ["createtable_tablespace"], "postprocess": id}, + {"name": "createtable_statement$ebnf$4", "symbols": ["createtable_opts"], "postprocess": id}, {"name": "createtable_statement$ebnf$4", "symbols": [], "postprocess": () => null}, - {"name": "createtable_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "createtable_statement$ebnf$1", (lexerAny.has("kw_table") ? {type: "kw_table"} : kw_table), "createtable_statement$ebnf$2", "qname", "lparen", "createtable_declarationlist", "rparen", "createtable_statement$ebnf$3", "createtable_statement$ebnf$4"], "postprocess": x => { + {"name": "createtable_statement$ebnf$5", "symbols": ["createtable_tablespace"], "postprocess": id}, + {"name": "createtable_statement$ebnf$5", "symbols": [], "postprocess": () => null}, + {"name": "createtable_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "createtable_statement$ebnf$1", (lexerAny.has("kw_table") ? {type: "kw_table"} : kw_table), "createtable_statement$ebnf$2", "qname", "lparen", "createtable_declarationlist", "rparen", "createtable_statement$ebnf$3", "createtable_statement$ebnf$4", "createtable_statement$ebnf$5"], "postprocess": x => { const cols = x[6].filter((v: any) => 'kind' in v); const constraints = x[6].filter((v: any) => !('kind' in v)); @@ -1900,10 +1921,41 @@ const grammar: Grammar = { columns: cols, ...unwrap(x[1]), ...constraints.length ? { constraints } : {}, - ...x[8], - ...x[9] ? { tablespace: x[9] } : {}, + ...x[8] ? { partitionBy: x[8] } : {}, + ...x[9], + ...x[10] ? { tablespace: x[10] } : {}, }); } }, + {"name": "createtable_statement$ebnf$6", "symbols": ["createtable_modifiers"], "postprocess": id}, + {"name": "createtable_statement$ebnf$6", "symbols": [], "postprocess": () => null}, + {"name": "createtable_statement$ebnf$7", "symbols": ["kw_ifnotexists"], "postprocess": id}, + {"name": "createtable_statement$ebnf$7", "symbols": [], "postprocess": () => null}, + {"name": "createtable_statement$ebnf$8", "symbols": ["createtable_partitionby"], "postprocess": id}, + {"name": "createtable_statement$ebnf$8", "symbols": [], "postprocess": () => null}, + {"name": "createtable_statement", "symbols": [(lexerAny.has("kw_create") ? {type: "kw_create"} : kw_create), "createtable_statement$ebnf$6", (lexerAny.has("kw_table") ? {type: "kw_table"} : kw_table), "createtable_statement$ebnf$7", "qname", "kw_partition", "kw_of", "qname", "createtable_partition_bound", "createtable_statement$ebnf$8"], "postprocess": x => track(x, { + type: 'create table', + ... !!x[3] ? { ifNotExists: true } : {}, + name: x[4], + columns: [], + ...unwrap(x[1]), + partitionOf: track(x, { parent: x[7], bound: x[8] }), + ...x[9] ? { partitionBy: x[9] } : {}, + }) }, + {"name": "createtable_partitionby$macrocall$2", "symbols": ["expr"]}, + {"name": "createtable_partitionby$macrocall$1$ebnf$1", "symbols": []}, + {"name": "createtable_partitionby$macrocall$1$ebnf$1$subexpression$1", "symbols": [(lexerAny.has("comma") ? {type: "comma"} : comma), "createtable_partitionby$macrocall$2"], "postprocess": last}, + {"name": "createtable_partitionby$macrocall$1$ebnf$1", "symbols": ["createtable_partitionby$macrocall$1$ebnf$1", "createtable_partitionby$macrocall$1$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "createtable_partitionby$macrocall$1", "symbols": ["createtable_partitionby$macrocall$2", "createtable_partitionby$macrocall$1$ebnf$1"], "postprocess": ([head, tail]) => { + return [unwrap(head), ...(tail.map(unwrap) || [])]; + } }, + {"name": "createtable_partitionby", "symbols": ["kw_partition", "kw_by", "createtable_partition_strategy", "lparen", "createtable_partitionby$macrocall$1", "rparen"], "postprocess": x => track(x, { strategy: x[2], columns: x[4] })}, + {"name": "createtable_partition_strategy", "symbols": ["kw_range"], "postprocess": () => 'range'}, + {"name": "createtable_partition_strategy", "symbols": ["kw_list"], "postprocess": () => 'list'}, + {"name": "createtable_partition_strategy", "symbols": ["kw_hash"], "postprocess": () => 'hash'}, + {"name": "createtable_partition_bound", "symbols": [(lexerAny.has("kw_for") ? {type: "kw_for"} : kw_for), "kw_values", (lexerAny.has("kw_from") ? {type: "kw_from"} : kw_from), "lparen", "expr_list_raw", "rparen", (lexerAny.has("kw_to") ? {type: "kw_to"} : kw_to), "lparen", "expr_list_raw", "rparen"], "postprocess": x => track(x, { type: 'range', from: x[4].map(partitionBoundVal), to: x[8].map(partitionBoundVal) })}, + {"name": "createtable_partition_bound", "symbols": [(lexerAny.has("kw_for") ? {type: "kw_for"} : kw_for), "kw_values", (lexerAny.has("kw_in") ? {type: "kw_in"} : kw_in), "lparen", "expr_list_raw", "rparen"], "postprocess": x => track(x, { type: 'list', values: x[4] })}, + {"name": "createtable_partition_bound", "symbols": [(lexerAny.has("kw_for") ? {type: "kw_for"} : kw_for), "kw_values", (lexerAny.has("kw_with") ? {type: "kw_with"} : kw_with), "lparen", "kw_modulus", "int", "comma", "kw_remainder", "int", "rparen"], "postprocess": x => track(x, { type: 'hash', modulus: unbox(x[5]), remainder: unbox(x[8]) })}, + {"name": "createtable_partition_bound", "symbols": [(lexerAny.has("kw_default") ? {type: "kw_default"} : kw_default)], "postprocess": x => track(x, { type: 'default' })}, {"name": "createtable_tablespace", "symbols": ["kw_tablespace", "ident"], "postprocess": x => asName(last(x))}, {"name": "createtable_modifiers", "symbols": ["kw_unlogged"], "postprocess": x => x[0] ? { unlogged: true } : {}}, {"name": "createtable_modifiers", "symbols": ["m_locglob"]}, diff --git a/.deno/to-sql.ts b/.deno/to-sql.ts index d975cb9..1a77312 100644 --- a/.deno/to-sql.ts +++ b/.deno/to-sql.ts @@ -1047,28 +1047,66 @@ const visitor = astVisitor(m => ({ } ret.push(t.ifNotExists ? 'TABLE IF NOT EXISTS ' : 'TABLE '); m.tableRef(t.name); - ret.push('('); - list(t.columns, c => { - switch (c.kind) { - case 'column': - return m.createColumn(c); - case 'like table': - return m.likeTable(c); - default: - throw NotSupported.never(c); + if (t.partitionOf) { + ret.push(' PARTITION OF '); + visitQualifiedName(t.partitionOf.parent); + ret.push(' '); + const b = t.partitionOf.bound; + const boundVal = (v: any) => { + if (v === 'minvalue') { ret.push('MINVALUE'); } + else if (v === 'maxvalue') { ret.push('MAXVALUE'); } + else { m.expr(v); } + }; + switch (b.type) { + case 'range': + ret.push('FOR VALUES FROM ('); + b.from.forEach((v, i) => { if (i) { ret.push(', '); } boundVal(v); }); + ret.push(') TO ('); + b.to.forEach((v, i) => { if (i) { ret.push(', '); } boundVal(v); }); + ret.push(')'); + break; + case 'list': + ret.push('FOR VALUES IN ('); + list(b.values, e => m.expr(e), false); + ret.push(')'); + break; + case 'hash': + ret.push(`FOR VALUES WITH (MODULUS ${b.modulus}, REMAINDER ${b.remainder})`); + break; + case 'default': + ret.push('DEFAULT'); + break; } - }, false); - if (t.constraints) { - ret.push(', '); - list(t.constraints, c => { - const cname = c.constraintName; - if (cname) { - ret.push('CONSTRAINT ', name(cname), ' '); + ret.push(' '); + } else { + ret.push('('); + list(t.columns, c => { + switch (c.kind) { + case 'column': + return m.createColumn(c); + case 'like table': + return m.likeTable(c); + default: + throw NotSupported.never(c); } - addConstraint(c, m); - }, false) + }, false); + if (t.constraints) { + ret.push(', '); + list(t.constraints, c => { + const cname = c.constraintName; + if (cname) { + ret.push('CONSTRAINT ', name(cname), ' '); + } + addConstraint(c, m); + }, false) + } + ret.push(') '); + } + if (t.partitionBy) { + ret.push(' PARTITION BY ', t.partitionBy.strategy.toUpperCase(), ' ('); + list(t.partitionBy.columns, e => m.expr(e), false); + ret.push(')'); } - ret.push(') '); if (t.inherits?.length) { ret.push(' INHERITS '); list(t.inherits, i => visitQualifiedName(i), true); diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 6dba41e..f626f65 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -700,11 +700,11 @@ export class AstDefaultMapper implements IAstMapper { throw NotSupported.never(col); } }) - if (!columns?.length) { + if (!columns?.length && !val.partitionOf) { return null; // no column to create } return assignChanged(val, { - columns, + columns: columns ?? [], }); } diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 51367b6..a41a44a 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -616,6 +616,44 @@ export interface CreateTableStatement extends PGNode { constraints?: TableConstraint[]; inherits?: QName[]; tablespace?: Name; + /** `PARTITION BY {RANGE|LIST|HASH} (cols)` — makes this a partitioned parent */ + partitionBy?: PartitionBy; + /** `PARTITION OF parent FOR VALUES …` — makes this a partition of `parent` */ + partitionOf?: PartitionOf; +} + +export interface PartitionBy extends PGNode { + strategy: 'range' | 'list' | 'hash'; + columns: Expr[]; +} + +export interface PartitionOf extends PGNode { + parent: QName; + bound: PartitionBound; +} + +export type PartitionBound + = PartitionBoundRange + | PartitionBoundList + | PartitionBoundHash + | PartitionBoundDefault; + +export interface PartitionBoundRange extends PGNode { + type: 'range'; + from: (Expr | 'minvalue' | 'maxvalue')[]; + to: (Expr | 'minvalue' | 'maxvalue')[]; +} +export interface PartitionBoundList extends PGNode { + type: 'list'; + values: Expr[]; +} +export interface PartitionBoundHash extends PGNode { + type: 'hash'; + modulus: number; + remainder: number; +} +export interface PartitionBoundDefault extends PGNode { + type: 'default'; } export interface CreateColumnsLikeTable extends PGNode { diff --git a/src/syntax/base.ne b/src/syntax/base.ne index 71619e6..d9287a8 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -298,6 +298,10 @@ kw_option -> %word {% notReservedKw('option') %} kw_materialized -> %word {% notReservedKw('materialized') %} kw_partial -> %word {% notReservedKw('partial') %} kw_partition -> %word {% notReservedKw('partition') %} +kw_list -> %word {% notReservedKw('list') %} +kw_hash -> %word {% notReservedKw('hash') %} +kw_modulus -> %word {% notReservedKw('modulus') %} +kw_remainder -> %word {% notReservedKw('remainder') %} kw_simple -> %word {% notReservedKw('simple') %} kw_generated -> %word {% notReservedKw('generated') %} kw_always -> %word {% notReservedKw('always') %} diff --git a/src/syntax/create-table.ne b/src/syntax/create-table.ne index 2ada8fb..920ed0f 100644 --- a/src/syntax/create-table.ne +++ b/src/syntax/create-table.ne @@ -1,5 +1,17 @@ @lexer lexerAny @include "base.ne" +@include "expr.ne" + +@{% +// bare `minvalue`/`maxvalue` in a range partition bound parse as column refs; +// convert them to the special sentinel strings. +function partitionBoundVal(e: any) { + if (e && e.type === 'ref' && !e.table && (e.name === 'minvalue' || e.name === 'maxvalue')) { + return e.name; + } + return e; +} +%} array_of[EXP] -> $EXP (%comma $EXP {% last %}):* {% ([head, tail]) => { @@ -15,6 +27,7 @@ createtable_statement -> %kw_create lparen createtable_declarationlist rparen + createtable_partitionby:? createtable_opts:? createtable_tablespace:? {% x => { @@ -29,11 +42,49 @@ createtable_statement -> %kw_create columns: cols, ...unwrap(x[1]), ...constraints.length ? { constraints } : {}, - ...x[8], - ...x[9] ? { tablespace: x[9] } : {}, + ...x[8] ? { partitionBy: x[8] } : {}, + ...x[9], + ...x[10] ? { tablespace: x[10] } : {}, }); } %} +# `CREATE TABLE child PARTITION OF parent FOR VALUES ...` +createtable_statement -> %kw_create + createtable_modifiers:? + %kw_table + kw_ifnotexists:? + qname + kw_partition kw_of qname + createtable_partition_bound + createtable_partitionby:? + {% x => track(x, { + type: 'create table', + ... !!x[3] ? { ifNotExists: true } : {}, + name: x[4], + columns: [], + ...unwrap(x[1]), + partitionOf: track(x, { parent: x[7], bound: x[8] }), + ...x[9] ? { partitionBy: x[9] } : {}, + }) %} + +createtable_partitionby + -> kw_partition kw_by createtable_partition_strategy lparen array_of[expr] rparen + {% x => track(x, { strategy: x[2], columns: x[4] }) %} + +createtable_partition_strategy + -> kw_range {% () => 'range' %} + | kw_list {% () => 'list' %} + | kw_hash {% () => 'hash' %} + +createtable_partition_bound + -> %kw_for kw_values %kw_from lparen expr_list_raw rparen %kw_to lparen expr_list_raw rparen + {% x => track(x, { type: 'range', from: x[4].map(partitionBoundVal), to: x[8].map(partitionBoundVal) }) %} + | %kw_for kw_values %kw_in lparen expr_list_raw rparen + {% x => track(x, { type: 'list', values: x[4] }) %} + | %kw_for kw_values %kw_with lparen kw_modulus int comma kw_remainder int rparen + {% x => track(x, { type: 'hash', modulus: unbox(x[5]), remainder: unbox(x[8]) }) %} + | %kw_default {% x => track(x, { type: 'default' }) %} + createtable_tablespace -> kw_tablespace ident {% x => asName(last(x)) %} diff --git a/src/syntax/partition.spec.ts b/src/syntax/partition.spec.ts new file mode 100644 index 0000000..b7a3b93 --- /dev/null +++ b/src/syntax/partition.spec.ts @@ -0,0 +1,81 @@ +import 'mocha'; +import 'chai'; +import { checkStatement } from './spec-utils'; + +describe('Partitioning', () => { + + checkStatement([`create table t (id int, d date) partition by range (d)`], { + type: 'create table', + name: { name: 't' }, + columns: [ + { kind: 'column', name: { name: 'id' }, dataType: { name: 'int' } }, + { kind: 'column', name: { name: 'd' }, dataType: { name: 'date' } }, + ], + partitionBy: { strategy: 'range', columns: [{ type: 'ref', name: 'd' }] }, + }); + + checkStatement([`create table t (id int) partition by list (id)`], { + type: 'create table', + name: { name: 't' }, + columns: [{ kind: 'column', name: { name: 'id' }, dataType: { name: 'int' } }], + partitionBy: { strategy: 'list', columns: [{ type: 'ref', name: 'id' }] }, + }); + + checkStatement([`create table t_p1 partition of t for values from (1) to (10)`], { + type: 'create table', + name: { name: 't_p1' }, + columns: [], + partitionOf: { + parent: { name: 't' }, + bound: { + type: 'range', + from: [{ type: 'integer', value: 1 }], + to: [{ type: 'integer', value: 10 }], + }, + }, + }); + + checkStatement([`create table t_q1 partition of t for values in (1, 2, 3)`], { + type: 'create table', + name: { name: 't_q1' }, + columns: [], + partitionOf: { + parent: { name: 't' }, + bound: { + type: 'list', + values: [ + { type: 'integer', value: 1 }, + { type: 'integer', value: 2 }, + { type: 'integer', value: 3 }, + ], + }, + }, + }); + + checkStatement([`create table t_h1 partition of t for values with (modulus 4, remainder 0)`], { + type: 'create table', + name: { name: 't_h1' }, + columns: [], + partitionOf: { + parent: { name: 't' }, + bound: { type: 'hash', modulus: 4, remainder: 0 }, + }, + }); + + checkStatement([`create table t_def partition of t default`], { + type: 'create table', + name: { name: 't_def' }, + columns: [], + partitionOf: { parent: { name: 't' }, bound: { type: 'default' } }, + }); + + checkStatement([`create table t_r partition of t for values from (minvalue) to (maxvalue)`], { + type: 'create table', + name: { name: 't_r' }, + columns: [], + partitionOf: { + parent: { name: 't' }, + bound: { type: 'range', from: ['minvalue'], to: ['maxvalue'] }, + }, + }); +}); diff --git a/src/to-sql.ts b/src/to-sql.ts index b99391f..6682716 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1047,28 +1047,66 @@ const visitor = astVisitor(m => ({ } ret.push(t.ifNotExists ? 'TABLE IF NOT EXISTS ' : 'TABLE '); m.tableRef(t.name); - ret.push('('); - list(t.columns, c => { - switch (c.kind) { - case 'column': - return m.createColumn(c); - case 'like table': - return m.likeTable(c); - default: - throw NotSupported.never(c); + if (t.partitionOf) { + ret.push(' PARTITION OF '); + visitQualifiedName(t.partitionOf.parent); + ret.push(' '); + const b = t.partitionOf.bound; + const boundVal = (v: any) => { + if (v === 'minvalue') { ret.push('MINVALUE'); } + else if (v === 'maxvalue') { ret.push('MAXVALUE'); } + else { m.expr(v); } + }; + switch (b.type) { + case 'range': + ret.push('FOR VALUES FROM ('); + b.from.forEach((v, i) => { if (i) { ret.push(', '); } boundVal(v); }); + ret.push(') TO ('); + b.to.forEach((v, i) => { if (i) { ret.push(', '); } boundVal(v); }); + ret.push(')'); + break; + case 'list': + ret.push('FOR VALUES IN ('); + list(b.values, e => m.expr(e), false); + ret.push(')'); + break; + case 'hash': + ret.push(`FOR VALUES WITH (MODULUS ${b.modulus}, REMAINDER ${b.remainder})`); + break; + case 'default': + ret.push('DEFAULT'); + break; } - }, false); - if (t.constraints) { - ret.push(', '); - list(t.constraints, c => { - const cname = c.constraintName; - if (cname) { - ret.push('CONSTRAINT ', name(cname), ' '); + ret.push(' '); + } else { + ret.push('('); + list(t.columns, c => { + switch (c.kind) { + case 'column': + return m.createColumn(c); + case 'like table': + return m.likeTable(c); + default: + throw NotSupported.never(c); } - addConstraint(c, m); - }, false) + }, false); + if (t.constraints) { + ret.push(', '); + list(t.constraints, c => { + const cname = c.constraintName; + if (cname) { + ret.push('CONSTRAINT ', name(cname), ' '); + } + addConstraint(c, m); + }, false) + } + ret.push(') '); + } + if (t.partitionBy) { + ret.push(' PARTITION BY ', t.partitionBy.strategy.toUpperCase(), ' ('); + list(t.partitionBy.columns, e => m.expr(e), false); + ret.push(')'); } - ret.push(') '); if (t.inherits?.length) { ret.push(' INHERITS '); list(t.inherits, i => visitQualifiedName(i), true); From 5a02858610a9f4fc7ab3158fec20ab3c12b416c9 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 03:15:46 +0530 Subject: [PATCH 18/23] Support INTERSECT and EXCEPT set operations Extends the UNION grammar/AST to the full set-operation family: INTERSECT / INTERSECT ALL / EXCEPT / EXCEPT ALL. - SelectFromUnion.type widened to a SetOperationType union - union.ne accepts %kw_intersect / %kw_except alongside %kw_union - to-sql + ast-mapper handle the new types (same code path as UNION) 814 tests pass (+4 round-trip specs); no grammar ambiguity introduced. Co-Authored-By: Claude Opus 4.8 --- .deno/ast-mapper.ts | 16 ++++++++++++++++ .deno/syntax/ast.ts | 6 +++++- .deno/syntax/main.ne.ts | 7 ++++++- .deno/to-sql.ts | 4 +++- src/ast-mapper.ts | 16 ++++++++++++++++ src/syntax/ast.ts | 6 +++++- src/syntax/union.ne | 2 +- src/syntax/union.spec.ts | 24 ++++++++++++++++++++++++ src/to-sql.ts | 4 +++- 9 files changed, 79 insertions(+), 6 deletions(-) diff --git a/.deno/ast-mapper.ts b/.deno/ast-mapper.ts index e396daf..833e17a 100644 --- a/.deno/ast-mapper.ts +++ b/.deno/ast-mapper.ts @@ -206,6 +206,10 @@ function withAccepts(val: a.Statement | nil): val is a.WithStatementBinding { case 'update': case 'union': case 'union all': + case 'intersect': + case 'intersect all': + case 'except': + case 'except all': case 'with': return true; default: @@ -311,6 +315,10 @@ export class AstDefaultMapper implements IAstMapper { return this.createDomain(val); case 'union': case 'union all': + case 'intersect': + case 'intersect all': + case 'except': + case 'except all': return this.union(val); case 'show': return this.show(val); @@ -1042,6 +1050,10 @@ export class AstDefaultMapper implements IAstMapper { return this.selection(val); case 'union': case 'union all': + case 'intersect': + case 'intersect all': + case 'except': + case 'except all': return this.union(val); case 'with': return this.with(val); @@ -1266,6 +1278,10 @@ export class AstDefaultMapper implements IAstMapper { case 'select': case 'union': case 'union all': + case 'intersect': + case 'intersect all': + case 'except': + case 'except all': case 'with': case 'with recursive': return this.select(val); diff --git a/.deno/syntax/ast.ts b/.deno/syntax/ast.ts index c4c022f..2e0e981 100644 --- a/.deno/syntax/ast.ts +++ b/.deno/syntax/ast.ts @@ -819,8 +819,12 @@ export interface SelectFromStatement extends PGNode { skip?: SkipClause; } +export type SetOperationType = 'union' | 'union all' + | 'intersect' | 'intersect all' + | 'except' | 'except all'; + export interface SelectFromUnion extends PGNode { - type: 'union' | 'union all', + type: SetOperationType, left: SelectStatement; right: SelectStatement; } diff --git a/.deno/syntax/main.ne.ts b/.deno/syntax/main.ne.ts index e0fc773..b0bfad5 100644 --- a/.deno/syntax/main.ne.ts +++ b/.deno/syntax/main.ne.ts @@ -348,6 +348,8 @@ declare var kw_check: any; declare var kw_default: any; declare var kw_to: any; declare var kw_union: any; +declare var kw_intersect: any; +declare var kw_except: any; declare var kw_all: any; declare var kw_as: any; declare var kw_all: any; @@ -3215,9 +3217,12 @@ const grammar: Grammar = { {"name": "union_left", "symbols": ["selection_paren"]}, {"name": "union_right", "symbols": ["selection"]}, {"name": "union_right", "symbols": ["selection_paren"]}, + {"name": "union_statement$subexpression$1$subexpression$1", "symbols": [(lexerAny.has("kw_union") ? {type: "kw_union"} : kw_union)]}, + {"name": "union_statement$subexpression$1$subexpression$1", "symbols": [(lexerAny.has("kw_intersect") ? {type: "kw_intersect"} : kw_intersect)]}, + {"name": "union_statement$subexpression$1$subexpression$1", "symbols": [(lexerAny.has("kw_except") ? {type: "kw_except"} : kw_except)]}, {"name": "union_statement$subexpression$1$ebnf$1", "symbols": [(lexerAny.has("kw_all") ? {type: "kw_all"} : kw_all)], "postprocess": id}, {"name": "union_statement$subexpression$1$ebnf$1", "symbols": [], "postprocess": () => null}, - {"name": "union_statement$subexpression$1", "symbols": [(lexerAny.has("kw_union") ? {type: "kw_union"} : kw_union), "union_statement$subexpression$1$ebnf$1"]}, + {"name": "union_statement$subexpression$1", "symbols": ["union_statement$subexpression$1$subexpression$1", "union_statement$subexpression$1$ebnf$1"]}, {"name": "union_statement", "symbols": ["union_left", "union_statement$subexpression$1", "union_right"], "postprocess": x => { return track(x, { type: toStr(x[1], ' '), diff --git a/.deno/to-sql.ts b/.deno/to-sql.ts index 1a77312..1b8b5c1 100644 --- a/.deno/to-sql.ts +++ b/.deno/to-sql.ts @@ -1673,7 +1673,9 @@ const visitor = astVisitor(m => ({ ret.push('('); m.statement(s.left); ret.push(') ', s.type.toUpperCase(), ' '); - if (s.right.type === 'union' || s.right.type === 'union all') { + if (s.right.type === 'union' || s.right.type === 'union all' + || s.right.type === 'intersect' || s.right.type === 'intersect all' + || s.right.type === 'except' || s.right.type === 'except all') { m.union(s.right); } else { ret.push('('); diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index f626f65..86e757a 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -206,6 +206,10 @@ function withAccepts(val: a.Statement | nil): val is a.WithStatementBinding { case 'update': case 'union': case 'union all': + case 'intersect': + case 'intersect all': + case 'except': + case 'except all': case 'with': return true; default: @@ -311,6 +315,10 @@ export class AstDefaultMapper implements IAstMapper { return this.createDomain(val); case 'union': case 'union all': + case 'intersect': + case 'intersect all': + case 'except': + case 'except all': return this.union(val); case 'show': return this.show(val); @@ -1042,6 +1050,10 @@ export class AstDefaultMapper implements IAstMapper { return this.selection(val); case 'union': case 'union all': + case 'intersect': + case 'intersect all': + case 'except': + case 'except all': return this.union(val); case 'with': return this.with(val); @@ -1266,6 +1278,10 @@ export class AstDefaultMapper implements IAstMapper { case 'select': case 'union': case 'union all': + case 'intersect': + case 'intersect all': + case 'except': + case 'except all': case 'with': case 'with recursive': return this.select(val); diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index a41a44a..46a4044 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -819,8 +819,12 @@ export interface SelectFromStatement extends PGNode { skip?: SkipClause; } +export type SetOperationType = 'union' | 'union all' + | 'intersect' | 'intersect all' + | 'except' | 'except all'; + export interface SelectFromUnion extends PGNode { - type: 'union' | 'union all', + type: SetOperationType, left: SelectStatement; right: SelectStatement; } diff --git a/src/syntax/union.ne b/src/syntax/union.ne index 5767231..17db9e0 100644 --- a/src/syntax/union.ne +++ b/src/syntax/union.ne @@ -9,7 +9,7 @@ union_left -> select_statement union_right -> selection | selection_paren -union_statement -> union_left (%kw_union %kw_all:?) union_right {% x => { +union_statement -> union_left ((%kw_union | %kw_intersect | %kw_except) %kw_all:?) union_right {% x => { return track(x, { type: toStr(x[1], ' '), left: unwrap(x[0]), diff --git a/src/syntax/union.spec.ts b/src/syntax/union.spec.ts index 52616b5..4a50612 100644 --- a/src/syntax/union.spec.ts +++ b/src/syntax/union.spec.ts @@ -122,4 +122,28 @@ describe('Union statement', () => { left: {type: 'values', values: [[int(1)]]}, right: {type: 'values', values: [[int(2)]]}, }); + + checkSelect(`values (1) intersect values (2)`, { + type: 'intersect', + left: {type: 'values', values: [[int(1)]]}, + right: {type: 'values', values: [[int(2)]]}, + }); + + checkSelect(`values (1) intersect all values (2)`, { + type: 'intersect all', + left: {type: 'values', values: [[int(1)]]}, + right: {type: 'values', values: [[int(2)]]}, + }); + + checkSelect(`values (1) except values (2)`, { + type: 'except', + left: {type: 'values', values: [[int(1)]]}, + right: {type: 'values', values: [[int(2)]]}, + }); + + checkSelect(`values (1) except all values (2)`, { + type: 'except all', + left: {type: 'values', values: [[int(1)]]}, + right: {type: 'values', values: [[int(2)]]}, + }); }); \ No newline at end of file diff --git a/src/to-sql.ts b/src/to-sql.ts index 6682716..ccc9970 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1673,7 +1673,9 @@ const visitor = astVisitor(m => ({ ret.push('('); m.statement(s.left); ret.push(') ', s.type.toUpperCase(), ' '); - if (s.right.type === 'union' || s.right.type === 'union all') { + if (s.right.type === 'union' || s.right.type === 'union all' + || s.right.type === 'intersect' || s.right.type === 'intersect all' + || s.right.type === 'except' || s.right.type === 'except all') { m.union(s.right); } else { ret.push('('); From db5776bc2d0a91e33da3732dfb95c445ffa874e7 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 04:23:52 +0530 Subject: [PATCH 19/23] Support IS DISTINCT FROM / IS NOT DISTINCT FROM Adds the null-safe comparison operators to the grammar (a new alternative in `expr_is` producing a binary expr with op 'IS DISTINCT FROM' / 'IS NOT DISTINCT FROM'; the right operand also accepts a parenthesized expression). EqualityOperator widened accordingly; to-sql renders the op verbatim. 816 tests pass (+2 specs); no grammar ambiguity introduced. Co-Authored-By: Claude Opus 4.8 --- .deno/syntax/ast.ts | 2 +- .deno/syntax/main.ne.ts | 12 ++++++++++++ src/syntax/ast.ts | 2 +- src/syntax/expr.ne | 6 ++++++ src/syntax/expr.spec.ts | 14 ++++++++++++++ 5 files changed, 34 insertions(+), 2 deletions(-) diff --git a/.deno/syntax/ast.ts b/.deno/syntax/ast.ts index 2e0e981..ea8b177 100644 --- a/.deno/syntax/ast.ts +++ b/.deno/syntax/ast.ts @@ -983,7 +983,7 @@ export interface ExprPosition extends PGNode { // === https://www.postgresql.org/docs/12/functions.html export type LogicOperator = 'OR' | 'AND'; -export type EqualityOperator = 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE' | '=' | '!='; +export type EqualityOperator = 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE' | '=' | '!=' | 'IS DISTINCT FROM' | 'IS NOT DISTINCT FROM'; // see https://www.postgresql.org/docs/12/functions-math.html export type MathOpsBinary = '|' | '&' | '>>' | '^' | '#' | '<<' | '>>'; export type ComparisonOperator = '>' | '>=' | '<' | '<=' | '@>' | '<@' | '?' | '?|' | '?&' | '#>' | '#>>' | '~' | '~*' | '!~' | '!~*' | '@@'; diff --git a/.deno/syntax/main.ne.ts b/.deno/syntax/main.ne.ts index b0bfad5..db13e3b 100644 --- a/.deno/syntax/main.ne.ts +++ b/.deno/syntax/main.ne.ts @@ -1345,6 +1345,18 @@ const grammar: Grammar = { .toUpperCase(), operand: unwrap(x[0]), }) }, + {"name": "expr_is$subexpression$7", "symbols": ["expr_is"]}, + {"name": "expr_is$subexpression$7", "symbols": ["expr_paren"]}, + {"name": "expr_is$ebnf$2", "symbols": [(lexerAny.has("kw_not") ? {type: "kw_not"} : kw_not)], "postprocess": id}, + {"name": "expr_is$ebnf$2", "symbols": [], "postprocess": () => null}, + {"name": "expr_is$subexpression$8", "symbols": ["expr_compare"]}, + {"name": "expr_is$subexpression$8", "symbols": ["expr_paren"]}, + {"name": "expr_is", "symbols": ["expr_is$subexpression$7", (lexerAny.has("kw_is") ? {type: "kw_is"} : kw_is), "expr_is$ebnf$2", (lexerAny.has("kw_distinct") ? {type: "kw_distinct"} : kw_distinct), (lexerAny.has("kw_from") ? {type: "kw_from"} : kw_from), "expr_is$subexpression$8"], "postprocess": x => track(x, { + type: 'binary', + op: x[2] ? 'IS NOT DISTINCT FROM' : 'IS DISTINCT FROM', + left: unwrap(x[0]), + right: unwrap(x[5]), + }) }, {"name": "expr_is", "symbols": ["expr_compare"], "postprocess": unwrap}, {"name": "expr_compare$macrocall$2$macrocall$2", "symbols": [(lexerAny.has("op_compare") ? {type: "op_compare"} : op_compare)]}, {"name": "expr_compare$macrocall$2$macrocall$1$macrocall$2", "symbols": ["expr_compare$macrocall$2$macrocall$2"]}, diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 46a4044..3a2d0e6 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -983,7 +983,7 @@ export interface ExprPosition extends PGNode { // === https://www.postgresql.org/docs/12/functions.html export type LogicOperator = 'OR' | 'AND'; -export type EqualityOperator = 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE' | '=' | '!='; +export type EqualityOperator = 'IN' | 'NOT IN' | 'LIKE' | 'NOT LIKE' | 'ILIKE' | 'NOT ILIKE' | '=' | '!=' | 'IS DISTINCT FROM' | 'IS NOT DISTINCT FROM'; // see https://www.postgresql.org/docs/12/functions-math.html export type MathOpsBinary = '|' | '&' | '>>' | '^' | '#' | '<<' | '>>'; export type ComparisonOperator = '>' | '>=' | '<' | '<=' | '@>' | '<@' | '?' | '?|' | '?&' | '#>' | '#>>' | '~' | '~*' | '!~' | '!~*' | '@@'; diff --git a/src/syntax/expr.ne b/src/syntax/expr.ne index e445324..c24823d 100644 --- a/src/syntax/expr.ne +++ b/src/syntax/expr.ne @@ -84,6 +84,12 @@ expr_is .toUpperCase(), operand: unwrap(x[0]), }) %} + | (expr_is | expr_paren) %kw_is %kw_not:? %kw_distinct %kw_from (expr_compare | expr_paren) {% x => track(x, { + type: 'binary', + op: x[2] ? 'IS NOT DISTINCT FROM' : 'IS DISTINCT FROM', + left: unwrap(x[0]), + right: unwrap(x[5]), + }) %} | expr_compare {% unwrap %} diff --git a/src/syntax/expr.spec.ts b/src/syntax/expr.spec.ts index f9e28df..90e9c5c 100644 --- a/src/syntax/expr.spec.ts +++ b/src/syntax/expr.spec.ts @@ -1488,6 +1488,20 @@ line`, columns: [{ expr: { type: 'integer', value: 1 } }], }, }) + + checkTreeExpr(['a is distinct from b'], { + type: 'binary', + op: 'IS DISTINCT FROM', + left: { type: 'ref', name: 'a' }, + right: { type: 'ref', name: 'b' }, + }); + + checkTreeExpr(['a is not distinct from b'], { + type: 'binary', + op: 'IS NOT DISTINCT FROM', + left: { type: 'ref', name: 'a' }, + right: { type: 'ref', name: 'b' }, + }); }); From aa8440e051ad879b6f41fa7e211656ac308e2024 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 04:33:30 +0530 Subject: [PATCH 20/23] Support week/decade/century/millennium interval units The interval-literal lexer only recognized year..millisecond units. Adds week, decade, century, and millennium; they are normalized in buildInterval (week -> 7 days, decade/century/millennium -> 10/100/1000 years), matching Postgres. Mixed forms like '2 weeks 3 days' work (normalization happens after the unit-uniqueness check). 816 tests pass. Co-Authored-By: Claude Opus 4.8 --- .deno/literal-syntaxes/interval-builder.ts | 13 ++++++++++++- .deno/literal-syntaxes/interval-lexer.ts | 4 ++++ .deno/literal-syntaxes/interval.ne.ts | 8 ++++++++ src/literal-syntaxes/interval-builder.ts | 13 ++++++++++++- src/literal-syntaxes/interval-lexer.ts | 4 ++++ src/literal-syntaxes/interval.ne | 2 +- 6 files changed, 41 insertions(+), 3 deletions(-) diff --git a/.deno/literal-syntaxes/interval-builder.ts b/.deno/literal-syntaxes/interval-builder.ts index 2a02e76..dd0fc0d 100644 --- a/.deno/literal-syntaxes/interval-builder.ts +++ b/.deno/literal-syntaxes/interval-builder.ts @@ -23,12 +23,23 @@ function* unwrap(k: K): IterableIterator { } } +// weeks/decades/centuries/millenniums are normalized to days/years, as Postgres does +const unitConversions: { [k: string]: [keyof Interval, number] } = { + weeks: ['days', 7], + decades: ['years', 10], + centuries: ['years', 100], + millenniums: ['years', 1000], +}; + export function buildInterval(orig: string, vals: 'invalid' | K): Interval { const ret: Interval = {}; if (vals === 'invalid') { throw new Error(`invalid input syntax for type interval: "${orig}"`) } - for (const [k, v] of unwrap(vals)) { + for (const [k0, v0] of unwrap(vals)) { + const conv = unitConversions[k0 as string]; + const k = conv ? conv[0] : k0; + const v = conv ? v0 * conv[1] : v0; ret[k] = (ret[k] ?? 0) + v; } return ret; diff --git a/.deno/literal-syntaxes/interval-lexer.ts b/.deno/literal-syntaxes/interval-lexer.ts index 9dc5ebf..97b2dc5 100644 --- a/.deno/literal-syntaxes/interval-lexer.ts +++ b/.deno/literal-syntaxes/interval-lexer.ts @@ -5,8 +5,12 @@ export const lexer = compile({ int: /\d+/, neg: '-', dot: '.', + millenniums: /(?:millennium|millenniums|millennia)\b/, + centuries: /(?:century|centuries)\b/, + decades: /decades?\b/, years: /(?:y|yrs?|years?)\b/, months: /(?:mon(?:th)?s?)\b/, + weeks: /weeks?\b/, days: /(?:d|days?)\b/, hours: /(?:h|hrs?|hours?)\b/, minutes: /(?:m|mins?|minutes?)\b/, diff --git a/.deno/literal-syntaxes/interval.ne.ts b/.deno/literal-syntaxes/interval.ne.ts index ccc3d17..7741666 100644 --- a/.deno/literal-syntaxes/interval.ne.ts +++ b/.deno/literal-syntaxes/interval.ne.ts @@ -5,11 +5,15 @@ function id(d: any[]): any { return d[0]; } declare var years: any; declare var months: any; +declare var weeks: any; declare var days: any; declare var hours: any; declare var minutes: any; declare var seconds: any; declare var milliseconds: any; +declare var decades: any; +declare var centuries: any; +declare var millenniums: any; declare var int: any; declare var neg: any; declare var dot: any; @@ -69,11 +73,15 @@ const grammar: Grammar = { } }, {"name": "unit", "symbols": [(lexerAny.has("years") ? {type: "years"} : years)]}, {"name": "unit", "symbols": [(lexerAny.has("months") ? {type: "months"} : months)]}, + {"name": "unit", "symbols": [(lexerAny.has("weeks") ? {type: "weeks"} : weeks)]}, {"name": "unit", "symbols": [(lexerAny.has("days") ? {type: "days"} : days)]}, {"name": "unit", "symbols": [(lexerAny.has("hours") ? {type: "hours"} : hours)]}, {"name": "unit", "symbols": [(lexerAny.has("minutes") ? {type: "minutes"} : minutes)]}, {"name": "unit", "symbols": [(lexerAny.has("seconds") ? {type: "seconds"} : seconds)]}, {"name": "unit", "symbols": [(lexerAny.has("milliseconds") ? {type: "milliseconds"} : milliseconds)]}, + {"name": "unit", "symbols": [(lexerAny.has("decades") ? {type: "decades"} : decades)]}, + {"name": "unit", "symbols": [(lexerAny.has("centuries") ? {type: "centuries"} : centuries)]}, + {"name": "unit", "symbols": [(lexerAny.has("millenniums") ? {type: "millenniums"} : millenniums)]}, {"name": "num", "symbols": ["int"]}, {"name": "num", "symbols": ["float"]}, {"name": "uint", "symbols": [(lexerAny.has("int") ? {type: "int"} : int)], "postprocess": ([x]) => parseInt(x, 10)}, diff --git a/src/literal-syntaxes/interval-builder.ts b/src/literal-syntaxes/interval-builder.ts index 0c7eb4d..b66bc67 100644 --- a/src/literal-syntaxes/interval-builder.ts +++ b/src/literal-syntaxes/interval-builder.ts @@ -23,12 +23,23 @@ function* unwrap(k: K): IterableIterator { } } +// weeks/decades/centuries/millenniums are normalized to days/years, as Postgres does +const unitConversions: { [k: string]: [keyof Interval, number] } = { + weeks: ['days', 7], + decades: ['years', 10], + centuries: ['years', 100], + millenniums: ['years', 1000], +}; + export function buildInterval(orig: string, vals: 'invalid' | K): Interval { const ret: Interval = {}; if (vals === 'invalid') { throw new Error(`invalid input syntax for type interval: "${orig}"`) } - for (const [k, v] of unwrap(vals)) { + for (const [k0, v0] of unwrap(vals)) { + const conv = unitConversions[k0 as string]; + const k = conv ? conv[0] : k0; + const v = conv ? v0 * conv[1] : v0; ret[k] = (ret[k] ?? 0) + v; } return ret; diff --git a/src/literal-syntaxes/interval-lexer.ts b/src/literal-syntaxes/interval-lexer.ts index 0e41b77..30e6900 100644 --- a/src/literal-syntaxes/interval-lexer.ts +++ b/src/literal-syntaxes/interval-lexer.ts @@ -5,8 +5,12 @@ export const lexer = compile({ int: /\d+/, neg: '-', dot: '.', + millenniums: /(?:millennium|millenniums|millennia)\b/, + centuries: /(?:century|centuries)\b/, + decades: /decades?\b/, years: /(?:y|yrs?|years?)\b/, months: /(?:mon(?:th)?s?)\b/, + weeks: /weeks?\b/, days: /(?:d|days?)\b/, hours: /(?:h|hrs?|hours?)\b/, minutes: /(?:m|mins?|minutes?)\b/, diff --git a/src/literal-syntaxes/interval.ne b/src/literal-syntaxes/interval.ne index 9327999..d68dd4f 100644 --- a/src/literal-syntaxes/interval.ne +++ b/src/literal-syntaxes/interval.ne @@ -29,7 +29,7 @@ elt -> time | num unit {% ([[n], u]) => { } %} -unit -> %years | %months | %days | %hours | %minutes | %seconds | %milliseconds +unit -> %years | %months | %weeks | %days | %hours | %minutes | %seconds | %milliseconds | %decades | %centuries | %millenniums num -> int | float uint -> %int {% ([x]) => parseInt(x, 10) %} From 9abd9310a649ae9f735ac6524a12ac6d859d11e1 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 04:51:58 +0530 Subject: [PATCH 21/23] Support GROUP BY GROUPING SETS (...) Parses `GROUP BY GROUPING SETS ( element, ... )` where an element is a bare expression, a parenthesized column group, or an empty group `()` (grand total). Emitted as a `grouping sets` call in the groupBy list (alongside the existing rollup/cube calls). The grammar stays unambiguous by leaning on the fact that `(a)` / `(a,b)` already parse as expressions; only `()` needs a dedicated rule. - kw_grouping / kw_sets keywords - select_groupby now takes a group_by_list of grouping_sets_call | expr 816 tests pass; no grammar ambiguity introduced. Co-Authored-By: Claude Opus 4.8 --- .deno/syntax/main.ne.ts | 20 +++++++++++++++++++- src/syntax/base.ne | 2 ++ src/syntax/select.ne | 20 +++++++++++++++++++- 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/.deno/syntax/main.ne.ts b/.deno/syntax/main.ne.ts index db13e3b..2f266ac 100644 --- a/.deno/syntax/main.ne.ts +++ b/.deno/syntax/main.ne.ts @@ -726,6 +726,8 @@ const grammar: Grammar = { {"name": "kw_materialized", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('materialized')}, {"name": "kw_partial", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('partial')}, {"name": "kw_partition", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('partition')}, + {"name": "kw_grouping", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('grouping')}, + {"name": "kw_sets", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('sets')}, {"name": "kw_list", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('list')}, {"name": "kw_hash", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('hash')}, {"name": "kw_modulus", "symbols": [(lexerAny.has("word") ? {type: "word"} : word)], "postprocess": notReservedKw('modulus')}, @@ -1162,7 +1164,23 @@ const grammar: Grammar = { {"name": "select_distinct$ebnf$1", "symbols": [], "postprocess": () => null}, {"name": "select_distinct", "symbols": [(lexerAny.has("kw_distinct") ? {type: "kw_distinct"} : kw_distinct), "select_distinct$ebnf$1"], "postprocess": x => box(x, x[1] || 'distinct')}, {"name": "select_where", "symbols": [(lexerAny.has("kw_where") ? {type: "kw_where"} : kw_where), "expr"], "postprocess": last}, - {"name": "select_groupby", "symbols": [(lexerAny.has("kw_group") ? {type: "kw_group"} : kw_group), "kw_by", "expr_list_raw"], "postprocess": last}, + {"name": "select_groupby", "symbols": [(lexerAny.has("kw_group") ? {type: "kw_group"} : kw_group), "kw_by", "group_by_list"], "postprocess": last}, + {"name": "group_by_list$ebnf$1", "symbols": []}, + {"name": "group_by_list$ebnf$1$subexpression$1", "symbols": ["comma", "group_by_elt"], "postprocess": last}, + {"name": "group_by_list$ebnf$1", "symbols": ["group_by_list$ebnf$1", "group_by_list$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "group_by_list", "symbols": ["group_by_elt", "group_by_list$ebnf$1"], "postprocess": ([head, tail]) => [head, ...(tail || [])]}, + {"name": "group_by_elt", "symbols": ["grouping_sets_call"], "postprocess": unwrap}, + {"name": "group_by_elt", "symbols": ["expr_list_item"], "postprocess": unwrap}, + {"name": "grouping_sets_call$ebnf$1", "symbols": []}, + {"name": "grouping_sets_call$ebnf$1$subexpression$1", "symbols": ["comma", "grouping_set"], "postprocess": last}, + {"name": "grouping_sets_call$ebnf$1", "symbols": ["grouping_sets_call$ebnf$1", "grouping_sets_call$ebnf$1$subexpression$1"], "postprocess": (d) => d[0].concat([d[1]])}, + {"name": "grouping_sets_call", "symbols": ["kw_grouping", "kw_sets", "lparen", "grouping_set", "grouping_sets_call$ebnf$1", "rparen"], "postprocess": x => track(x, { + type: 'call', + function: { name: 'grouping sets' }, + args: [x[3], ...(x[4] || [])], + }) }, + {"name": "grouping_set", "symbols": ["lparen", "rparen"], "postprocess": x => track(x, { type: 'list', expressions: [] })}, + {"name": "grouping_set", "symbols": ["expr"], "postprocess": unwrap}, {"name": "select_having", "symbols": [(lexerAny.has("kw_having") ? {type: "kw_having"} : kw_having), "expr"], "postprocess": last}, {"name": "select_limit_offset$ebnf$1$subexpression$1", "symbols": ["select_offset"]}, {"name": "select_limit_offset$ebnf$1$subexpression$1", "symbols": ["select_limit"]}, diff --git a/src/syntax/base.ne b/src/syntax/base.ne index d9287a8..ad7b07d 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -298,6 +298,8 @@ kw_option -> %word {% notReservedKw('option') %} kw_materialized -> %word {% notReservedKw('materialized') %} kw_partial -> %word {% notReservedKw('partial') %} kw_partition -> %word {% notReservedKw('partition') %} +kw_grouping -> %word {% notReservedKw('grouping') %} +kw_sets -> %word {% notReservedKw('sets') %} kw_list -> %word {% notReservedKw('list') %} kw_hash -> %word {% notReservedKw('hash') %} kw_modulus -> %word {% notReservedKw('modulus') %} diff --git a/src/syntax/select.ne b/src/syntax/select.ne index 638c29c..71feccb 100644 --- a/src/syntax/select.ne +++ b/src/syntax/select.ne @@ -166,7 +166,25 @@ select_distinct select_where -> %kw_where expr {% last %} -select_groupby -> %kw_group kw_by expr_list_raw {% last %} +select_groupby -> %kw_group kw_by group_by_list {% last %} + +group_by_list -> group_by_elt (comma group_by_elt {% last %}):* {% ([head, tail]) => [head, ...(tail || [])] %} + +group_by_elt -> grouping_sets_call {% unwrap %} | expr_list_item {% unwrap %} + +# GROUPING SETS ( element, ... ) where element is a parenthesized column group, +# an empty group (grand total), or a bare expression +grouping_sets_call -> kw_grouping kw_sets lparen grouping_set (comma grouping_set {% last %}):* rparen {% x => track(x, { + type: 'call', + function: { name: 'grouping sets' }, + args: [x[3], ...(x[4] || [])], +}) %} + +# a parenthesized group already parses as an expr ((a) -> a, (a,b) -> a list), so only +# the empty group () needs a dedicated rule; this keeps the grammar unambiguous +grouping_set + -> lparen rparen {% x => track(x, { type: 'list', expressions: [] }) %} + | expr {% unwrap %} select_having -> %kw_having expr {% last %} From 4a3c663784ed293af8cca3b7711e41f6eaa9db3d Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 12:46:12 +0530 Subject: [PATCH 22/23] feat: GRANT/role DDL, NOTIFY/LISTEN, ALTER COLUMN USING, CREATE INDEX INCLUDE, SECURITY, comment tolerance Parser surface needed to run a full Supabase-style bootstrap + real migrations: - GRANT/REVOKE on schema/database/function/sequence + ALL ... IN SCHEMA, ALTER ROLE, ALTER DEFAULT PRIVILEGES (parsed; engine treats as no-ops) - NOTIFY / LISTEN / UNLISTEN statements - COMMENT ON POLICY / FUNCTION - ALTER COLUMN ... TYPE ... USING - CREATE INDEX ... INCLUDE (covering-index payload columns) - CREATE FUNCTION ... SECURITY DEFINER | INVOKER - Comment-only / whitespace-only input now parses to [] instead of throwing (matches Postgres accepting an empty command string) Round-trip (to-sql) + ast-mapper handlers added for every new node; specs added. 827 -> 829 parser tests passing. Co-Authored-By: Claude Opus 4.8 --- src/ast-mapper.ts | 35 +++++++++++++++++++ src/parser.ts | 40 ++++++++++++++++++++- src/syntax/alter-table.ne | 6 +++- src/syntax/ast.ts | 58 ++++++++++++++++++++++++++++--- src/syntax/base.ne | 12 +++++++ src/syntax/create-index.ne | 10 ++++-- src/syntax/create-index.spec.ts | 9 +++++ src/syntax/create-role.ne | 36 +++++++++++++++++++ src/syntax/edge-cases.spec.ts | 22 ++++++++++++ src/syntax/functions.ne | 1 + src/syntax/functions.spec.ts | 20 +++++++++++ src/syntax/grant.ne | 31 ++++++++++++++--- src/syntax/grant.spec.ts | 26 ++++++++++++++ src/syntax/main.ne | 2 ++ src/syntax/simple-statements.ne | 28 ++++++++++++++- src/to-sql.ts | 61 ++++++++++++++++++++++++++++++--- 16 files changed, 377 insertions(+), 20 deletions(-) diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index 86e757a..b995818 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -22,6 +22,9 @@ export interface IAstPartialMapper { drop?: (val: a.DropStatement) => a.Statement | nil dropTrigger?: (val: a.DropTriggerStatement) => a.Statement | nil show?: (val: a.ShowStatement) => a.Statement | nil + notify?: (val: a.NotifyStatement) => a.Statement | nil + listen?: (val: a.ListenStatement) => a.Statement | nil + unlisten?: (val: a.UnlistenStatement) => a.Statement | nil createTable?: (val: a.CreateTableStatement) => a.Statement | nil truncateTable?: (val: a.TruncateTableStatement) => a.Statement | nil createExtension?: (val: a.CreateExtensionStatement) => a.Statement | nil @@ -90,6 +93,8 @@ export interface IAstPartialMapper { valueKeyword?(val: a.ExprValueKeyword): a.Expr | nil tablespace?(val: a.TablespaceStatement): a.Statement | nil createRole?(val: a.CreateRoleStatement): a.Statement | nil + alterRole?(val: a.AlterRoleStatement): a.Statement | nil + alterDefaultPrivileges?(val: a.AlterDefaultPrivilegesStatement): a.Statement | nil setRole?(val: a.SetRoleStatement): a.Statement | nil reset?(val: a.ResetStatement): a.Statement | nil createPolicy?(val: a.CreatePolicyStatement): a.Statement | nil @@ -277,6 +282,10 @@ export class AstDefaultMapper implements IAstMapper { return this.setNames(val); case 'create role': return this.createRole(val); + case 'alter role': + return this.alterRole(val); + case 'alter default privileges': + return this.alterDefaultPrivileges(val); case 'set role': return this.setRole(val); case 'reset': @@ -322,6 +331,12 @@ export class AstDefaultMapper implements IAstMapper { return this.union(val); case 'show': return this.show(val); + case 'notify': + return this.notify(val); + case 'listen': + return this.listen(val); + case 'unlisten': + return this.unlisten(val); case 'prepare': return this.prepare(val); case 'deallocate': @@ -446,10 +461,30 @@ export class AstDefaultMapper implements IAstMapper { return val; } + notify(val: a.NotifyStatement): a.Statement | nil { + return val; + } + + listen(val: a.ListenStatement): a.Statement | nil { + return val; + } + + unlisten(val: a.UnlistenStatement): a.Statement | nil { + return val; + } + createRole(val: a.CreateRoleStatement): a.Statement | nil { return val; } + alterRole(val: a.AlterRoleStatement): a.Statement | nil { + return val; + } + + alterDefaultPrivileges(val: a.AlterDefaultPrivilegesStatement): a.Statement | nil { + return val; + } + setRole(val: a.SetRoleStatement): a.Statement | nil { return val; } diff --git a/src/parser.ts b/src/parser.ts index 313e51c..31784c0 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -6,7 +6,7 @@ import geometricGrammar from './literal-syntaxes/geometric.ne'; import intervalTextGrammar from './literal-syntaxes/interval.ne'; import intervalIsoGrammar from './literal-syntaxes/interval-iso.ne'; import { buildInterval } from './literal-syntaxes/interval-builder'; -import { tracking, trackingComments } from './lexer'; +import { tracking, trackingComments, lexer } from './lexer'; let sqlCompiled: Grammar; let arrayCompiled: Grammar; @@ -52,6 +52,11 @@ export function parse(sql: string, optEntry?: string | ParseOptions): any { : optEntry?.entry; const opts = typeof optEntry === 'string' ? null : optEntry; + // Tolerate comment-only / whitespace-only input for statement parsing: + // real Postgres accepts an empty command string and returns no results. + if (!entry && !hasMeaningfulTokens(sql)) { + return []; + } // parse sql const doParse = () => _parse(sql, sqlCompiled, entry); @@ -66,6 +71,39 @@ export function parse(sql: string, optEntry?: string | ParseOptions): any { return parsed; } +/** True if the SQL contains at least one token that is not whitespace or a comment. */ +function hasMeaningfulTokens(sql: string): boolean { + try { + lexer.reset(sql); + let inBlockComment = 0; + for (const tok of lexer as any) { + if (tok.type === 'commentFullOpen') { + inBlockComment++; + continue; + } + if (tok.type === 'commentFullClose') { + if (inBlockComment > 0) { + inBlockComment--; + } + continue; + } + if (inBlockComment > 0) { + // content inside a block comment + continue; + } + if (tok.type === 'space' || tok.type === 'commentLine') { + continue; + } + return true; + } + return false; + } catch { + // lexer choked on something that isn't whitespace/comment: let the + // real parser run so it produces a proper error. + return true; + } +} + export function parseArrayLiteral(sql: string): string[] { if (!arrayCompiled) { arrayCompiled = Grammar.fromCompiled(arrayGrammar); diff --git a/src/syntax/alter-table.ne b/src/syntax/alter-table.ne index 382143c..7a9c944 100644 --- a/src/syntax/alter-table.ne +++ b/src/syntax/alter-table.ne @@ -77,7 +77,11 @@ altertable_alter_column }) %} altercol - -> (kw_set kw_data):? kw_type data_type {% x => track(x, { type: 'set type', dataType: unwrap(last(x)) }) %} + -> (kw_set kw_data):? kw_type data_type (%kw_collate qname {% last %}):? (%kw_using expr {% last %}):? {% x => track(x, { + type: 'set type', + dataType: unwrap(x[2]), + ...(x[4] ? { using: unwrap(x[4]) } : {}), + }) %} | kw_set %kw_default expr {% x => track(x, {type: 'set default', default: unwrap(last(x)) }) %} | kw_drop %kw_default {% x => track(x, {type: 'drop default' }) %} | (kw_set | kw_drop) kw_not_null {% x => track(x, {type: toStr(x, ' ') }) %} diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index 3a2d0e6..d43a224 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -19,6 +19,9 @@ export type Statement = SelectStatement | UpdateStatement | MergeStatement | ShowStatement + | NotifyStatement + | ListenStatement + | UnlistenStatement | PrepareStatement | DeallocateStatement | ExecuteStatement @@ -38,6 +41,8 @@ export type Statement = SelectStatement | SetTimezone | SetNames | CreateRoleStatement + | AlterRoleStatement + | AlterDefaultPrivilegesStatement | SetRoleStatement | ResetStatement | CreatePolicyStatement @@ -97,6 +102,8 @@ export interface CreateFunctionStatement extends PGNode { purity?: 'immutable' | 'stable' | 'volatile'; leakproof?: boolean; onNullInput?: 'call' | 'null' | 'strict'; + /** SECURITY DEFINER / SECURITY INVOKER (default invoker) */ + security?: 'definer' | 'invoker'; } export interface DropFunctionStatement extends PGNode { @@ -127,11 +134,15 @@ export interface CommentStatement extends PGNode { * But this is what's supported. File an issue if you want more. */ on: { - type: 'table' | 'database' | 'index' | 'materialized view' | 'trigger' | 'type' | 'view'; + type: 'table' | 'database' | 'index' | 'materialized view' | 'trigger' | 'type' | 'view' | 'function'; name: QName; } | { type: 'column'; column: QColumn; + } | { + type: 'policy'; + policy: Name; + name: QName; }; } @@ -259,6 +270,22 @@ export interface ShowStatement extends PGNode { variable: Name; } +export interface NotifyStatement extends PGNode { + type: 'notify'; + channel: Name; + payload?: string; +} + +export interface ListenStatement extends PGNode { + type: 'listen'; + channel: Name; +} + +export interface UnlistenStatement extends PGNode { + type: 'unlisten'; + channel: Name | '*'; +} + export interface TruncateTableStatement extends PGNode { type: 'truncate table'; tables: QName[]; @@ -488,6 +515,8 @@ export interface TableAlterationRowLevelSecurity extends PGNode { export interface AlterColumnSetType extends PGNode { type: 'set type'; dataType: DataTypeDef; + /** the USING conversion, if any */ + using?: Expr; } export interface AlterColumnSetDefault extends PGNode { @@ -550,6 +579,8 @@ export interface CreateIndexStatement extends PGNode { indexName?: Name; tablespace?: string; with?: CreateIndexWith[]; + /** INCLUDE (cols) — covering-index payload columns (parsed; not used for lookups) */ + include?: Name[]; } export interface CreateIndexWith extends PGNode { @@ -1203,6 +1234,18 @@ export interface CreateRoleStatement extends PGNode { options: RoleOptions; } +/** ALTER ROLE ... — parsed but a no-op (pg-mem has no role/config system) */ +export interface AlterRoleStatement extends PGNode { + type: 'alter role'; + /** the role name, or 'all' for ALTER ROLE ALL */ + role: Name | 'all'; +} + +/** ALTER DEFAULT PRIVILEGES ... — parsed but a no-op (pg-mem has no privilege system) */ +export interface AlterDefaultPrivilegesStatement extends PGNode { + type: 'alter default privileges'; +} + export interface SetRoleStatement extends PGNode { type: 'set role'; scope?: string; @@ -1259,14 +1302,21 @@ export interface CreateTriggerStatement extends PGNode { } export interface GrantOnTarget extends PGNode { - type: 'table'; + type: 'table' | 'schema' | 'database' | 'function' | 'sequence'; names: QName[]; } +/** GRANT ... ON ALL {TABLES|SEQUENCES|FUNCTIONS|ROUTINES} IN SCHEMA ... */ +export interface GrantOnAllInSchema extends PGNode { + type: 'all in schema'; + objectType: 'tables' | 'sequences' | 'functions' | 'routines'; + schemas: QName[]; +} + export interface GrantStatement extends PGNode { type: 'grant'; privileges: 'all' | string[]; - on: GrantOnTarget; + on: GrantOnTarget | GrantOnAllInSchema; to: Name[]; withGrantOption?: boolean; } @@ -1274,7 +1324,7 @@ export interface GrantStatement extends PGNode { export interface RevokeStatement extends PGNode { type: 'revoke'; privileges: 'all' | string[]; - on: GrantOnTarget; + on: GrantOnTarget | GrantOnAllInSchema; from: Name[]; grantOptionFor?: boolean; } diff --git a/src/syntax/base.ne b/src/syntax/base.ne index ad7b07d..7765cde 100644 --- a/src/syntax/base.ne +++ b/src/syntax/base.ne @@ -300,6 +300,18 @@ kw_partial -> %word {% notReservedKw('partial') %} kw_partition -> %word {% notReservedKw('partition') %} kw_grouping -> %word {% notReservedKw('grouping') %} kw_sets -> %word {% notReservedKw('sets') %} +kw_routine -> %word {% notReservedKw('routine') %} +kw_database -> %word {% notReservedKw('database') %} +kw_tables -> %word {% notReservedKw('tables') %} +kw_sequences -> %word {% notReservedKw('sequences') %} +kw_functions -> %word {% notReservedKw('functions') %} +kw_routines -> %word {% notReservedKw('routines') %} +kw_types -> %word {% notReservedKw('types') %} +kw_schemas -> %word {% notReservedKw('schemas') %} +kw_include -> %word {% notReservedKw('include') %} +kw_notify -> %word {% notReservedKw('notify') %} +kw_listen -> %word {% notReservedKw('listen') %} +kw_unlisten -> %word {% notReservedKw('unlisten') %} kw_list -> %word {% notReservedKw('list') %} kw_hash -> %word {% notReservedKw('hash') %} kw_modulus -> %word {% notReservedKw('modulus') %} diff --git a/src/syntax/create-index.ne b/src/syntax/create-index.ne index 5c5f784..34f5023 100644 --- a/src/syntax/create-index.ne +++ b/src/syntax/create-index.ne @@ -19,6 +19,7 @@ createindex_statement lparen createindex_expressions rparen + createindex_include:? createindex_with:? createindex_tblspace:? createindex_predicate:? @@ -31,11 +32,14 @@ createindex_statement table: x[7], ...x[8] && { using: asName(x[8]) }, expressions: x[10], - ...x[12] && { with: x[12] }, - ...x[13] && { tablespace: unwrap(x[13]) }, - ...x[14] && { where: unwrap(x[14]) }, + ...x[12] && { include: x[12] }, + ...x[13] && { with: x[13] }, + ...x[14] && { tablespace: unwrap(x[14]) }, + ...x[15] && { where: unwrap(x[15]) }, }) %} +createindex_include -> kw_include lparen array_of[ident] rparen {% x => x[2].map(asName) %} + createindex_expressions -> createindex_expression (comma createindex_expression {% last %}):* {% ([head, tail]) => { return [head, ...(tail || [])]; } %} diff --git a/src/syntax/create-index.spec.ts b/src/syntax/create-index.spec.ts index a8efcc0..af4cf69 100644 --- a/src/syntax/create-index.spec.ts +++ b/src/syntax/create-index.spec.ts @@ -21,6 +21,15 @@ describe('Create index', () => { }], }); + checkCreateIndex(['create index on test(a) INCLUDE (b, c)'], { + type: 'create index', + table: { name: 'test' }, + expressions: [{ + expression: { type: 'ref', name: 'a' }, + }], + include: [{ name: 'b' }, { name: 'c' }], + }); + checkInvalid(`create index on test('a')`); checkInvalid('create index on test(a * 2)'); checkInvalid('create index on test(a and b)'); diff --git a/src/syntax/create-role.ne b/src/syntax/create-role.ne index 360017b..1da2505 100644 --- a/src/syntax/create-role.ne +++ b/src/syntax/create-role.ne @@ -16,6 +16,42 @@ function mergeRoleOptions(opts: any[]) { } %} +# ALTER ROLE ... — parsed, no-op. Covers "SET cfg TO ...", "RESET ...", and option lists. +alterrole_statement -> kw_alter (kw_role | %kw_user) alterrole_target alterrole_body {% x => track(x, { + type: 'alter role', + role: x[2], +}) %} + +alterrole_target + -> ident {% x => asName(x[0]) %} + | %kw_all {% () => 'all' %} + | %kw_current_user {% () => track([], { name: 'current_user' }) %} + | %kw_session_user {% () => track([], { name: 'session_user' }) %} + +alterrole_body + -> kw_set ident (%kw_to | %op_eq) alterrole_setvals {% () => null %} + | kw_set ident kw_from kw_current {% () => null %} + | kw_reset (ident | %kw_all) {% () => null %} + | %kw_in kw_database ident kw_set ident (%kw_to | %op_eq) alterrole_setvals {% () => null %} + | %kw_with:? role_option:* {% () => null %} + +alterrole_setvals -> alterrole_setval (comma alterrole_setval {% last %}):* +alterrole_setval -> (string | int | float | %word | %quoted_word | %kw_default | %kw_on | %kw_true | %kw_false | %kw_null) {% () => null %} + +# ALTER DEFAULT PRIVILEGES ... — parsed, no-op +alterdefaultprivileges_statement -> + kw_alter %kw_default kw_privileges + (%kw_for (kw_role | %kw_user) grant_grantees {% x => x[2] %}):? + (%kw_in kw_schema grant_name_list {% last %}):? + adp_action + {% x => track(x, { type: 'alter default privileges' }) %} + +adp_action + -> %kw_grant grant_privileges %kw_on adp_objtype %kw_to grant_grantees (%kw_with %kw_grant kw_option):? {% () => null %} + | kw_revoke (%kw_grant kw_option %kw_for {% () => null %}):? grant_privileges %kw_on adp_objtype %kw_from grant_grantees (kw_cascade | kw_restrict):? {% () => null %} + +adp_objtype -> (kw_tables | kw_sequences | kw_functions | kw_routines | kw_types | kw_schemas) {% () => null %} + role_option -> kw_superuser {% () => ({ superuser: true }) %} | kw_nosuperuser {% () => ({ superuser: false }) %} diff --git a/src/syntax/edge-cases.spec.ts b/src/syntax/edge-cases.spec.ts index 76bb58a..1cc5dcf 100644 --- a/src/syntax/edge-cases.spec.ts +++ b/src/syntax/edge-cases.spec.ts @@ -1,11 +1,33 @@ import 'mocha'; import 'chai'; +import { expect } from 'chai'; import { checkCreateTable, checkCreateTableLoc, checkInvalid, checkValid } from './spec-utils'; import { parse, parseFirst } from '../parser'; describe('Edge cases', () => { + describe('Comment-only / empty input', () => { + it('returns [] for empty string', () => { + expect(parse('')).to.deep.equal([]); + }); + it('returns [] for whitespace only', () => { + expect(parse(' \n\t ')).to.deep.equal([]); + }); + it('returns [] for a line comment only', () => { + expect(parse('-- just a comment')).to.deep.equal([]); + }); + it('returns [] for a block comment only', () => { + expect(parse('/* a block comment */')).to.deep.equal([]); + }); + it('returns [] for mixed comments and whitespace', () => { + expect(parse(' -- one\n /* two */ \n')).to.deep.equal([]); + }); + it('still parses a statement after comments', () => { + expect(parse('-- lead\nselect 1').length).to.equal(1); + }); + }); + // https://github.com/oguimbal/pg-mem/issues/171 describe('Behaviour with table named after keywords', () => { diff --git a/src/syntax/functions.ne b/src/syntax/functions.ne index bc131e5..8fbf5d8 100644 --- a/src/syntax/functions.ne +++ b/src/syntax/functions.ne @@ -75,6 +75,7 @@ func_spec -> kw_language word {% x => track(x, { language: asName(last(x)) }) %} | (word {%kw('called')%}) oninp {% () => ({ onNullInput: 'call' }) %} | (word {%kw('returns')%}) %kw_null oninp {% () => ({ onNullInput: 'null' }) %} | (word {%kw('strict')%}) {% () => ({ onNullInput: 'strict' }) %} + | (word {%kw('external')%}):? (word {%kw('security')%}) (word {%kw('definer')%} | word {%kw('invoker')%}) {% x => track(x, { security: toStr(last(x)) }) %} func_purity -> word {%kw('immutable')%} | word {%kw('stable')%} diff --git a/src/syntax/functions.spec.ts b/src/syntax/functions.spec.ts index 0922fa5..d1f1b30 100644 --- a/src/syntax/functions.spec.ts +++ b/src/syntax/functions.spec.ts @@ -36,6 +36,26 @@ describe('Create function', () => { setof: true, }); + checkStatement(`CREATE FUNCTION f() RETURNS void LANGUAGE plpgsql SECURITY DEFINER AS 'x'`, { + type: 'create function', + name: { name: 'f' }, + arguments: [], + code: 'x', + language: { name: 'plpgsql' }, + returns: { name: 'void' }, + security: 'definer', + }); + + checkStatement(`CREATE FUNCTION f() RETURNS void SECURITY INVOKER LANGUAGE sql AS 'x'`, { + type: 'create function', + name: { name: 'f' }, + arguments: [], + code: 'x', + language: { name: 'sql' }, + returns: { name: 'void' }, + security: 'invoker', + }); + // modifiers BEFORE code block checkStatement(`CREATE FUNCTION add(integer, integer) RETURNS integer stable LANGUAGE SQL RETURNS NULL ON NULL INPUT diff --git a/src/syntax/grant.ne b/src/syntax/grant.ne index 408a1ba..7dcba54 100644 --- a/src/syntax/grant.ne +++ b/src/syntax/grant.ne @@ -31,11 +31,32 @@ grant_privileges grant_priv -> (%kw_select | %kw_references | kw_insert | kw_update | kw_delete | kw_truncate | kw_trigger | kw_usage | kw_execute | kw_connect | kw_temporary | kw_temp) {% x => toStr(unwrap(x)).toLowerCase() %} -# only the "[TABLE] name[, ...]" object form is modelled; other object types are ignored -grant_on_target -> %kw_on (%kw_table | kw_sequence):? grant_name_list {% x => track(x, { - type: 'table', - names: x[2], -}) %} +# object forms: TABLE / SEQUENCE / SCHEMA / DATABASE / FUNCTION lists, plus +# "ALL {TABLES|SEQUENCES|FUNCTIONS|ROUTINES} IN SCHEMA ...". All are no-ops in pg-mem. +grant_on_target + -> %kw_on (%kw_table | kw_sequence):? grant_name_list {% x => track(x, { + type: toStr(unwrap(x[1] ?? [])) === 'sequence' ? 'sequence' : 'table', + names: x[2], + }) %} + | %kw_on kw_schema grant_name_list {% x => track(x, { type: 'schema', names: x[2] }) %} + | %kw_on kw_database grant_name_list {% x => track(x, { type: 'database', names: x[2] }) %} + | %kw_on (kw_function | kw_procedure | kw_routine) grant_func_list {% x => track(x, { type: 'function', names: x[2] }) %} + | %kw_on %kw_all grant_all_object_type %kw_in kw_schema grant_name_list {% x => track(x, { + type: 'all in schema', + objectType: x[2], + schemas: x[5], + }) %} + +grant_all_object_type + -> kw_tables {% () => 'tables' %} + | kw_sequences {% () => 'sequences' %} + | kw_functions {% () => 'functions' %} + | kw_routines {% () => 'routines' %} + +# function target: name with an optional (ignored) argument-type signature +grant_func_list -> grant_func (comma grant_func {% last %}):* {% ([head, tail]) => [head, ...(tail || [])] %} +grant_func -> qualified_name (lparen grant_func_args:? rparen):? {% x => x[0] %} +grant_func_args -> data_type (comma data_type {% last %}):* grant_name_list -> qualified_name (comma qualified_name {% last %}):* {% ([head, tail]) => [head, ...(tail || [])] %} diff --git a/src/syntax/grant.spec.ts b/src/syntax/grant.spec.ts index 0405d11..987fa7c 100644 --- a/src/syntax/grant.spec.ts +++ b/src/syntax/grant.spec.ts @@ -39,4 +39,30 @@ describe('Grant / revoke', () => { on: { type: 'table', names: [{ name: 'docs' }] }, from: [{ name: 'alice' }], }); + + checkStatement([`grant usage on schema extensions to anon, authenticated`], { + type: 'grant', + privileges: ['usage'], + on: { type: 'schema', names: [{ name: 'extensions' }] }, + to: [{ name: 'anon' }, { name: 'authenticated' }], + }); + + checkStatement([`grant all on all tables in schema public to anon`], { + type: 'grant', + privileges: 'all', + on: { type: 'all in schema', objectType: 'tables', schemas: [{ name: 'public' }] }, + to: [{ name: 'anon' }], + }); + + checkStatement([`grant execute on function auth.uid() to anon`], { + type: 'grant', + privileges: ['execute'], + on: { type: 'function', names: [{ schema: 'auth', name: 'uid' }] }, + to: [{ name: 'anon' }], + }); + + checkStatement([`alter role anon set search_path to "$user", public, extensions`], { + type: 'alter role', + role: { name: 'anon' }, + }); }); diff --git a/src/syntax/main.ne b/src/syntax/main.ne index 58ef8e7..b877331 100644 --- a/src/syntax/main.ne +++ b/src/syntax/main.ne @@ -56,6 +56,8 @@ statement_noprep | createtable_statement | createextension_statement | createrole_statement + | alterrole_statement + | alterdefaultprivileges_statement | createpolicy_statement | droppolicy_statement | grant_statement diff --git a/src/syntax/simple-statements.ne b/src/syntax/simple-statements.ne index c12db4c..ad7ffb9 100644 --- a/src/syntax/simple-statements.ne +++ b/src/syntax/simple-statements.ne @@ -16,6 +16,9 @@ simplestatements_all | simplestatements_reset | simplestatements_show | simplestatements_begin + | simplestatements_notify + | simplestatements_listen + | simplestatements_unlisten array_of[EXP] -> $EXP (%comma $EXP {% last %}):* {% ([head, tail]) => { @@ -23,6 +26,18 @@ array_of[EXP] -> $EXP (%comma $EXP {% last %}):* {% ([head, tail]) => { } %} +# NOTIFY / LISTEN / UNLISTEN — parsed; no-op in pg-mem (no async channels) +simplestatements_notify -> kw_notify ident (comma string {% last %}):? {% x => track(x, { + type: 'notify', + channel: asName(x[1]), + ...(x[2] ? { payload: unbox(x[2]) } : {}), +}) %} +simplestatements_listen -> kw_listen ident {% x => track(x, { type: 'listen', channel: asName(x[1]) }) %} +simplestatements_unlisten -> kw_unlisten (ident {% x => asName(x[0]) %} | %star {% () => '*' %}) {% x => track(x, { + type: 'unlisten', + channel: unwrap(x[1]), +}) %} + # https://www.postgresql.org/docs/12/sql-start-transaction.html simplestatements_start_transaction -> (kw_start kw_transaction) {% x => track(x, { type: 'start transaction' }) %} @@ -154,7 +169,7 @@ comment_statement -> kw_comment %kw_on comment_what %kw_is string {% x => track( on: unwrap(x[2]), }) %} -comment_what -> comment_what_col | comment_what_nm +comment_what -> comment_what_col | comment_what_nm | comment_what_policy | comment_what_function comment_what_nm -> (%kw_table | kw_materialized kw_view @@ -169,6 +184,17 @@ comment_what_col -> kw_column qcolumn {% x => track(x, { column: last(x), }) %} +comment_what_policy -> kw_policy ident %kw_on qualified_name {% x => track(x, { + type: 'policy', + policy: asName(x[1]), + name: x[3], + }) %} + +comment_what_function -> (kw_function | kw_procedure | kw_routine) grant_func {% x => track(x, { + type: 'function', + name: x[1], + }) %} + # https://www.postgresql.org/docs/current/sql-begin.html simplestatements_begin -> kw_begin diff --git a/src/to-sql.ts b/src/to-sql.ts index ccc9970..79601cc 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -1,7 +1,7 @@ import { IAstPartialMapper, AstDefaultMapper } from './ast-mapper'; import { astVisitor, IAstVisitor, IAstFullVisitor } from './ast-visitor'; import { NotSupported, nil, ReplaceReturnType, NoExtraProperties } from './utils'; -import { TableConstraint, JoinClause, ColumnConstraint, AlterSequenceStatement, CreateSequenceStatement, AlterSequenceSetOptions, CreateSequenceOptions, QName, SetGlobalValue, AlterColumnAddGenerated, QColumn, Name, OrderByStatement, QNameAliased, FrameBound } from './syntax/ast'; +import { TableConstraint, JoinClause, ColumnConstraint, AlterSequenceStatement, CreateSequenceStatement, AlterSequenceSetOptions, CreateSequenceOptions, QName, SetGlobalValue, AlterColumnAddGenerated, QColumn, Name, OrderByStatement, QNameAliased, FrameBound, GrantOnTarget, GrantOnAllInSchema } from './syntax/ast'; import { literal } from './pg-escape'; import { sqlKeywords } from './keywords'; @@ -259,6 +259,17 @@ function join(m: IAstVisitor, j: JoinClause | nil, tbl: () => void) { ret.push(' '); } +function emitGrantOn(on: GrantOnTarget | GrantOnAllInSchema) { + if (on.type === 'all in schema') { + ret.push('ON ALL ', on.objectType.toUpperCase(), ' IN SCHEMA '); + list(on.schemas, n => visitQualifiedName(n), false); + return; + } + const kw = on.type === 'table' ? 'ON' : 'ON ' + on.type.toUpperCase(); + ret.push(kw, ' '); + list(on.names, n => visitQualifiedName(n), false); +} + function visitOp(v: { op: string; opSchema?: string; }) { if (v.opSchema) { ret.push(' operator(', ident(v.opSchema), '.', v.op, ') '); @@ -410,6 +421,10 @@ const visitor = astVisitor(m => ({ setColumnType: t => { ret.push(' SET DATA TYPE '); m.dataType(t.dataType); + if (t.using) { + ret.push(' USING '); + m.expr(t.using); + } ret.push(' '); }, @@ -671,6 +686,10 @@ const visitor = astVisitor(m => ({ case 'column': visitQColumn(c.on.column); break; + case 'policy': + ret.push(name(c.on.policy), ' ON '); + visitQualifiedName(c.on.name); + break; default: visitQualifiedName(c.on.name); break; @@ -850,6 +869,9 @@ const visitor = astVisitor(m => ({ default: throw NotSupported.never(c.onNullInput); } + if (c.security) { + ret.push('SECURITY ', c.security.toUpperCase(), ' '); + } }, @@ -1018,6 +1040,10 @@ const visitor = astVisitor(m => ({ ret.push('nulls ', e.nulls, ' '); } }, true); + if (c.include?.length) { + ret.push(' INCLUDE '); + list(c.include, n => ret.push(name(n)), true); + } if (c.with) { ret.push('WITH '); list(c.with, w => { @@ -1539,6 +1565,21 @@ const visitor = astVisitor(m => ({ ret.push('SHOW ', name(s.variable)); }, + notify: s => { + ret.push('NOTIFY ', name(s.channel)); + if (s.payload !== undefined) { + ret.push(', ', literal(s.payload)); + } + }, + + listen: s => { + ret.push('LISTEN ', name(s.channel)); + }, + + unlisten: s => { + ret.push('UNLISTEN ', s.channel === '*' ? '*' : name(s.channel)); + }, + createRole: r => { ret.push('CREATE ROLE ', name(r.name)); const o = r.options; @@ -1618,8 +1659,8 @@ const visitor = astVisitor(m => ({ }, grant: g => { - ret.push('GRANT ', g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' ON '); - list(g.on.names, n => visitQualifiedName(n), false); + ret.push('GRANT ', g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' '); + emitGrantOn(g.on); ret.push(' TO '); list(g.to, r => ret.push(name(r)), false); if (g.withGrantOption) { @@ -1632,12 +1673,22 @@ const visitor = astVisitor(m => ({ if (g.grantOptionFor) { ret.push('GRANT OPTION FOR '); } - ret.push(g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' ON '); - list(g.on.names, n => visitQualifiedName(n), false); + ret.push(g.privileges === 'all' ? 'ALL' : g.privileges.map(x => x.toUpperCase()).join(', '), ' '); + emitGrantOn(g.on); ret.push(' FROM '); list(g.from, r => ret.push(name(r)), false); }, + alterRole: r => { + ret.push('ALTER ROLE ', r.role === 'all' ? 'ALL' : name(r.role)); + }, + + alterDefaultPrivileges: () => { + // no-op passthrough: the action details aren't retained on the AST, so emit a + // valid canonical statement (a real Postgres would keep the original clause) + ret.push('ALTER DEFAULT PRIVILEGES GRANT ALL ON TABLES TO PUBLIC'); + }, + prepare: s => { ret.push('PREPARE ', name(s.name)); if (s.args?.length) { From 8c8871105295d8cc4eaedb1f82b72e5dc9cb7058 Mon Sep 17 00:00:00 2001 From: sanketsahu Date: Fri, 10 Jul 2026 14:07:33 +0530 Subject: [PATCH 23/23] feat: dollar-quoted strings ($tag$), array slicing (arr[lo:hi]) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Dollar-quoted string literals with named tags ($tag$…$tag$, not just $$…$$) now lex correctly, both as expression values (e.g. INSERT VALUES) and in DO/function bodies. The matching close tag is resolved in the lexer.next wrapper (a moo regex can't backreference the tag). - Array slice syntax: arr[lo:hi], arr[:hi], arr[lo:] (ExprArraySlice) — grammar, AST, to-sql round-trip, ast-mapper. 836 parser tests passing. Co-Authored-By: Claude Opus 4.8 --- src/ast-mapper.ts | 17 +++++++++++++++++ src/lexer.ts | 36 +++++++++++++++++++++++++++++++---- src/syntax/ast.ts | 10 ++++++++++ src/syntax/edge-cases.spec.ts | 18 ++++++++++++++++++ src/syntax/expr.ne | 7 +++++++ src/syntax/expr.spec.ts | 19 ++++++++++++++++++ src/to-sql.ts | 13 +++++++++++++ 7 files changed, 116 insertions(+), 4 deletions(-) diff --git a/src/ast-mapper.ts b/src/ast-mapper.ts index b995818..3503b37 100644 --- a/src/ast-mapper.ts +++ b/src/ast-mapper.ts @@ -74,6 +74,7 @@ export interface IAstPartialMapper { ternary?: (val: a.ExprTernary) => a.Expr | nil arraySelect?: (val: a.ExprArrayFromSelect) => a.Expr | nil arrayIndex?: (val: a.ExprArrayIndex) => a.Expr | nil + arraySlice?: (val: a.ExprArraySlice) => a.Expr | nil member?: (val: a.ExprMember) => a.Expr | nil extract?: (st: a.ExprExtract) => a.Expr | nil case?: (val: a.ExprCase) => a.Expr | nil @@ -1308,6 +1309,8 @@ export class AstDefaultMapper implements IAstMapper { return this.member(val); case 'arrayIndex': return this.arrayIndex(val); + case 'arraySlice': + return this.arraySlice(val); case 'ternary': return this.ternary(val); case 'select': @@ -1392,6 +1395,20 @@ export class AstDefaultMapper implements IAstMapper { }); } + arraySlice(val: a.ExprArraySlice): a.Expr | nil { + const array = this.expr(val.array); + if (!array) { + return null; + } + const from = val.from && this.expr(val.from); + const to = val.to && this.expr(val.to); + return assignChanged(val, { + array, + from: from ?? undefined, + to: to ?? undefined, + }); + } + member(val: a.ExprMember): a.Expr | nil { const operand = this.expr(val.operand); if (!operand) { diff --git a/src/lexer.ts b/src/lexer.ts index 19116f4..768f3d6 100644 --- a/src/lexer.ts +++ b/src/lexer.ts @@ -92,10 +92,11 @@ export const lexer = compile({ // see also https://www.postgresql.org/docs/9.0/functions-math.html match: ['|', '&', '^', '#'], }, - codeblock: { - match: /\$\$(?:.|[\s\t\n\v\f\r])*?\$\$/s, - lineBreaks: true, - value: (x: string) => x.substring(2, x.length - 2), + // opening of a dollar-quoted string: $$ or $tag$ (tag = optional identifier). + // The matching close is found in the lexer.next wrapper (a regex can't + // backreference the tag), which rewrites this into a single `codeblock` token. + dollarOpen: { + match: /\$(?:[a-zA-Z_][a-zA-Z0-9_]*)?\$/, }, }); @@ -134,6 +135,33 @@ lexer.next = (next => () => { } continue; } + if (tok.type === 'dollarOpen') { + // dollar-quoted string: $tag$ ... $tag$ (or $$ ... $$). Everything up to + // the matching close tag is opaque content — scan the raw buffer for it + // (Postgres does not nest identical tags) and emit one `codeblock` token. + const tag: string = tok.text; + const contentStart: number = (lexer as any).index; + const buffer: string = (lexer as any).buffer; + const close = buffer.indexOf(tag, contentStart); + if (close >= 0) { + const content = buffer.slice(contentStart, close); + const consumed = buffer.slice(contentStart, close + tag.length); + (lexer as any).index = close + tag.length; + // keep moo's line/col tracking consistent past the opaque span + const nl = consumed.split('\n').length - 1; + if (nl > 0) { + (lexer as any).line += nl; + (lexer as any).col = consumed.length - consumed.lastIndexOf('\n'); + } else { + (lexer as any).col += consumed.length; + } + (tok as any).type = 'codeblock'; + (tok as any).text = tag + consumed; + (tok as any).value = content; + } + // if unterminated, fall through with type 'dollarOpen' so the parser errors + break; + } if (tok.type === 'space') { continue; } diff --git a/src/syntax/ast.ts b/src/syntax/ast.ts index d43a224..a42acab 100644 --- a/src/syntax/ast.ts +++ b/src/syntax/ast.ts @@ -968,6 +968,7 @@ export type Expr = ExprRef | ExprMember | ExprValueKeyword | ExprArrayIndex + | ExprArraySlice | ExprNumeric | ExprString | ExprCase @@ -1171,6 +1172,15 @@ export interface ExprArrayIndex extends PGNode { index: Expr; } +export interface ExprArraySlice extends PGNode { + type: 'arraySlice', + array: Expr; + /** lower bound (1-based, inclusive); omitted means "from the start" */ + from?: Expr; + /** upper bound (1-based, inclusive); omitted means "to the end" */ + to?: Expr; +} + export interface ExprNull extends PGNode { type: 'null'; } diff --git a/src/syntax/edge-cases.spec.ts b/src/syntax/edge-cases.spec.ts index 1cc5dcf..8b2c825 100644 --- a/src/syntax/edge-cases.spec.ts +++ b/src/syntax/edge-cases.spec.ts @@ -7,6 +7,24 @@ import { parse, parseFirst } from '../parser'; describe('Edge cases', () => { + describe('Dollar-quoted strings', () => { + it('parses a named dollar-quoted string literal (with ; and quotes inside)', () => { + const [st] = parse(`insert into t(a) values ($x$he;llo 'q'$x$)`) as any; + expect(st.type).to.equal('insert'); + expect(st.insert.values[0][0]).to.deep.include({ type: 'string', value: `he;llo 'q'` }); + }); + it('parses a named dollar-quoted DO block body', () => { + const [st] = parse(`do $tag$ begin perform 1; end $tag$`) as any; + expect(st.type).to.equal('do'); + expect(st.code).to.contain('perform 1'); + }); + it('still parses a $$ function body', () => { + const [st] = parse(`create function f() returns int language sql as $$ select 1 $$`) as any; + expect(st.type).to.equal('create function'); + expect(st.code).to.contain('select 1'); + }); + }); + describe('Comment-only / empty input', () => { it('returns [] for empty string', () => { expect(parse('')).to.deep.equal([]); diff --git a/src/syntax/expr.ne b/src/syntax/expr.ne index c24823d..e642f7a 100644 --- a/src/syntax/expr.ne +++ b/src/syntax/expr.ne @@ -110,6 +110,12 @@ expr_array_index array: unwrap(x[0]), index: unwrap(x[2]), }) %} + | (expr_array_index | expr_paren) %lbracket expr_nostar:? %op_colon expr_nostar:? %rbracket {% x => track(x, { + type: 'arraySlice', + array: unwrap(x[0]), + ...x[2] ? { from: unwrap(x[2]) } : {}, + ...x[4] ? { to: unwrap(x[4]) } : {}, + }) %} | expr_member {% unwrap %} expr_member @@ -291,6 +297,7 @@ expr_primary -> %float {% x => track(x, mkNumeric(x[0])) %} | %int {% x => track(x, mkInteger(x[0])) %} | string {% x => track(x, { type: 'string', value: unbox(x[0]) }) %} + | %codeblock {% x => track(x, { type: 'string', value: x[0].value }) %} | %kw_true {% x => track(x, { type: 'boolean', value: true }) %} | %kw_false {% x => track(x, { type: 'boolean', value: false }) %} | %kw_null {% x => track(x, { type: 'null' }) %} diff --git a/src/syntax/expr.spec.ts b/src/syntax/expr.spec.ts index 90e9c5c..ae23407 100644 --- a/src/syntax/expr.spec.ts +++ b/src/syntax/expr.spec.ts @@ -1194,6 +1194,25 @@ line`, right: { type: 'integer', value: 2 }, } }) + + checkTreeExpr(['a[1:3]', '"a"[1 : 3]'], { + type: 'arraySlice', + array: { type: 'ref', name: 'a' }, + from: { type: 'integer', value: 1 }, + to: { type: 'integer', value: 3 }, + }) + + checkTreeExpr(['a[:3]'], { + type: 'arraySlice', + array: { type: 'ref', name: 'a' }, + to: { type: 'integer', value: 3 }, + }) + + checkTreeExpr(['a[2:]'], { + type: 'arraySlice', + array: { type: 'ref', name: 'a' }, + from: { type: 'integer', value: 2 }, + }) }); diff --git a/src/to-sql.ts b/src/to-sql.ts index 79601cc..33f5c51 100644 --- a/src/to-sql.ts +++ b/src/to-sql.ts @@ -502,6 +502,19 @@ const visitor = astVisitor(m => ({ ret.push('] '); }, + arraySlice: v => { + m.expr(v.array); + ret.push('['); + if (v.from) { + m.expr(v.from); + } + ret.push(':'); + if (v.to) { + m.expr(v.to); + } + ret.push('] '); + }, + expr: e => { if (e.type === 'ref') { m.ref(e);