diff --git a/nezha-fronted/package-lock.json b/nezha-fronted/package-lock.json index 7ccf0d8e3..84ed239b1 100644 --- a/nezha-fronted/package-lock.json +++ b/nezha-fronted/package-lock.json @@ -3127,7 +3127,7 @@ "babel-helper-builder-binary-assignment-operator-visitor": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "integrity": "sha512-gCtfYORSG1fUMX4kKraymq607FWgMWg+j42IFPc18kFQEsmtaibP4UrqsXt8FlEJle25HUd4tsoDR7H2wDhe9Q==", "dev": true, "requires": { "babel-helper-explode-assignable-expression": "^6.24.1", @@ -3138,7 +3138,7 @@ "babel-helper-call-delegate": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "integrity": "sha512-RL8n2NiEj+kKztlrVJM9JT1cXzzAdvWFh76xh/H1I4nKwunzE4INBXn8ieCZ+wh4zWszZk7NBS1s/8HR5jDkzQ==", "dev": true, "requires": { "babel-helper-hoist-variables": "^6.24.1", @@ -3150,7 +3150,7 @@ "babel-helper-define-map": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "integrity": "sha512-bHkmjcC9lM1kmZcVpA5t2om2nzT/xiZpo6TJq7UlZ3wqKfzia4veeXbIhKvJXAMzhhEBd3cR1IElL5AenWEUpA==", "dev": true, "requires": { "babel-helper-function-name": "^6.24.1", @@ -3162,7 +3162,7 @@ "babel-helper-explode-assignable-expression": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "integrity": "sha512-qe5csbhbvq6ccry9G7tkXbzNtcDiH4r51rrPUbwwoTzZ18AqxWYRZT6AOmxrpxKnQBW0pYlBI/8vh73Z//78nQ==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -3185,7 +3185,7 @@ "babel-helper-function-name": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "integrity": "sha512-Oo6+e2iX+o9eVvJ9Y5eKL5iryeRdsIkwRYheCuhYdVHsdEQysbc2z2QkqCLIYnNxkT5Ss3ggrHdXiDI7Dhrn4Q==", "dev": true, "requires": { "babel-helper-get-function-arity": "^6.24.1", @@ -3198,7 +3198,7 @@ "babel-helper-get-function-arity": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "integrity": "sha512-WfgKFX6swFB1jS2vo+DwivRN4NB8XUdM3ij0Y1gnC21y1tdBoe6xjVnd7NSI6alv+gZXCtJqvrTeMW3fR/c0ng==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -3208,7 +3208,7 @@ "babel-helper-hoist-variables": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "integrity": "sha512-zAYl3tqerLItvG5cKYw7f1SpvIxS9zi7ohyGHaI9cgDUjAT6YcY9jIEH5CstetP5wHIVSceXwNS7Z5BpJg+rOw==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -3218,7 +3218,7 @@ "babel-helper-optimise-call-expression": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "integrity": "sha512-Op9IhEaxhbRT8MDXx2iNuMgciu2V8lDvYCNQbDGjdBNCjaMvyLf4wl4A3b8IgndCyQF8TwfgsQ8T3VD8aX1/pA==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -3239,7 +3239,7 @@ "babel-helper-remap-async-to-generator": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "integrity": "sha512-RYqaPD0mQyQIFRu7Ho5wE2yvA/5jxqCIj/Lv4BXNq23mHYu/vxikOy2JueLiBxQknwapwrJeNCesvY0ZcfnlHg==", "dev": true, "requires": { "babel-helper-function-name": "^6.24.1", @@ -3252,7 +3252,7 @@ "babel-helper-replace-supers": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "integrity": "sha512-sLI+u7sXJh6+ToqDr57Bv973kCepItDhMou0xCP2YPVmR1jkHSCY+p1no8xErbV1Siz5QE8qKT1WIwybSWlqjw==", "dev": true, "requires": { "babel-helper-optimise-call-expression": "^6.24.1", @@ -3311,7 +3311,7 @@ "babel-plugin-check-es2015-constants": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "integrity": "sha512-B1M5KBP29248dViEo1owyY32lk1ZSH2DaNNrXLGt8lyjjHm7pBqAdQ7VKUPR6EEDO323+OvT3MQXbCin8ooWdA==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3370,7 +3370,7 @@ "babel-plugin-syntax-async-functions": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "integrity": "sha512-4Zp4unmHgw30A1eWI5EpACji2qMocisdXhAftfhXoSV9j0Tvj6nRFE3tOmRY912E0FMRm/L5xWE7MGVT2FoLnw==", "dev": true }, "babel-plugin-syntax-async-generators": { @@ -3388,7 +3388,7 @@ "babel-plugin-syntax-decorators": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz", - "integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=", + "integrity": "sha512-AWj19x2aDm8qFQ5O2JcD6pwJDW1YdcnO+1b81t7gxrGjz5VHiUqeYWAR4h7zueWMalRelrQDXprv2FrY1dbpbw==", "dev": true }, "babel-plugin-syntax-dynamic-import": { @@ -3400,13 +3400,13 @@ "babel-plugin-syntax-exponentiation-operator": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "integrity": "sha512-Z/flU+T9ta0aIEKl1tGEmN/pZiI1uXmCiGFRegKacQfEJzp7iNsKloZmyJlQr+75FCJtiFfGIK03SiCvCt9cPQ==", "dev": true }, "babel-plugin-syntax-jsx": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", + "integrity": "sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==", "dev": true }, "babel-plugin-syntax-object-rest-spread": { @@ -3418,7 +3418,7 @@ "babel-plugin-syntax-trailing-function-commas": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "integrity": "sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ==", "dev": true }, "babel-plugin-transform-async-generator-functions": { @@ -3435,7 +3435,7 @@ "babel-plugin-transform-async-to-generator": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "integrity": "sha512-7BgYJujNCg0Ti3x0c/DL3tStvnKS6ktIYOmo9wginv/dfZOrbSZ+qG4IRRHMBOzZ5Awb1skTiAsQXg/+IWkZYw==", "dev": true, "requires": { "babel-helper-remap-async-to-generator": "^6.24.1", @@ -3471,7 +3471,7 @@ "babel-plugin-transform-es2015-arrow-functions": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "integrity": "sha512-PCqwwzODXW7JMrzu+yZIaYbPQSKjDTAsNNlK2l5Gg9g4rz2VzLnZsStvp/3c46GfXpwkyufb3NCyG9+50FF1Vg==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3480,7 +3480,7 @@ "babel-plugin-transform-es2015-block-scoped-functions": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "integrity": "sha512-2+ujAT2UMBzYFm7tidUsYh+ZoIutxJ3pN9IYrF1/H6dCKtECfhmB8UkHVpyxDwkj0CYbQG35ykoz925TUnBc3A==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3489,7 +3489,7 @@ "babel-plugin-transform-es2015-block-scoping": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "integrity": "sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw==", "dev": true, "requires": { "babel-runtime": "^6.26.0", @@ -3502,7 +3502,7 @@ "babel-plugin-transform-es2015-classes": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "integrity": "sha512-5Dy7ZbRinGrNtmWpquZKZ3EGY8sDgIVB4CU8Om8q8tnMLrD/m94cKglVcHps0BCTdZ0TJeeAWOq2TK9MIY6cag==", "dev": true, "requires": { "babel-helper-define-map": "^6.24.1", @@ -3519,7 +3519,7 @@ "babel-plugin-transform-es2015-computed-properties": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "integrity": "sha512-C/uAv4ktFP/Hmh01gMTvYvICrKze0XVX9f2PdIXuriCSvUmV9j+u+BB9f5fJK3+878yMK6dkdcq+Ymr9mrcLzw==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -3529,7 +3529,7 @@ "babel-plugin-transform-es2015-destructuring": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "integrity": "sha512-aNv/GDAW0j/f4Uy1OEPZn1mqD+Nfy9viFGBfQ5bZyT35YqOiqx7/tXdyfZkJ1sC21NyEsBdfDY6PYmLHF4r5iA==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3538,7 +3538,7 @@ "babel-plugin-transform-es2015-duplicate-keys": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "integrity": "sha512-ossocTuPOssfxO2h+Z3/Ea1Vo1wWx31Uqy9vIiJusOP4TbF7tPs9U0sJ9pX9OJPf4lXRGj5+6Gkl/HHKiAP5ug==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -3548,7 +3548,7 @@ "babel-plugin-transform-es2015-for-of": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "integrity": "sha512-DLuRwoygCoXx+YfxHLkVx5/NpeSbVwfoTeBykpJK7JhYWlL/O8hgAK/reforUnZDlxasOrVPPJVI/guE3dCwkw==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3557,7 +3557,7 @@ "babel-plugin-transform-es2015-function-name": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "integrity": "sha512-iFp5KIcorf11iBqu/y/a7DK3MN5di3pNCzto61FqCNnUX4qeBwcV1SLqe10oXNnCaxBUImX3SckX2/o1nsrTcg==", "dev": true, "requires": { "babel-helper-function-name": "^6.24.1", @@ -3568,7 +3568,7 @@ "babel-plugin-transform-es2015-literals": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "integrity": "sha512-tjFl0cwMPpDYyoqYA9li1/7mGFit39XiNX5DKC/uCNjBctMxyL1/PT/l4rSlbvBG1pOKI88STRdUsWXB3/Q9hQ==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3577,7 +3577,7 @@ "babel-plugin-transform-es2015-modules-amd": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "integrity": "sha512-LnIIdGWIKdw7zwckqx+eGjcS8/cl8D74A3BpJbGjKTFFNJSMrjN4bIh22HY1AlkUbeLG6X6OZj56BDvWD+OeFA==", "dev": true, "requires": { "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", @@ -3600,7 +3600,7 @@ "babel-plugin-transform-es2015-modules-systemjs": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "integrity": "sha512-ONFIPsq8y4bls5PPsAWYXH/21Hqv64TBxdje0FvU3MhIV6QM2j5YS7KvAzg/nTIVLot2D2fmFQrFWCbgHlFEjg==", "dev": true, "requires": { "babel-helper-hoist-variables": "^6.24.1", @@ -3611,7 +3611,7 @@ "babel-plugin-transform-es2015-modules-umd": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "integrity": "sha512-LpVbiT9CLsuAIp3IG0tfbVo81QIhn6pE8xBJ7XSeCtFlMltuar5VuBV6y6Q45tpui9QWcy5i0vLQfCfrnF7Kiw==", "dev": true, "requires": { "babel-plugin-transform-es2015-modules-amd": "^6.24.1", @@ -3622,7 +3622,7 @@ "babel-plugin-transform-es2015-object-super": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "integrity": "sha512-8G5hpZMecb53vpD3mjs64NhI1au24TAmokQ4B+TBFBjN9cVoGoOvotdrMMRmHvVZUEvqGUPWL514woru1ChZMA==", "dev": true, "requires": { "babel-helper-replace-supers": "^6.24.1", @@ -3632,7 +3632,7 @@ "babel-plugin-transform-es2015-parameters": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "integrity": "sha512-8HxlW+BB5HqniD+nLkQ4xSAVq3bR/pcYW9IigY+2y0dI+Y7INFeTbfAQr+63T3E4UDsZGjyb+l9txUnABWxlOQ==", "dev": true, "requires": { "babel-helper-call-delegate": "^6.24.1", @@ -3646,7 +3646,7 @@ "babel-plugin-transform-es2015-shorthand-properties": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "integrity": "sha512-mDdocSfUVm1/7Jw/FIRNw9vPrBQNePy6wZJlR8HAUBLybNp1w/6lr6zZ2pjMShee65t/ybR5pT8ulkLzD1xwiw==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -3656,7 +3656,7 @@ "babel-plugin-transform-es2015-spread": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "integrity": "sha512-3Ghhi26r4l3d0Js933E5+IhHwk0A1yiutj9gwvzmFbVV0sPMYk2lekhOufHBswX7NCoSeF4Xrl3sCIuSIa+zOg==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3665,7 +3665,7 @@ "babel-plugin-transform-es2015-sticky-regex": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "integrity": "sha512-CYP359ADryTo3pCsH0oxRo/0yn6UsEZLqYohHmvLQdfS9xkf+MbCzE3/Kolw9OYIY4ZMilH25z/5CbQbwDD+lQ==", "dev": true, "requires": { "babel-helper-regex": "^6.24.1", @@ -3676,7 +3676,7 @@ "babel-plugin-transform-es2015-template-literals": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "integrity": "sha512-x8b9W0ngnKzDMHimVtTfn5ryimars1ByTqsfBDwAqLibmuuQY6pgBQi5z1ErIsUOWBdw1bW9FSz5RZUojM4apg==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3685,7 +3685,7 @@ "babel-plugin-transform-es2015-typeof-symbol": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "integrity": "sha512-fz6J2Sf4gYN6gWgRZaoFXmq93X+Li/8vf+fb0sGDVtdeWvxC9y5/bTD7bvfWMEq6zetGEHpWjtzRGSugt5kNqw==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3694,7 +3694,7 @@ "babel-plugin-transform-es2015-unicode-regex": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "integrity": "sha512-v61Dbbihf5XxnYjtBN04B/JBvsScY37R1cZT5r9permN1cp+b70DY3Ib3fIkgn1DI9U3tGgBJZVD8p/mE/4JbQ==", "dev": true, "requires": { "babel-helper-regex": "^6.24.1", @@ -3705,7 +3705,7 @@ "babel-plugin-transform-exponentiation-operator": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "integrity": "sha512-LzXDmbMkklvNhprr20//RStKVcT8Cu+SQtX18eMHLhjHf2yFzwtQ0S2f0jQ+89rokoNdmwoSqYzAhq86FxlLSQ==", "dev": true, "requires": { "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", @@ -3726,7 +3726,7 @@ "babel-plugin-transform-regenerator": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "integrity": "sha512-LS+dBkUGlNR15/5WHKe/8Neawx663qttS6AGqoOUhICc9d1KciBvtrQSuc0PI+CxQ2Q/S1aKuJ+u64GtLdcEZg==", "dev": true, "requires": { "regenerator-transform": "^0.10.0" @@ -3735,7 +3735,7 @@ "babel-plugin-transform-runtime": { "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz", - "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=", + "integrity": "sha512-cpGMVC1vt/772y3jx1gwSaTitQVZuFDlllgreMsZ+rTYC6jlYXRyf5FQOgSnckOiA5QmzbXTyBY2A5AmZXF1fA==", "dev": true, "requires": { "babel-runtime": "^6.22.0" @@ -3744,7 +3744,7 @@ "babel-plugin-transform-strict-mode": { "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "integrity": "sha512-j3KtSpjyLSJxNoCDrhwiJad8kw0gJ9REGj8/CqL0HeRyLnvUNYV9zcqluL6QJSXh3nfsLEmSLvwRfGzrgR96Pw==", "dev": true, "requires": { "babel-runtime": "^6.22.0", @@ -4197,7 +4197,7 @@ "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" }, "brace-expansion": { "version": "1.1.11", @@ -5182,7 +5182,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "color-string": { "version": "1.9.1", @@ -5293,7 +5293,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "concat-stream": { "version": "1.6.2", @@ -8139,7 +8139,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" }, "escodegen": { "version": "1.14.3", @@ -9199,7 +9199,7 @@ "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "faye-websocket": { @@ -9617,7 +9617,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "fsevents": { "version": "1.2.13", @@ -10148,7 +10148,7 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "has-symbol-support-x": { "version": "1.4.2", @@ -10704,7 +10704,7 @@ "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" }, "in-publish": { "version": "2.0.1", @@ -10730,7 +10730,7 @@ "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "requires": { "once": "^1.3.0", "wrappy": "1" @@ -10974,7 +10974,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-finite": { "version": "1.0.2", @@ -11189,7 +11189,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "isobject": { @@ -12492,7 +12492,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, "json-stringify-safe": { "version": "5.0.1", @@ -13806,6 +13806,11 @@ "moment": ">= 2.9.0" } }, + "monaco-editor": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.20.0.tgz", + "integrity": "sha512-hkvf4EtPJRMQlPC3UbMoRs0vTAFAYdzFQ+gpMb8A+9znae1c43q8Mab9iVsgTcg/4PNiLGGn3SlDIa8uvK1FIQ==" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -13987,6 +13992,11 @@ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true }, + "nano-assign": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-assign/-/nano-assign-1.0.1.tgz", + "integrity": "sha512-1K8ncUoAYFPYcCZqrB+K2XQaFCmA35rryJCtPkGrG3zYkwm+iIUZRIHyaAfuy6zxaK9siPdjeJq7+Inijm6xhw==" + }, "nanoid": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", @@ -14020,7 +14030,7 @@ "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "ncp": { @@ -14510,7 +14520,7 @@ "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "requires": { "wrappy": "1" } @@ -14887,7 +14897,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-is-inside": { "version": "1.0.2", @@ -16633,7 +16643,7 @@ "rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, "requires": { "resolve": "^1.1.6" @@ -16717,7 +16727,7 @@ "regexpu-core": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "integrity": "sha512-tJ9+S4oKjxY8IZ9jmjnp/mtytu1u3iyIQAfmI51IKWH6bFf7XR1ybtaO6j7INhZKXOTYADk7V5qxaqLkmNxiZQ==", "dev": true, "requires": { "regenerate": "^1.2.1", @@ -16728,13 +16738,13 @@ "regjsgen": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "integrity": "sha512-x+Y3yA24uF68m5GA+tBjbGYo64xXVJpbToBaWCoSNSc1hdk6dfctaRWrNFTVJZIIhL5GxW8zwjoixbnifnK59g==", "dev": true }, "regjsparser": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "integrity": "sha512-jlQ9gYLfk2p3V5Ag5fYhA7fv7OHzd1KUH0PRP46xc3TgwjwgROIW572AfYg/X9kaNq/LJnu6oJcFRXlIrGoTRw==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -16743,7 +16753,7 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "dev": true } } @@ -18465,7 +18475,7 @@ "svg-tags": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", - "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, "svgo": { @@ -19180,7 +19190,7 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "throat": { @@ -19820,7 +19830,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "util.promisify": { "version": "1.0.0", @@ -20153,6 +20163,15 @@ } } }, + "vue-monaco": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/vue-monaco/-/vue-monaco-1.2.2.tgz", + "integrity": "sha512-+BhCHeAuDmjtCUP9MUxan6OjGgOqDR7xHlNScZ8Cfq32iac76Fv7z6RfC+lSrp0YpCjEPl6bvpY21N11UBRmMg==", + "requires": { + "monaco-editor": "^0.20.0", + "nano-assign": "^1.0.0" + } + }, "vue-quill-editor": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/vue-quill-editor/-/vue-quill-editor-3.0.6.tgz", @@ -21146,7 +21165,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "write-file-atomic": { "version": "2.4.1", diff --git a/nezha-fronted/package.json b/nezha-fronted/package.json index 4c57f7164..5622099bc 100644 --- a/nezha-fronted/package.json +++ b/nezha-fronted/package.json @@ -90,6 +90,7 @@ "vue-grid-layout": "^2.3.12", "vue-i18n": "^8.15.1", "vue-introjs": "^1.3.2", + "vue-monaco": "^1.2.2", "vue-quill-editor": "^3.0.6", "vue-resource": "^1.5.1", "vue-router": "^3.0.1", diff --git a/nezha-fronted/src/assets/css/components/page/dashboard/explore/promqlInput.scss b/nezha-fronted/src/assets/css/components/page/dashboard/explore/promqlInput.scss index 3dbb425b1..6c2200476 100644 --- a/nezha-fronted/src/assets/css/components/page/dashboard/explore/promqlInput.scss +++ b/nezha-fronted/src/assets/css/components/page/dashboard/explore/promqlInput.scss @@ -177,6 +177,12 @@ .el-col .el-col-24 .metric-selector-input-box{ } + .lines-content { + //height: auto !important; + //width: 100% !important; + //position: unset !important; + top: 5px !important; + } } .topo-page { .promqlInput { diff --git a/nezha-fronted/src/components/page/dashboard/explore/logql/getTimeRange.js b/nezha-fronted/src/components/page/dashboard/explore/logql/getTimeRange.js new file mode 100644 index 000000000..7dde0e25e --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/logql/getTimeRange.js @@ -0,0 +1,9 @@ +import { DefaultTimeRange } from '../../variables/interpolation/defaults.js' +import { getClosest } from './utils.js' + +function getTimeRange (sceneObject) { + let _a + return (_a = getClosest(sceneObject, (s) => s.state.$timeRange)) != null ? _a : DefaultTimeRange +} + +export { getTimeRange } diff --git a/nezha-fronted/src/components/page/dashboard/explore/logql/lezerConfig.js b/nezha-fronted/src/components/page/dashboard/explore/logql/lezerConfig.js new file mode 100644 index 000000000..2a2716b43 --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/logql/lezerConfig.js @@ -0,0 +1,908 @@ +const lr = require('@lezer/lr') +const lodash = require('lodash') +// This file was generated by lezer-generator. You probably shouldn't edit it. +const Json$1 = 1 +const Logfmt$1 = 2 +const Unpack$1 = 3 +const Pattern$1 = 4 +const Regexp$1 = 5 +const Unwrap$1 = 6 +const Ip$1 = 7 +const LabelFormat$1 = 8 +const LineFormat$1 = 9 +const LabelReplace$1 = 10 +const Vector$1 = 11 +const Offset$1 = 12 +const Bool$1 = 13 +const On$1 = 14 +const Ignoring$1 = 15 +const GroupLeft$1 = 16 +const GroupRight$1 = 17 +const Decolorize$1 = 18 +const Drop$1 = 19 +const Keep$1 = 20 +const By$1 = 21 +const Without$1 = 22 +const And$1 = 23 +const Or$1 = 24 +const Unless$1 = 25 +const Sum$1 = 26 +const Avg$1 = 27 +const Count$1 = 28 +const Max$1 = 29 +const Min$1 = 30 +const Stddev$1 = 31 +const Stdvar$1 = 32 +const Bottomk$1 = 33 +const Topk$1 = 34 +const LogExpr$1 = 38 +const MetricExpr$1 = 86 + +const keywordTokens = { + json: Json$1, + logfmt: Logfmt$1, + unpack: Unpack$1, + pattern: Pattern$1, + regexp: Regexp$1, + ip: Ip$1, + label_format: LabelFormat$1, + line_format: LineFormat$1, + label_replace: LabelReplace$1, + vector: Vector$1, + offset: Offset$1, + bool: Bool$1, + on: On$1, + ignoring: Ignoring$1, + group_left: GroupLeft$1, + group_right: GroupRight$1, + unwrap: Unwrap$1, + decolorize: Decolorize$1, + drop: Drop$1, + keep: Keep$1 +} + +const specializeIdentifier = (value) => { + return keywordTokens[value.toLowerCase()] || -1 +} + +const contextualKeywordTokens = { + by: By$1, + without: Without$1, + and: And$1, + or: Or$1, + unless: Unless$1, + sum: Sum$1, + avg: Avg$1, + count: Count$1, + max: Max$1, + min: Min$1, + stddev: Stddev$1, + stdvar: Stdvar$1, + bottomk: Bottomk$1, + topk: Topk$1 +} + +const extendIdentifier = (value) => { + return contextualKeywordTokens[value.toLowerCase()] || -1 +} + +// This file was generated by lezer-generator. You probably shouldn't edit it. +// eslint-disable-next-line camelcase +const spec_Identifier = { __proto__: null, count_over_time: 281, rate: 283, rate_counter: 285, bytes_over_time: 287, bytes_rate: 289, avg_over_time: 291, sum_over_time: 293, min_over_time: 295, max_over_time: 297, stddev_over_time: 299, stdvar_over_time: 301, quantile_over_time: 303, first_over_time: 305, last_over_time: 307, absent_over_time: 309, bytes: 315, duration: 317, duration_seconds: 319 } +const parser = lr.LRParser.deserialize({ + version: 14, + states: "CdOYQPOOO#]QPO'#DTO$lQPO'#DSOYQPO'#DSOOQO'#EW'#EWO$yQPO'#EVOOQO'#Es'#EsO%OQPO'#ErQ%ZQPOOOOQO'#FR'#FRO&[QPO'#FRO&aQPO'#FSO&fQPO'#FTOOQO'#EU'#EUOOQO'#DR'#DROOQO'#EX'#EXOOQO'#EY'#EYOOQO'#EZ'#EZOOQO'#E['#E[OOQO'#E]'#E]OOQO'#E^'#E^OOQO'#E_'#E_OOQO'#E`'#E`OOQO'#Ea'#EaOOQO'#Eb'#EbOOQO'#Ec'#EcOOQO'#Ed'#EdOOQO'#Ee'#EeOOQO'#Ef'#EfOOQO'#Eg'#EgO&kQPO'#DVOOQO'#DU'#DUO&yQPO,59oOOQO'#Db'#DbO'RQPO'#DaOOQO'#D`'#D`O'ZQPO'#D_O(tQPO'#D_OOQO'#D^'#D^O*vQPO,59nO,UQPO,59nO,]QPO,5:pO,dQPO,5:qO,oQPO'#EpO.tQPO,5;^O.{QPO,5;^O/QQPO,5;`O/QQPO,5;`O/QQPO,5;`O/QQPO,5;`O/QQPO,5;`O/QQPO,5;`OOQO,5;m,5;mOYQPO,5;nO1^QPO,5;oO1cQPO,59qO#]QPO,59pOOQO1G/Z1G/ZOOQO'#De'#DeOOQO,59{,59{O1hQPO,59{OOQO,59z,59zO1mQPO'#DVO2[QPO'#DgOOQO'#Dg'#DgO3xQPO'#DgOOQO'#Dm'#DmOOQO'#Dk'#DkO)dQPO'#DkO3}QPO,59yO5hQPO'#DyO5mQPO'#DzOOQO'#D}'#D}O5rQPO'#EOO5wQPO'#EROOQO,59y,59yOOQO,59x,59xOOQO1G/Y1G/YOOQO1G0[1G0[O5|QPO'#EhO,gQPO'#EhO6bQPO1G0]O6gQPO1G0]O6lQPO,5;[O6tQPO1G0xO8PQPO1G0xO8WQPO1G0xO8_QPO'#EvO:gQPO'#EuO:qQPO'#EuOYQPO1G0zOYQPO1G0zOYQPO1G0zOYQPO1G0zOYQPO1G0zOYQPO1G0zO:{QPO1G1YO;SQPO1G1ZOOQO1G/]1G/]OOQO1G/[1G/[O;XQPO1G/gO;^QPO,59qO;dQPO,5:YO;oQPO'#DjOOQO'#Di'#DiO;tQPO,5:SOOQO,5:R,5:RO=_QPO,5:VO)dQPO,5:VO)dQPO,5:VOOQO,5:e,5:eO=mQPO'#D|OOQO'#D{'#D{O=rQPO,5:fO?]QPO'#EQOOQO'#EQ'#EQOOQO'#EP'#EPO@|QPO,5:jOBgQPO'#ETOOQO'#ET'#ETOOQO'#ES'#ESODWQPO,5:mOEqQPO'#D_O5|QPO,5;SOExQPO'#EiOE}QPO,5;SOFhQPO,5;SOFrQPO,5;SOFyQPO,5;SOGOQPO7+%wO,gQPO7+%wOOQO'#Eq'#EqOH`QPO1G0vOOQO1G0v1G0vOHhQPO7+&dOYQPO7+&dOIxQPO7+&dOJPQPO7+&dOJWQQO'#EwOOQO,5;b,5;bOL`QPO,5;aOLgQPO,5;aOMxQPO7+&fONPQPO7+&fOOQO7+&f7+&fON^QPO7+&fONeQPO7+&fO! jQPO7+&fO! zQPO7+&tOOQO7+&u7+&uO!!PQPO7+%RO!!UQPO1G/rOOQO1G/t1G/tOOQO1G/{1G/{OOQO1G/}1G/}O!!ZQPO,5:UO!!`QPO,5:TOOQO1G/q1G/qO!!eQPO1G/qO!$OQPO,5:hO5mQPO,5:gO5rQPO,5:kO5wQPO,5:nO!$WQPO,5;VOE}QPO1G0nO!$fQPO1G0nO!$nQPO,5;TO)dQPO,5;VO!$sQPO1G0nO!$zQPO'#EjO!%PQPO1G0nO!$sQPO1G0nO!%XQPO1G0nO!%`QPO1G0nO6]QPO1G0nOOQO1G0n1G0nOOQO<}OOQO1G0w1G0wO!*xQPOAN?jO!,YQPOAN?jO!,aQQO1G0}OOQO1G0}1G0}OOQO7+&g7+&gO!,iQPOAN?zO!,nQPO<dAN>dO!-lQPO< (specializeIdentifier(value) << 1) }, { term: 42, get: (value, stack) => (extendIdentifier(value) << 1) | 1 }, { term: 42, get: value => spec_Identifier[value] || -1 }], + tokenPrec: 0 +}) +// This file was generated by lezer-generator. You probably shouldn't edit it. +const Json = 1 +const Logfmt = 2 +const Unpack = 3 +const Pattern = 4 +const Regexp = 5 +const Unwrap = 6 +const Ip = 7 +const LabelFormat = 8 +const LineFormat = 9 +const LabelReplace = 10 +const Vector = 11 +const Offset = 12 +const Bool = 13 +const On = 14 +const Ignoring = 15 +const GroupLeft = 16 +const GroupRight = 17 +const Decolorize = 18 +const Drop = 19 +const Keep = 20 +const By = 21 +const Without = 22 +const And = 23 +const Or = 24 +const Unless = 25 +const Sum = 26 +const Avg = 27 +const Count = 28 +const Max = 29 +const Min = 30 +const Stddev = 31 +const Stdvar = 32 +const Bottomk = 33 +const Topk = 34 +const LineComment = 35 +const LogQL = 36 +const Expr = 37 +const LogExpr = 38 +const Selector = 39 +const Matchers = 40 +const Matcher = 41 +const Identifier = 42 +const Eq = 43 +const String = 44 +const Neq = 45 +const Re = 46 +const Nre = 47 +const PipelineExpr = 48 +const PipelineStage = 49 +const LineFilters = 50 +const LineFilter = 51 +const Filter = 52 +const PipeExact = 53 +const PipeMatch = 54 +const FilterOp = 55 +const Pipe = 56 +const LabelParser = 57 +const JsonExpressionParser = 58 +const JsonExpressionList = 59 +const JsonExpression = 60 +const LabelFilter = 61 +const IpLabelFilter = 62 +const UnitFilter = 63 +const DurationFilter = 64 +const Gtr = 65 +const Duration = 66 +const Gte = 67 +const Lss = 68 +const Lte = 69 +const Eql = 70 +const BytesFilter = 71 +const Bytes = 72 +const NumberFilter = 73 +const Number = 74 +const LineFormatExpr = 75 +const LabelFormatExpr = 76 +const LabelsFormat = 77 +const LabelFormatMatcher = 78 +const DecolorizeExpr = 79 +const DropLabelsExpr = 80 +const DropLabels = 81 +const DropLabel = 82 +const KeepLabelsExpr = 83 +const KeepLabels = 84 +const KeepLabel = 85 +const MetricExpr = 86 +const RangeAggregationExpr = 87 +const RangeOp = 88 +const CountOverTime = 89 +const Rate = 90 +const RateCounter = 91 +const BytesOverTime = 92 +const BytesRate = 93 +const AvgOverTime = 94 +const SumOverTime = 95 +const MinOverTime = 96 +const MaxOverTime = 97 +const StddevOverTime = 98 +const StdvarOverTime = 99 +const QuantileOverTime = 100 +const FirstOverTime = 101 +const LastOverTime = 102 +const AbsentOverTime = 103 +const LogRangeExpr = 104 +const Range = 105 +const OffsetExpr = 106 +const UnwrapExpr = 107 +const ConvOp = 108 +const BytesConv = 109 +const DurationConv = 110 +const DurationSecondsConv = 111 +const Grouping = 112 +const Labels = 113 +const VectorAggregationExpr = 114 +const VectorOp = 115 +const BinOpExpr = 116 +const BinOpModifier = 117 +const OnOrIgnoringModifier = 118 +const GroupingLabels = 119 +const GroupingLabelList = 120 +const GroupingLabel = 121 +const LabelName = 122 +const Add = 123 +const Sub = 124 +const Mul = 125 +const Div = 126 +const Mod = 127 +const Pow = 128 +const LiteralExpr = 129 +const LabelReplaceExpr = 130 +const VectorExpr = 131 + +function getNodeFromQuery (query, nodeType) { + const nodes = [] + const tree = parser.parse(query) + tree.iterate({ + enter: (node) => { + if (nodeType === undefined || nodeType === node.type.id) { + nodes.push(node.node) + } + } + }) + return nodes[0] +} + +function isLogsQuery (query) { + if (getNodeFromQuery(query, MetricExpr$1)) { + return false + } + return true +} + +function indent (level) { + return ' '.repeat(level) +} + +function indentMultiline (block, level) { + const lines = block.split('\n') + return lines.map((line) => indent(level) + line).join('\n') +} + +function trimMultiline (block) { + const lines = block.split('\n') + return lines.map((line) => line.trimEnd()).join('\n') +} + +function needsBrackets (node, queryType) { + const childNodeIsSame = node.firstChild && (node.firstChild.type.id === queryType) + let addBrackets = false + + if (node.firstChild && childNodeIsSame) { + addBrackets = true + node = node.firstChild + } + + return { addBrackets, newNode: node } +} + +function iterateNode (node, lookingFor) { + const nodes = [] + let child = node.firstChild + + while (child) { + if (lookingFor.includes(child.type.id)) { + nodes.push(child) + } + + nodes.push(...iterateNode(child, lookingFor)) + child = child.nextSibling + } + + return nodes +} + +function buildResponse (pipelineType, lastPipelineType, formattedNode) { + if (lastPipelineType === pipelineType) { + return ` ${formattedNode}` + } + + return `\n${indent(1)}${formattedNode}` +} + +function trimEnd (input, charactersToTrim) { + let endIndex = input.length - 1 + while (endIndex >= 0 && charactersToTrim.includes(input[endIndex])) { + endIndex-- + } + return input.substring(0, endIndex + 1) +} + +const formatLogExpr = (node, query) => { + const { addBrackets, newNode } = needsBrackets(node, LogExpr) + node = newNode + + const tree = parser.parse(query.substring(node.from, node.to)) + let formatted = '' + + tree.iterate({ + enter: (ref) => { + const node = ref.node + + switch (node.type.id) { + case Selector: + formatted += formatSelector(node, query) + break + + case PipelineExpr: + node.parent && (node.parent.type.id !== PipelineExpr && (formatted += formatPipelineExpr(node, query))) + break + } + } + }) + + return addBrackets ? '(' + formatted + ')' : formatted +} + +function formatSelector (node, query) { + const selector = query.substring(node.from, node.to) + const subtree = parser.parse(selector) + const labelNodes = [] + let response = '' + + subtree.iterate({ + enter: (ref) => { + const node = ref.node + if (node.type.id === Matcher) { + labelNodes.push(node) + } + } + }) + + labelNodes.sort((a, b) => { + const labelNodeA = a.getChild(Identifier) + const labelNodeB = b.getChild(Identifier) + + const labelValueA = labelNodeA && query.substring(labelNodeA.from, labelNodeA.to) + const labelValueB = labelNodeB && query.substring(labelNodeB.from, labelNodeB.to) + + if (!labelValueA || !labelValueB) { + return 0 + } + + if (labelValueA < labelValueB) { + return -1 + } + + if (labelValueA > labelValueB) { + return 1 + } + + return 0 + }) + + labelNodes.forEach((node) => { + const labelNode = node.getChild(Identifier) + const operatorNode = labelNode ? labelNode.nextSibling : null + const valueNode = node.getChild(String) + + const label = labelNode ? query.substring(labelNode.from, labelNode.to) : null + const operator = operatorNode ? query.substring(operatorNode.from, operatorNode.to) : null + const value = valueNode ? query.substring(valueNode.from, valueNode.to) : null + + response += `${label}${operator}${value}, ` + }) + + return '{' + trimEnd(response, ', ') + '}' +} + +function formatPipelineExpr (node, query) { + const pipelineExprNodes = [ + LineFilter, + LabelParser, + LabelFilter, + JsonExpressionParser, + LineFormatExpr, + LabelFormatExpr, + DecolorizeExpr + ] + let lastPipelineType + let response = '' + + iterateNode(node, pipelineExprNodes).forEach((node) => { + switch (node.type.id) { + case LineFilter: + response += buildResponse(LineFilter, lastPipelineType, formatLineFilter(node, query)) + lastPipelineType = LineFilter + break + + case LabelParser: + response += buildResponse(LabelParser, lastPipelineType, formatLabelParser(node, query)) + lastPipelineType = LabelParser + break + + case JsonExpressionParser: + response += buildResponse(JsonExpressionParser, lastPipelineType, formatJsonExpressionParser(node, query)) + lastPipelineType = JsonExpressionParser + break + + case LabelFilter: + response += buildResponse(LabelFilter, lastPipelineType, formatLabelFilter(node, query)) + lastPipelineType = LabelFilter + break + + case LineFormatExpr: + response += buildResponse(LineFormatExpr, lastPipelineType, formatLineFormatExpr(node, query)) + lastPipelineType = LineFormatExpr + break + + case LabelFormatExpr: + response += buildResponse(LabelFormatExpr, lastPipelineType, formatLabelFormatExpr(node, query)) + lastPipelineType = LabelFormatExpr + break + + case DecolorizeExpr: + response += buildResponse(DecolorizeExpr, lastPipelineType, formatDecolorizeExpr()) + lastPipelineType = DecolorizeExpr + break + } + }) + + return response +} + +function formatLineFilter (node, query) { + const filterNode = node.getChild(Filter) + const filterOperationNode = node.getChild(FilterOp) + const stringNode = node.getChild(String) + + const filter = filterNode && query.substring(filterNode.from, filterNode.to) + const string = stringNode && query.substring(stringNode.from, stringNode.to) + + if (filterOperationNode) { + return `${filter} ip(${string})` + } + return `${filter} ${string}` +} + +function formatLabelParser (node, query) { + const hasString = node.getChild(String) + + if (hasString) { + const parserNode = node.getChild(Regexp) || node.getChild(Pattern) + const stringNode = node.getChild(String) + + const parser = parserNode && query.substring(parserNode.from, parserNode.to) + const string = stringNode && query.substring(stringNode.from, stringNode.to) + + return `| ${parser}${string}` + } + + const labelParser = query.substring(node.from, node.to) + return `| ${labelParser}` +} + +function formatJsonExpressionParser (node, query) { + const jsonExpressionNodes = iterateNode(node, [JsonExpression]) + let response = '' + + jsonExpressionNodes.forEach((node) => { + const identifierNode = node.getChild(Identifier) + const valueNode = node.getChild(String) + + const identifier = identifierNode && query.substring(identifierNode.from, identifierNode.to) + const value = valueNode && query.substring(valueNode.from, valueNode.to) + + response += `${identifier}=${value}, ` + }) + + return `| json ${trimEnd(response, ', ')}` +} + +function formatLabelFilter (node, query) { + const selectedFilter = + node.getChild(Matcher) || + node.getChild(IpLabelFilter) || + node.getChild(NumberFilter) || + (node.getChild(UnitFilter) && node.getChild(UnitFilter).getChild(DurationFilter)) || + (node.getChild(UnitFilter) && (node.getChild(UnitFilter).getChild(BytesFilter))) + + if (!selectedFilter) { + return '' + } + + const selectedFilterType = selectedFilter.type.id + + const identifierNode = selectedFilter.getChild(Identifier) + const operatorNode = identifierNode && identifierNode.nextSibling + let valueNode + + if (selectedFilterType === DurationFilter) { + valueNode = selectedFilter.getChild(Duration) + } else if (selectedFilterType === BytesFilter) { + valueNode = selectedFilter.getChild(Bytes) + } else if (selectedFilterType === NumberFilter) { + valueNode = selectedFilter.getChild(Number) + } else { + valueNode = selectedFilter.getChild(String) + } + + const identifier = identifierNode && query.substring(identifierNode.from, identifierNode.to) + const operator = operatorNode && query.substring(operatorNode.from, operatorNode.to) + const value = valueNode && query.substring(valueNode.from, valueNode.to) + + if (selectedFilterType === IpLabelFilter) { + return `| ${identifier}${operator}ip(${value})` + } + + return `| ${identifier}${operator}${value}` +} + +function formatLineFormatExpr (node, query) { + const stringNode = node.getChild(String) + const string = stringNode && query.substring(stringNode.from, stringNode.to) + return `| line_format ${string}` +} + +function formatLabelFormatExpr (node, query) { + const labelFormatMatcherNodes = iterateNode(node, [LabelFormatMatcher]) + let response = '| label_format ' + + labelFormatMatcherNodes.forEach((labelFormatMatcherNode) => { + let identifierNode + let valueNode + + if (labelFormatMatcherNode.getChildren(Identifier).length === 2) { + [identifierNode, valueNode] = labelFormatMatcherNode.getChildren(Identifier) + } else { + identifierNode = labelFormatMatcherNode.getChild(Identifier) + valueNode = labelFormatMatcherNode.getChild(String) + } + + const identifier = identifierNode && query.substring(identifierNode.from, identifierNode.to) + const value = valueNode && query.substring(valueNode.from, valueNode.to) + + response += `${identifier}=${value}, ` + }) + + return trimEnd(response, ', ') +} + +function formatDecolorizeExpr () { + // eslint-disable-next-line quotes + return `| decolorize` +} + +const formatMetricExpr = (node, query) => { + const { addBrackets, newNode } = needsBrackets(node, MetricExpr) + node = newNode + let formatted = '' + + const childNode = node.firstChild + switch (childNode && childNode.type.id) { + case RangeAggregationExpr: + formatted = formatRangeAggregationExpr(node, query) + break + + case VectorAggregationExpr: + formatted = formatVectorAggregationExpr(node, query) + break + + case BinOpExpr: + formatted = formatBinOpExpr(node, query) + break + + case LiteralExpr: + formatted = formatLiteralExpr(node, query) + break + + case LabelReplaceExpr: + formatted = formatLabelReplaceExpr(node, query) + break + + case VectorExpr: + formatted = formatVectorExpr(node, query) + break + } + + return addBrackets ? '(' + formatted + ')' : formatted +} + +function formatRangeAggregationExpr (node, query) { + let response = '' + + iterateNode(node, [RangeOp, Number, LogRangeExpr, Grouping]).forEach((node) => { + if (node.parent && (node.parent.type.id !== RangeAggregationExpr)) { + return + } + + switch (node.type.id) { + case RangeOp: + response += `${query.substring(node.from, node.to)}(\n` + break + + case Number: + response += `${indent(1) + query.substring(node.from, node.to)},\n` + break + + case LogRangeExpr: + response += formatLogRangeExpr(node, query) + break + + case Grouping: + response += formatGrouping(node, query) + break + } + }) + + return response +} + +function formatLogRangeExpr (node, query) { + const nodes = [] + let selector = '' + let pipeline = '' + let range = '' + let offset = '' + let unwrap = '' + + iterateNode(node, [Selector, Range, OffsetExpr, UnwrapExpr, PipelineExpr]).forEach((node) => { + if (node.parent && (node.parent.type.id !== LogRangeExpr)) { + return + } + + nodes.push(node) + + switch (node.type.id) { + case Selector: { + const logExpr = query.substring(node.from, node.to) + selector += formatSelector({ ...node, from: 0, to: logExpr.length }, logExpr) + break + } + + case PipelineExpr: + pipeline += formatPipelineExpr(node, query) + break + + case Range: + range += query.substring(node.from, node.to) + break + + case OffsetExpr: { + const durationNode = node.getChild(Duration) + offset += ` offset ${durationNode ? query.substring(durationNode.from, durationNode.to) : ''}` + break + } + + case UnwrapExpr: + iterateNode(node, [Identifier, ConvOp, LabelFilter]).forEach((node, _, arr) => { + switch (node.type.id) { + case Identifier: { + if (node.parent && (node.parent.type.id !== UnwrapExpr)) { + return + } + + const hasConvOp = arr.find((node) => node.type.id === ConvOp) + + if (hasConvOp) { + return + } + + unwrap += `| unwrap ${query.substring(node.from, node.to)} ` + return + } + + case ConvOp: { + const identifierNode = arr.find((node) => node.type.id === Identifier) + const identifier = identifierNode ? query.substring(identifierNode.from, identifierNode.to) : '' + unwrap += `| unwrap ${query.substring(node.from, node.to)}(${identifier}) ` + return + } + + case LabelFilter: + unwrap += formatLabelFilter(node, query) + } + }) + break + } + }) + + let response = '' + nodes.forEach((node, index, array) => { + const previousNode = array[index - 1] + + if (node.type.id === Selector) { + response += indent(1) + selector + } + + if (node.type.id === PipelineExpr) { + response += indentMultiline(pipeline, 1) + } + + if (node.type.id === Range) { + response += '\n' + indent(1) + range + } + + if (node.type.id === OffsetExpr) { + response += offset + } + + if (node.type.id === UnwrapExpr) { + if (previousNode && ((previousNode.type.id !== OffsetExpr)) && (previousNode && (previousNode.type.id !== Range))) { + response += '\n' + indent(1) + unwrap + } else { + response += ' ' + unwrap + } + } + }) + + return (response += '\n)') +} + +function formatGrouping (node, query) { + let response = '' + + const labels = iterateNode(node, [Identifier]).map((node) => { + return query.substring(node.from, node.to) + }) + + iterateNode(node, [By, Without]).forEach((node) => { + if (node.parent && (node.parent.type.id !== Grouping)) { + return + } + + switch (node.type.id) { + case By: + response = ` by (${labels.join(', ')}) ` + break + + case Without: + response = ` without (${labels.join(', ')}) ` + break + } + }) + + return response +} + +function formatVectorAggregationExpr (node, query) { + let response = '' + + iterateNode(node, [VectorOp, Number, MetricExpr, Grouping]).forEach((node, _, arr) => { + if (node.parent && (node.parent.type.id !== VectorAggregationExpr)) { + return + } + + switch (node.type.id) { + case VectorOp: + response += `${query.substring(node.from, node.to)}` + break + + case Number: + response += '(\n' + response += `${indent(1) + query.substring(node.from, node.to)},\n` + break + + case MetricExpr: { + const hasNumber = arr.find((node) => node.type.id === Number && node.parent.type.id === VectorAggregationExpr) + response += hasNumber ? '' : '(\n' + + const metricExpr = query.substring(node.from, node.to) + const metricNode = getNodeFromQuery(metricExpr, MetricExpr) + response += indentMultiline(formatMetricExpr(metricNode, metricExpr), 1) + response += '\n)' + break + } + + case Grouping: + response += formatGrouping(node, query) + break + } + }) + + return response +} + +function formatBinOpExpr (node, query) { + let operator + + const [leftExpr, rightExpr] = iterateNode(node, [Expr]).map((node, idx) => { + if (idx === 0) { + operator = query.substring(node.nextSibling.from || 0, node.nextSibling.to) + } + + const expr = query.substring(node.from, node.to) + let expressionNode + + if (isLogsQuery(expr)) { + expressionNode = getNodeFromQuery(expr, LogExpr$1) + return formatLogExpr(expressionNode, expr) + } else { + expressionNode = getNodeFromQuery(expr, MetricExpr) + return formatMetricExpr(expressionNode, expr) + } + }) + + return leftExpr + '\n' + operator + '\n' + rightExpr +} + +function formatLiteralExpr (node, query) { + node = node.getChild(LiteralExpr) || node + const addNode = node.getChild(Add) + const subNode = node.getChild(Sub) + const numberNode = node.getChild(Number) + + if (!numberNode) { + return '' + } + + if (addNode) { + return `+${query.substring(numberNode.from, numberNode.to)}` + } + + if (subNode) { + return `-${query.substring(numberNode.from, numberNode.to)}` + } + + return query.substring(numberNode.from, numberNode.to) +} + +function formatLabelReplaceExpr (node, query) { + let response = 'label_replace(\n' + + iterateNode(node, [MetricExpr, String]).forEach((node) => { + if (node.parent.type.id !== LabelReplaceExpr) { + return + } + + if (node.type.id === MetricExpr) { + const metricExpr = query.substring(node.from, node.to) + const metricNode = getNodeFromQuery(metricExpr, MetricExpr) + response += indentMultiline(formatMetricExpr(metricNode, metricExpr), 1) + ',\n' + } else { + response += indent(1) + query.substring(node.from, node.to) + ',\n' + } + }) + + return trimEnd(response, ',\n') + '\n)' +} + +function formatVectorExpr (node, query) { + node = node.getChild(VectorExpr) || node + const numberNode = node.getChild(Number) + + if (!numberNode) { + return '' + } + + return `vector(${query.substring(numberNode.from, numberNode.to)})` +} + +/** + * @experimental This feature is subject to change or removal in future versions. + */ +const formatLokiQuery = (query) => { + const tree = parser.parse(query) + let formatted = '' + + tree.iterate({ + enter: (ref) => { + const node = ref.node + + if (lodash.get(node, 'parent.type.id', '') !== Expr || lodash.get(node,'parent.parent.type.id', '') === BinOpExpr) { + return + } + + switch (node.type.id) { + case MetricExpr: + formatted = formatMetricExpr(node, query) + return false + + case LogExpr: + formatted = formatLogExpr(node, query) + return false + } + } + }) + return trimMultiline(formatted) +} + +export { AbsentOverTime, Add, And, Avg, AvgOverTime, BinOpExpr, BinOpModifier, Bool, Bottomk, By, Bytes, BytesConv, BytesFilter, BytesOverTime, BytesRate, ConvOp, Count, CountOverTime, Decolorize, DecolorizeExpr, Div, Drop, DropLabel, DropLabels, DropLabelsExpr, Duration, DurationConv, DurationFilter, DurationSecondsConv, Eq, Eql, Expr, Filter, FilterOp, FirstOverTime, GroupLeft, GroupRight, Grouping, GroupingLabel, GroupingLabelList, GroupingLabels, Gte, Gtr, Identifier, Ignoring, Ip, IpLabelFilter, Json, JsonExpression, JsonExpressionList, JsonExpressionParser, Keep, KeepLabel, KeepLabels, KeepLabelsExpr, LabelFilter, LabelFormat, LabelFormatExpr, LabelFormatMatcher, LabelName, LabelParser, LabelReplace, LabelReplaceExpr, Labels, LabelsFormat, LastOverTime, LineComment, LineFilter, LineFilters, LineFormat, LineFormatExpr, LiteralExpr, LogExpr, LogQL, LogRangeExpr, Logfmt, Lss, Lte, Matcher, Matchers, Max, MaxOverTime, MetricExpr, Min, MinOverTime, Mod, Mul, Neq, Nre, Number, NumberFilter, Offset, OffsetExpr, On, OnOrIgnoringModifier, Or, Pattern, Pipe, PipeExact, PipeMatch, PipelineExpr, PipelineStage, Pow, QuantileOverTime, Range, RangeAggregationExpr, RangeOp, Rate, RateCounter, Re, Regexp, Selector, Stddev, StddevOverTime, Stdvar, StdvarOverTime, String, Sub, Sum, SumOverTime, Topk, UnitFilter, Unless, Unpack, Unwrap, UnwrapExpr, Vector, VectorAggregationExpr, VectorExpr, VectorOp, Without, formatLokiQuery, parser } diff --git a/nezha-fronted/src/components/page/dashboard/explore/logql/logql.vue b/nezha-fronted/src/components/page/dashboard/explore/logql/logql.vue new file mode 100644 index 000000000..a41f16392 --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/logql/logql.vue @@ -0,0 +1,388 @@ + + + + + diff --git a/nezha-fronted/src/components/page/dashboard/explore/logql/logqlMixin.js b/nezha-fronted/src/components/page/dashboard/explore/logql/logqlMixin.js new file mode 100644 index 000000000..629341e11 --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/logql/logqlMixin.js @@ -0,0 +1,340 @@ +import { languageConfiguration, monarchlanguage } from './monacoConfig' +import { parser, formatLokiQuery } from './lezerConfig' +import { getSituation } from './situation' +export default { + data () { + return { + code: '', + LANGUAGE_SETUP_STARTED: false, + parser, + MONACO_EDITOR_OPTIONS: { + automaticLayout: true, + formatOnType: true, + formatOnPaste: true, + codeLens: false, + contextmenu: false, + // we need `fixedOverflowWidgets` because otherwise in grafana-dashboards + // the popup is clipped by the panel-visualizations. + fixedOverflowWidgets: true, + folding: false, + fontSize: 14, + lineDecorationsWidth: 8, // used as "padding-left" + lineNumbers: 'off', + minimap: { enabled: false }, + overviewRulerBorder: false, + overviewRulerLanes: 0, + padding: { + // these numbers were picked so that visually this matches the previous version + // of the query-editor the best + top: 10, + bottom: 5 + }, + renderLineHighlight: 'none', + scrollbar: { + // vertical: 'hidden', + verticalScrollbarSize: 8, // used as "padding-right" + horizontal: 'hidden', + horizontalScrollbarSize: 0 + }, + scrollBeyondLastLine: false, + suggest: { + showWords: true, + /** + * Enable custom contextmenu. + * Defaults to false. + */ + contextmenu: true, + /** + * The number of spaces a tab is equal to. + * This setting is overridden based on the file contents when `detectIndentation` is on. + * Defaults to 4. + */ + tabSize: 4, + /** + * Show code lens + * Defaults to false. + */ + codeLens: true, + /** + * Control the width of line numbers, by reserving horizontal space for rendering at least an amount of digits. + * Defaults to 4. + */ + lineNumbersMinChars: 4, + /** + * The width reserved for line decorations (in px). + * Line decorations are placed between line numbers and the editor content. + * You can pass in a string in the format floating point followed by "ch". e.g. 1.3ch. + * Defaults to 1 * theme.spacing.gridSize. + */ + // lineDecorationsWidth?: number | string; + /** + * Controls if a border should be drawn around the overview ruler. + * Defaults to `false`. + */ + overviewRulerBorder: false, + /** + * Enable that the editor will install an interval to check if its container dom node size has changed. + * Enabling this might have a severe performance impact. + * Defaults to true. + */ + automaticLayout: true + }, + suggestFontSize: 12, + wordWrap: 'on', + placeHolderScopedVars: { + __interval: { text: '1s', value: '1s' }, + __auto: { text: '1s', value: '1s' }, + __interval_ms: { text: '1000', value: 1000 }, + __range_ms: { text: '1000', value: 1000 }, + __range_s: { text: '1', value: 1 }, + __range: { text: '1s', value: '1s' } + }, + }, + monacoEditorHeight: 30, + templateSrv: '' + } + }, + methods: { + handleChange (value, event) { + this.heightChange() + }, + heightChange () { + const dom = this.$refs.monacoEditor.$el + const el = dom.getElementsByClassName('view-line') + const height = 11 + el.length * 19 + if (this.monacoEditorHeight !== height) { + this.monacoEditorHeight = height + } + }, + handleMount (editor) { + // const dom = this.$refs.monacoEditor.$el + // const el = dom.getElementsByClassName('view-lines') + // if (el && el[0]) { + // el[0].addEventListener('DOMNodeInserted', this.heightChange) + // } + }, + handelBeforeMount (monaco) { + const LANG_ID = 'logql' + const self = this + if (!window.LANGUAGE_SETUP_STARTED) { + window.LANGUAGE_SETUP_STARTED = true + // console.log(monaco) + monaco.languages.register({ id: LANG_ID }) + monaco.languages.setLanguageConfiguration(LANG_ID, languageConfiguration) + monaco.languages.setMonarchTokensProvider(LANG_ID, monarchlanguage) + monaco.editor.defineTheme('nz', { + base: 'vs', + inherit: true, + colors: { + 'editor.background': '#ffffff', + 'minimap.background': '#f9f9f9' + }, + // fallback syntax highlighting for languages that microsoft doesn't handle (ex cloudwatch's metric math) + rules: [ + { token: 'predefined', foreground: '#FF6600' }, + { token: 'operator', foreground: '#009966' }, + { token: 'tag', foreground: '#006699' } + ] + }) + monaco.languages.registerCompletionItemProvider('logql', { + provideCompletionItems: (model, position) => { + const suggestions = [ + ...monarchlanguage.keywords.map(k => { + // console.log(k) + return { + label: k, + kind: monaco.languages.CompletionItemKind.Keyword, + insertText: k + } + }) + ] + return { suggestions: suggestions } + } + }) + } + }, + nzSuggest (model, position) { + // console.log(model, position) + const suggestions = [] + // console.log(parser.parse(this.code)) + return suggestions + }, + suggest (model, position) { + const monaco = this.$refs.monacoEditor.monaco + const self = this + const word = model.getWordAtPosition(position) + const INSERT_AS_SNIPPET_ENUM_VALUE = 4 + console.log(monaco.Range.fromPositions(position)) + const range = monaco.Range.fromPositions(position) + // documentation says `position` will be "adjusted" in `getOffsetAt` + // i don't know what that means, to be sure i clone it + const positionClone = { + column: position.column, + lineNumber: position.lineNumber + } + const offset = model.getOffsetAt(positionClone) + console.log(offset) + const situation = getSituation(model.getValue(), offset) + console.log(situation) + const completionsPromise = situation != null ? Promise.resolve([]) : Promise.resolve([]) + return completionsPromise.then((items) => { + // monaco by default alphabetically orders the items. + // to stop it, we use a number-as-string sortkey, + // so that monaco keeps the order we use + const maxIndexDigits = items.length.toString().length + const suggestions = items.map((item, index) => ({ + kind: self.getMonacoCompletionItemKind(item.type, monaco), + label: item.label, + insertText: item.insertText, + insertTextRules: item.isSnippet ? INSERT_AS_SNIPPET_ENUM_VALUE : undefined, + detail: item.detail, + documentation: item.documentation, + sortText: index.toString().padStart(maxIndexDigits, '0'), // to force the order we have + range, + command: item.triggerOnInsert + ? { + id: 'editor.action.triggerSuggest', + title: '' + } + : undefined + })) + return { suggestions } + }) + }, + getMonacoCompletionItemKind (type, monaco) { + switch (type) { + case 'DURATION': + return monaco.languages.CompletionItemKind.Unit + case 'FUNCTION': + return monaco.languages.CompletionItemKind.Variable + case 'HISTORY': + return monaco.languages.CompletionItemKind.Snippet + case 'LABEL_NAME': + return monaco.languages.CompletionItemKind.Enum + case 'LABEL_VALUE': + return monaco.languages.CompletionItemKind.EnumMember + case 'PATTERN': + return monaco.languages.CompletionItemKind.Constructor + case 'PARSER': + return monaco.languages.CompletionItemKind.Class + case 'LINE_FILTER': + return monaco.languages.CompletionItemKind.TypeParameter + case 'PIPE_OPERATION': + return monaco.languages.CompletionItemKind.Interface + default: + return `Unexpected case in switch statement: ${JSON.stringify(type)}` + } + }, + interpolateString (string, scopedVars) { + return this.interpolate(string, scopedVars, this.interpolateQueryExpr) + }, + interpolateQueryExpr (value, variable) { + // if no multi or include all do not regexEscape + if (!variable.multi && !variable.includeAll) { + return this.lokiRegularEscape(value) + } + + if (typeof value === 'string') { + return this.lokiSpecialRegexEscape(value) + } + + const escapedValues = this.$lodash.map(value, this.lokiSpecialRegexEscape) + return escapedValues.join('|') + }, + lokiRegularEscape (value) { + if (typeof value === 'string') { + return value.replace(/'/g, "\\\\'") + } + return value + }, + lokiSpecialRegexEscape (value) { + if (typeof value === 'string') { + return this.lokiRegularEscape(value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()|]/g, '\\\\$&')) + } + return value + }, + setPlaceholder (monaco, editor) { + const placeholderDecorators = [ + { + range: new monaco.Range(1, 1, 1, 1), + options: { + className: 'nz-eqweqwe', + isWholeLine: true + } + } + ] + + let decorators = [] + + const checkDecorators = () => { + const model = editor.getModel() + + if (!model) { + return + } + + const newDecorators = model.getValueLength() === 0 ? placeholderDecorators : [] + decorators = model.deltaDecorations(decorators, newDecorators) + } + + checkDecorators() + editor.onDidChangeModelContent(checkDecorators) + }, + interpolate (target, scopedVars, format, interpolations) { + if (scopedVars && scopedVars.__sceneObject) { + return sceneGraph.interpolate( + scopedVars.__sceneObject.value, + target, + scopedVars, + format + ) + } + + if (!target) { + return target || '' + } + + this.regex.lastIndex = 0 + + return this._replaceWithVariableRegex(target, format, (match, variableName, fieldPath, fmt) => { + const value = this._evaluateVariableExpression(match, variableName, fieldPath, fmt, scopedVars) + + // If we get passed this interpolations map we will also record all the expressions that were replaced + if (interpolations) { + interpolations.push({ match, variableName, fieldPath, format: fmt, value, found: value !== match }) + } + + return value + }) + }, + sceneInterpolator (sceneObject, target, scopedVars, format) { + const VARIABLE_REGEX = /\$(\w+)|\[\[(\w+?)(?::(\w+))?\]\]|\${(\w+)(?:\.([^:^\}]+))?(?::([^\}]+))?}/g + if (!target) { + return target != null ? target : '' + } + VARIABLE_REGEX.lastIndex = 0 + return target.replace(VARIABLE_REGEX, (match, var1, var2, fmt2, var3, fieldPath, fmt3) => { + const variableName = var1 || var2 || var3 + const fmt = fmt2 || fmt3 || format + const variable = this.lookupFormatVariable(variableName, match, scopedVars, sceneObject) + if (!variable) { + return match + } + return this.formatValue(variable, variable.getValue(fieldPath), fmt) + }) + }, + formatValue (variable, value, formatNameOrFn) { + if (value === null || value === 0) { + return '' + } else { + return value + } + }, + lookupFormatVariable (name, match, scopedVars, sceneObject) { + console.log(name, match, scopedVars, sceneObject) + return null + } + }, + beforeDestroy () { + } +} diff --git a/nezha-fronted/src/components/page/dashboard/explore/logql/monacoConfig.js b/nezha-fronted/src/components/page/dashboard/explore/logql/monacoConfig.js new file mode 100644 index 000000000..a78480f83 --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/logql/monacoConfig.js @@ -0,0 +1,198 @@ +'use strict' +Object.defineProperty(exports, '__esModule', { value: true }) +exports.monarchlanguage = exports.languageConfiguration = 0 +exports.languageConfiguration = { + // the default separators except `@$` + wordPattern: /(-?\d*\.\d\w*)|([^`~!#%^&*()\-=+\[{\]}\\|;:'",.<>\/?\s]+)/g, + comments: { + lineComment: '#' + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ], + autoClosingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '`', close: '`' } + ], + surroundingPairs: [ + { open: '{', close: '}' }, + { open: '[', close: ']' }, + { open: '(', close: ')' }, + { open: '"', close: '"' }, + { open: "'", close: "'" }, + { open: '`', close: '`' }, + { open: '<', close: '>' } + ], + folding: {} +} +// LogQL built-in aggregation operators +// https://grafana.com/docs/loki/latest/logql/metric_queries/#built-in-aggregation-operators +const aggregations = [ + 'sum', + 'avg', + 'min', + 'max', + 'stddev', + 'stdvar', + 'count', + 'topk', + 'bottomk' +] +// LogQL parser expressions +// https://grafana.com/docs/loki/latest/logql/log_queries/#parser-expression +const parsers = ['json', 'logfmt', 'regexp', 'unpack', 'pattern'] +// LogQL format expressions +// https://grafana.com/docs/loki/latest/logql/log_queries/#parser-expression +// eslint-disable-next-line camelcase +const format_expressions = ['line_format', 'label_format'] +// LogQL vector aggregations +// https://grafana.com/docs/loki/latest/logql/metric_queries/#range-vector-aggregation +// eslint-disable-next-line camelcase +const vector_aggregations = [ + 'count_over_time', + 'rate', + 'bytes_over_time', + 'bytes_rate', + 'avg_over_time', + 'sum_over_time', + 'min_over_time', + 'max_over_time', + 'stdvar_over_time', + 'stddev_over_time', + 'quantile_over_time', + 'first_over_time', + 'last_over_time', + 'absent_over_time' +] +// LogQL by and without clauses +// eslint-disable-next-line camelcase +const vector_matching = ['by', 'without'] +// Produce a regex matching elements : (by|without) +const vectorMatchingRegex = '('.concat(vector_matching.reduce(function (prev, curr) { return ''.concat(prev, '|').concat(curr) }), ')') +// LogQL Operators +const operators = [ + '+', + '-', + '*', + '/', + '%', + '^', + '==', + '!=', + '>', + '<', + '>=', + '<=', + '|=', + '!=', + '|~', + '!~', + 'and', + 'or', + 'unless', + '|' +] +// Merging all the keywords in one list +const keywords = aggregations + .concat(parsers) + .concat(format_expressions) + .concat(vector_aggregations) + .concat(vector_matching) +exports.monarchlanguage = { + ignoreCase: false, + defaultToken: '', + tokenPostfix: '.logql', + keywords: keywords, + operators: operators, + vectorMatching: vectorMatchingRegex, + // we include these common regular expressions + symbols: /[=>](?!@symbols)/, '@brackets'], + [ + /@symbols/, + { + cases: { + '@operators': 'delimiter', + '@default': '' + } + } + ], + // numbers + [/\d+(?:ms|[smhdwy])/, 'number'], + [/\d*\d+[eE]([\-+]?\d+)?(@floatsuffix)/, 'number.float'], + [/\d*\.\d+([eE][\-+]?\d+)?(@floatsuffix)/, 'number.float'], + [/0[xX][0-9a-fA-F']*[0-9a-fA-F](@integersuffix)/, 'number.hex'], + [/0[0-7']*[0-7](@integersuffix)/, 'number.octal'], + [/0[bB][0-1']*[0-1](@integersuffix)/, 'number.binary'], + [/\d[\d']*\d(@integersuffix)/, 'number'], + [/\d(@integersuffix)/, 'number'] + ], + string_double: [ + // Set to token: number to differentiate color + [/\{\{(.*?)\}\}/, { token: 'number' }], + [/[^\\"]/, 'string'], + [/@escapes/, 'string.escape'], + [/\\./, 'string.escape.invalid'], + [/"/, 'string', '@pop'] + ], + string_single: [ + [/[^\\']+/, 'string'], + [/@escapes/, 'string.escape'], + [/\\./, 'string.escape.invalid'], + [/'/, 'string', '@pop'] + ], + string_backtick: [ + // Set to token: number to differentiate color + [/\{\{(.*?)\}\}/, { token: 'number' }], + [/[^\\`]/, 'string'], + [/@escapes/, 'string.escape'], + [/\\./, 'string.escape.invalid'], + [/`/, 'string', '@pop'] + ], + clauses: [ + [/[^(,)]/, 'tag'], + [/\)/, 'identifier', '@pop'] + ], + whitespace: [[/[ \t\r\n]+/, 'white']] + } +} diff --git a/nezha-fronted/src/components/page/dashboard/explore/logql/setError.js b/nezha-fronted/src/components/page/dashboard/explore/logql/setError.js new file mode 100644 index 000000000..838c5e8b3 --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/logql/setError.js @@ -0,0 +1,165 @@ +import lodash from 'lodash' +const VARIABLE_REGEX = /\$(\w+)|\[\[(\w+?)(?::(\w+))?\]\]|\${(\w+)(?:\.([^:^\}]+))?(?::([^\}]+))?}/g +class ScopedVarsVariable { + constructor (name, value) { + this.state = { name, value, type: 'scopedvar' } + } + + getValue (fieldPath) { + const { value } = this.state + let realValue = value.value + if (fieldPath) { + realValue = getFieldAccessor(fieldPath)(value.value) + } else { + realValue = value.value + } + if (realValue === 'string' || realValue === 'number' || realValue === 'boolean') { + return realValue + } + return String(realValue) + } + + getValueText () { + const { value } = this.state + if (value.text != null) { + return String(value.text) + } + return String(value) + } +} +export const DataLinkBuiltInVars = { + keepTime: '__url_time_range', + timeRangeFrom: '__from', + timeRangeTo: '__to', + includeVars: '__all_variables', + seriesName: '__series.name', + fieldName: '__field.name', + valueTime: '__value.time', + valueNumeric: '__value.numeric', + valueText: '__value.text', + valueRaw: '__value.raw', + // name of the calculation represented by the value + valueCalc: '__value.calc' +} +class AllVariablesMacro { + constructor (name, sceneObject) { + this.state = { name, type: 'url_variable' } + this._sceneObject = sceneObject + } + + getValue () { + const allVars = collectAllVariables(this._sceneObject) + const format = formatRegistry.get(schema.VariableFormatID.QueryParam) + const params = [] + for (const name of Object.keys(allVars)) { + const variable = allVars[name] + const value = variable.getValue() + if (!value) { + continue + } + if (isCustomVariableValue(value)) { + params.push(value.formatter(schema.VariableFormatID.QueryParam)) + } else { + params.push(format.formatter(value, [], variable)) + } + } + return new SkipFormattingValue(params.join('&')) + } + + getValueText () { + return '' + } +} +const macrosIndex = { + __all_variables: AllVariablesMacro, + __url_time_range: UrlTimeRangeMacro, + __value: ValueMacro, + __data: DataMacro, + __series: SeriesMacro, + __field: FieldMacro, + __url: UrlMacro, + __from: TimeFromAndToMacro, + __to: TimeFromAndToMacro, + __timezone: TimezoneMacro +} +const sceneGraph = { + // getVariables, + // getData, + // getTimeRange, + // getLayout, + interpolate + // lookupVariable, + // hasVariableDependencyInLoadingState, + // findObject +} +function interpolate (sceneObject, value, scopedVars, format) { + if (value === '' || value == null) { + return '' + } + return sceneInterpolator(sceneObject, value, scopedVars, format) +} +function sceneInterpolator (sceneObject, target, scopedVars, format) { + if (!target) { + return target != null ? target : '' + } + VARIABLE_REGEX.lastIndex = 0 + return target.replace(VARIABLE_REGEX, (match, var1, var2, fmt2, var3, fieldPath, fmt3) => { + const variableName = var1 || var2 || var3 + const fmt = fmt2 || fmt3 || format + const variable = lookupFormatVariable(variableName, match, scopedVars, sceneObject) + if (!variable) { + return match + } + return formatValue(variable, variable.getValue(fieldPath), fmt) + }) +} +function lookupFormatVariable (name, match, scopedVars, sceneObject) { + const scopedVar = scopedVars == null ? 0 : scopedVars[name] + if (scopedVar) { + return getSceneVariableForScopedVar(name, scopedVar) + } + const variable = lookupVariable(name, sceneObject) + if (variable) { + return variable + } + if (macrosIndex[name]) { + return new macrosIndex[name](name, sceneObject, match, scopedVars) + } + return null +} +let scopedVarsVariable +function getSceneVariableForScopedVar (name, value) { + if (!scopedVarsVariable) { + scopedVarsVariable = new ScopedVarsVariable(name, value) + } else { + scopedVarsVariable.state.name = name + scopedVarsVariable.state.value = value + } + return scopedVarsVariable +} +const fieldAccessorCache = {} +function getFieldAccessor (fieldPath) { + const accessor = fieldAccessorCache[fieldPath] + if (accessor) { + return accessor + } + return (fieldAccessorCache[fieldPath] = lodash.property(fieldPath)) +} +function lookupVariable (name, sceneObject) { + const variables = sceneObject.state.$variables + if (!variables) { + if (sceneObject.parent) { + return lookupVariable(name, sceneObject.parent) + } else { + return null + } + } + const found = variables.getByName(name) + if (found) { + return found + } else if (sceneObject.parent) { + return lookupVariable(name, sceneObject.parent) + } + return null +} +export default sceneGraph diff --git a/nezha-fronted/src/components/page/dashboard/explore/logql/situation.js b/nezha-fronted/src/components/page/dashboard/explore/logql/situation.js new file mode 100644 index 000000000..cb466b265 --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/logql/situation.js @@ -0,0 +1,559 @@ +import { + parser, + VectorAggregationExpr, + String, + Selector, + RangeAggregationExpr, + Range, + PipelineExpr, + PipelineStage, + Matchers, + Matcher, + LogQL, + LogRangeExpr, + LogExpr, + Identifier, + Grouping, + Expr, + LiteralExpr, + MetricExpr, + UnwrapExpr, + DropLabelsExpr, + KeepLabelsExpr, + DropLabels, + KeepLabels +} from './lezerConfig' + +function getLogQueryFromMetricsQuery (text) { + return text +} + +function move (node, direction) { + return node[direction] +} + +function walk (node, path) { + let current = node + for (const [direction, expectedNode] of path) { + current = move(current, direction) + if (current === null) { + // we could not move in the direction, we stop + return null + } + if (current.type.id !== expectedNode) { + // the reached node has wrong type, we stop + return null + } + } + return current +} + +function getNodeText (node, text) { + return text.slice(node.from, node.to) +} + +function parseStringLiteral (text) { + // If it is a string-literal, it is inside quotes of some kind + const inside = text.slice(1, text.length - 1) + + // Very simple un-escaping: + + // Double quotes + if (text.startsWith('"') && text.endsWith('"')) { + // NOTE: this is not 100% perfect, we only unescape the double-quote, + // there might be other characters too + return inside.replace(/\\"/gm, '"') + } + + // Single quotes + if (text.startsWith("'") && text.endsWith("'")) { + // NOTE: this is not 100% perfect, we only unescape the single-quote, + // there might be other characters too + return inside.replace(/\\'/gm, "'") + } + + // Backticks + if (text.startsWith('`') && text.endsWith('`')) { + return inside + } + + throw new Error(`Invalid string literal: ${text}`) +} + +export const LabelOperator = '=' | '!=' | '=~' | '!~' + +export const Label = {} + +export const Situation = {} + +const Resolver = { + path: [], + fun: (node, text, pos) => Situation +} + +function isPathMatch (resolverPath, cursorPath) { + return resolverPath.every((item, index) => item === cursorPath[index]) +} + +const ERROR_NODE_ID = 0 + +const RESOLVERS = [ + { + path: [Selector], + fun: resolveSelector + }, + { + path: [ERROR_NODE_ID, Matchers, Selector], + fun: resolveSelector + }, + { + path: [LogQL], + fun: resolveTopLevel + }, + { + path: [String, Matcher], + fun: resolveMatcher + }, + { + path: [Grouping], + fun: resolveLabelsForGrouping + }, + { + path: [LogRangeExpr], + fun: resolveLogRange + }, + { + path: [ERROR_NODE_ID, Matcher], + fun: resolveMatcher + }, + { + path: [ERROR_NODE_ID, Range], + fun: resolveDurations + }, + { + path: [ERROR_NODE_ID, LogRangeExpr], + fun: resolveLogRangeFromError + }, + { + path: [ERROR_NODE_ID, LiteralExpr, MetricExpr, VectorAggregationExpr], + fun: () => ({ type: 'IN_AGGREGATION' }) + }, + { + path: [ERROR_NODE_ID, PipelineStage, PipelineExpr], + fun: resolvePipeError + }, + { + path: [ERROR_NODE_ID, UnwrapExpr], + fun: resolveAfterUnwrap + }, + { + path: [UnwrapExpr], + fun: resolveAfterUnwrap + }, + { + path: [ERROR_NODE_ID, DropLabelsExpr], + fun: resolveAfterKeepAndDrop + }, + { + path: [ERROR_NODE_ID, DropLabels], + fun: resolveAfterKeepAndDrop + }, + { + path: [ERROR_NODE_ID, KeepLabelsExpr], + fun: resolveAfterKeepAndDrop + }, + { + path: [ERROR_NODE_ID, KeepLabels], + fun: resolveAfterKeepAndDrop + } +] + +const LABEL_OP_MAP = new Map([ + ['Eq', '='], + ['Re', '=~'], + ['Neq', '!='], + ['Nre', '!~'] +]) + +function getLabelOp (opNode) { + return LABEL_OP_MAP.get(opNode.name) || null +} + +function getLabel (matcherNode, text) { + if (matcherNode.type.id !== Matcher) { + return null + } + + const nameNode = walk(matcherNode, [['firstChild', Identifier]]) + + if (nameNode === null) { + return null + } + + const opNode = nameNode.nextSibling + if (opNode === null) { + return null + } + + const op = getLabelOp(opNode) + if (op === null) { + return null + } + + const valueNode = walk(matcherNode, [['lastChild', String]]) + + if (valueNode === null) { + return null + } + + const name = getNodeText(nameNode, text) + const value = parseStringLiteral(getNodeText(valueNode, text)) + + return { name, value, op } +} + +function getLabels (selectorNode, text) { + if (selectorNode.type.id !== Selector) { + return [] + } + + let listNode = walk(selectorNode, [['firstChild', Matchers]]) + + const labels = [] + + while (listNode !== null) { + const matcherNode = walk(listNode, [['lastChild', Matcher]]) + if (matcherNode !== null) { + const label = getLabel(matcherNode, text) + if (label !== null) { + labels.push(label) + } + } + + // there might be more labels + listNode = walk(listNode, [['firstChild', Matchers]]) + } + + // our labels-list is last-first, so we reverse it + labels.reverse() + + return labels +} + +function resolveAfterUnwrap (node, text, pos) { + return { + type: 'AFTER_UNWRAP', + logQuery: getLogQueryFromMetricsQuery(text).trim() + } +} + +function resolvePipeError (node, text, pos) { + // for example `{level="info"} |` + const exprNode = walk(node, [ + ['parent', PipelineStage], + ['parent', PipelineExpr] + ]) + + if (exprNode === null) { + return null + } + + const { parent } = exprNode + + if (parent === null) { + return null + } + + if (parent.type.id === LogExpr || parent.type.id === LogRangeExpr) { + return resolveLogOrLogRange(parent, text, pos, true) + } + + return null +} + +function resolveLabelsForGrouping (node, text, pos) { + const aggrExpNode = walk(node, [['parent', VectorAggregationExpr]]) + if (aggrExpNode === null) { + return null + } + const bodyNode = aggrExpNode.getChild('MetricExpr') + if (bodyNode === null) { + return null + } + + const selectorNode = walk(bodyNode, [ + ['firstChild', RangeAggregationExpr], + ['lastChild', LogRangeExpr], + ['firstChild', Selector] + ]) + + if (selectorNode === null) { + return null + } + + return { + type: 'IN_GROUPING', + logQuery: getLogQueryFromMetricsQuery(text).trim() + } +} + +function resolveMatcher (node, text, pos) { + // we can arrive here for two reasons. `node` is either: + // - a StringNode (like in `{job="^"}`) + // - or an error node (like in `{job=^}`) + const inStringNode = !node.type.isError + + const parent = walk(node, [['parent', Matcher]]) + if (parent === null) { + return null + } + + const labelNameNode = walk(parent, [['firstChild', Identifier]]) + if (labelNameNode === null) { + return null + } + + const labelName = getNodeText(labelNameNode, text) + + // now we need to go up, to the parent of Matcher, + // there can be one or many `Matchers` parents, we have + // to go through all of them + + const firstListNode = walk(parent, [['parent', Matchers]]) + if (firstListNode === null) { + return null + } + + let listNode = firstListNode + + // we keep going through the parent-nodes as long as they are Matchers. + // as soon as we reach Selector, we stop + let selectorNode = null + while (selectorNode === null) { + const parent = listNode.parent + if (parent === null) { + return null + } + + switch (parent.type.id) { + case Matchers: + // we keep looping + listNode = parent + continue + case Selector: + // we reached the end, we can stop the loop + selectorNode = parent + continue + default: + // we reached some other node, we stop + return null + } + } + + // now we need to find the other names + const allLabels = getLabels(selectorNode, text) + + // we need to remove "our" label from all-labels, if it is in there + const otherLabels = allLabels.filter((label) => label.name !== labelName) + + return { + type: 'IN_LABEL_SELECTOR_WITH_LABEL_NAME', + labelName, + betweenQuotes: inStringNode, + otherLabels + } +} + +function resolveTopLevel (node, text, pos) { + // we try a couply specific paths here. + // `{x="y"}` situation, with the cursor at the end + + const logExprNode = walk(node, [ + ['lastChild', Expr], + ['lastChild', LogExpr] + ]) + + if (logExprNode != null) { + return resolveLogOrLogRange(logExprNode, text, pos, false) + } + + // `s` situation, with the cursor at the end. + // (basically, user enters a non-special characters as first + // character in query field) + const idNode = walk(node, [ + ['firstChild', ERROR_NODE_ID], + ['firstChild', Identifier] + ]) + + if (idNode != null) { + return { + type: 'AT_ROOT' + } + } + + // no patterns match + return null +} + +function resolveDurations (node, text, pos) { + return { + type: 'IN_RANGE' + } +} + +function resolveLogRange (node, text, pos) { + return resolveLogOrLogRange(node, text, pos, false) +} + +function resolveLogRangeFromError (node, text, pos) { + const parent = walk(node, [['parent', LogRangeExpr]]) + if (parent === null) { + return null + } + + return resolveLogOrLogRange(parent, text, pos, false) +} + +function resolveLogOrLogRange (node, text, pos, afterPipe) { + // Here the `node` is either a LogExpr or a LogRangeExpr + // We want to handle the case where we are next to a selector + const selectorNode = walk(node, [['firstChild', Selector]]) + + // Check that the selector is before the cursor, not after it + if (!selectorNode || selectorNode.to > pos) { + return null + } + + return { + type: 'AFTER_SELECTOR', + afterPipe, + hasSpace: text.endsWith(' '), + logQuery: getLogQueryFromMetricsQuery(text).trim() + } +} + +function resolveSelector (node, text, pos) { + // for example `{^}` + + // false positive: + // `{a="1"^}` + const child = walk(node, [['firstChild', Matchers]]) + if (child !== null) { + // means the label-matching part contains at least one label already. + // + // in this case, we will need to have a `,` character at the end, + // to be able to suggest adding the next label. + // the area between the end-of-the-child-node and the cursor-pos + // must contain a `,` in this case. + const textToCheck = text.slice(child.from, pos) + if (!textToCheck.trim().endsWith(',')) { + return null + } + } + + const selectorNode = + node.type.id === ERROR_NODE_ID + ? walk(node, [ + ['parent', Matchers], + ['parent', Selector] + ]) + : node + if (!selectorNode) { + return null + } + + const otherLabels = getLabels(selectorNode, text) + + return { + type: 'IN_LABEL_SELECTOR_NO_LABEL_NAME', + otherLabels + } +} + +function resolveAfterKeepAndDrop (node, text, pos) { + let logQuery = getLogQueryFromMetricsQuery(text).trim() + let keepAndDropParent = null + let parent = node.parent + while (parent !== null) { + if (parent.type.id === PipelineStage) { + keepAndDropParent = parent + break + } + parent = parent.parent + } + + if (keepAndDropParent.type && (keepAndDropParent.type.id === PipelineStage)) { + logQuery = logQuery.slice(0, keepAndDropParent.from) + } + + return { + type: 'AFTER_KEEP_AND_DROP', + logQuery + } +} + +// we find the first error-node in the tree that is at the cursor-position. +// NOTE: this might be too slow, might need to optimize it +// (ideas: we do not need to go into every subtree, based on from/to) +// also, only go to places that are in the sub-tree of the node found +// by default by lezer. problem is, `next()` will go upward too, +// and we do not want to go higher than our node +function getErrorNode (tree, text, cursorPos) { + // sometimes the cursor is a couple spaces after the end of the expression. + // to account for this situation, we "move" the cursor position back, + // so that there are no spaces between the end-of-expression and the cursor + const trimRightTextLen = text.trimEnd().length + console.log(trimRightTextLen) + const pos = trimRightTextLen < cursorPos ? trimRightTextLen : cursorPos + console.log(pos) + const cur = tree.cursorAt(pos) + console.log(cur) + do { + if (cur.from === pos && cur.to === pos) { + const { node } = cur + console.log(node) + console.log(node.type.isError) + if (node.type.isError) { + return node + } + } + } while (cur.next()) + return null +} + +export function getSituation (text, pos) { + // there is a special case when we are at the start of writing text, + // so we handle that case first + + if (text === '') { + return { + type: 'EMPTY' + } + } + + const tree = parser.parse(text) + console.log(tree) + // if the tree contains error, it is very probable that + // our node is one of those error nodes. + // also, if there are errors, the node lezer finds us, + // might not be the best node. + // so first we check if there is an error node at the cursor position + const maybeErrorNode = getErrorNode(tree, text, pos) + console.log(maybeErrorNode) + const cur = maybeErrorNode.cursor().cursorAt(pos) + + const currentNode = cur.node + + const ids = [cur.type.id] + while (cur.parent()) { + ids.push(cur.type.id) + } + + for (const resolver of RESOLVERS) { + if (isPathMatch(resolver.path, ids)) { + return resolver.fun(currentNode, text, pos) + } + } + + return null +} diff --git a/nezha-fronted/src/components/page/dashboard/explore/logqlparser/logqloarser.go b/nezha-fronted/src/components/page/dashboard/explore/logqlparser/logqloarser.go new file mode 100644 index 000000000..7e67f0134 --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/logqlparser/logqloarser.go @@ -0,0 +1,125 @@ +package logql + +import ( + "syscall/js" + "errors" + "fmt" + "strconv" + "strings" + "text/scanner" + + "github.com/prometheus/prometheus/model/labels" +) + +func init() { + // Improve the error messages coming out of yacc. + exprErrorVerbose = true + for str, tok := range tokens { + exprToknames[tok-exprPrivate+1] = str + } + c := make(chan struct{}, 0) + + // 注册函数 + js.Global().Set("parsePromQL", js.FuncOf(parsePromQL)) + + <-c +} + +// ParseExpr parses a string and returns an Expr. +func ParseExpr(input string) (Expr, error) { + l := lexer{ + parser: exprNewParser().(*exprParserImpl), + } + l.Init(strings.NewReader(input)) + l.Scanner.Error = func(_ *scanner.Scanner, msg string) { + l.Error(msg) + } + + e := l.parser.Parse(&l) + if e != 0 || len(l.errs) > 0 { + return nil, l.errs[0] + } + return l.expr, nil +} + +// ParseMatchers parses a string and returns labels matchers, if the expression contains +// anything else it will return an error. +func ParseMatchers(input string) ([]*labels.Matcher, error) { + expr, err := ParseExpr(input) + if err != nil { + return nil, err + } + matcherExpr, ok := expr.(*matchersExpr) + if !ok { + return nil, errors.New("only label matchers is supported") + } + return matcherExpr.matchers, nil +} + +var tokens = map[string]int{ + ",": COMMA, + ".": DOT, + "{": OPEN_BRACE, + "}": CLOSE_BRACE, + "=": EQ, + "!=": NEQ, + "=~": RE, + "!~": NRE, + "|=": PIPE_EXACT, + "|~": PIPE_MATCH, +} + +type lexer struct { + scanner.Scanner + errs []ParseError + expr Expr + parser *exprParserImpl +} + +func (l *lexer) Lex(lval *exprSymType) int { + r := l.Scan() + + switch r { + case scanner.EOF: + return 0 + + case scanner.String: + var err error + lval.str, err = strconv.Unquote(l.TokenText()) + if err != nil { + l.Error(err.Error()) + return 0 + } + return STRING + } + + if tok, ok := tokens[l.TokenText()+string(l.Peek())]; ok { + l.Next() + return tok + } + + if tok, ok := tokens[l.TokenText()]; ok { + return tok + } + + lval.str = l.TokenText() + return IDENTIFIER +} + +func (l *lexer) Error(msg string) { + l.errs = append(l.errs, ParseError{ + msg: msg, + line: l.Line, + col: l.Column, + }) +} + +// ParseError is what is returned when we failed to parse. +type ParseError struct { + msg string + line, col int +} + +func (p ParseError) Error() string { + return fmt.Sprintf("parse error at line %d, col %d: %s", p.line, p.col, p.msg) +} diff --git a/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue b/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue index 60cfdf347..dc1aebb6f 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue @@ -86,20 +86,38 @@ class="not-fixed-height no-resize no-close" > --> - - + + + + + + + + + + + + + + +
+ +
{{ errorMsg }} @@ -459,11 +477,15 @@ import { closeBracketsKeymap } from '@codemirror/autocomplete' import exploreHistory from '@/components/page/dashboard/explore/histoyrComponent/exploreHistory' +import MonacoEditor from 'vue-monaco' +import logqlMixin from '@/components/page/dashboard/explore/logql/logqlMixin' export default { name: 'promqlInput', + mixins: [logqlMixin], components: { selectAlertSilence, - exploreHistory + exploreHistory, + MonacoEditor }, props: { index: { type: Number }, @@ -884,6 +906,11 @@ export default { } }, expressionChange: function () { + if (this.$refs.monacoEditor) { + setTimeout(() => { + this.heightChange() + }, 100) + } this.$emit('change') }, setError: function (errMsg) {