@qrvey/formula-lang 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -0,0 +1,61 @@
1
+ # Qrvey Formula Language
2
+
3
+ ## Usage
4
+
5
+ Use it inside a javascript module
6
+
7
+ ```
8
+ import { QFormulaLang, calculateAST } from "@qrvey/formula-lang"
9
+ import { iRootAST, ENGINES, Transpiler } from '../../qrvey-lang/transpiler/lib/constants/interfaces';
10
+
11
+ // input expression
12
+ const expression = 'MID("this is an ex", 1)';
13
+
14
+ // get the parser from QFormulaLang
15
+ const parser = QFormulaLang.parser;
16
+
17
+ // get the tree from input expression
18
+ const tree = parser.parse(expression);
19
+
20
+ // transform the tree into an understandable AST
21
+ const ast = calculateAST(expression, tree.topNode);
22
+
23
+ // transpile the code to a specific target Engine
24
+ const transpilated = calculateTranspilation(ast, ENGINES.ELASTICSEARCH)
25
+
26
+ calculateTranspilation = (ast: iRootAST, engine: ENGINES) => {
27
+ let result;
28
+ try {
29
+ const transpiler = new Transpiler(ast, engine)
30
+ result = transpiler.get()
31
+ } catch (error) {
32
+ result = JSON.stringify(error, undefined, 4)
33
+ }
34
+ return result
35
+ }
36
+ ```
37
+
38
+ Use inside codemirror editor
39
+ ```
40
+ import { EditorState } from "@codemirror/state";
41
+ import { QFormula, calculateAST } from "@qrvey/formula-lang"
42
+
43
+ // set the editor state with the QFormula plugin. This adds the support for
44
+ this._state = EditorState.create({
45
+ doc: options?.text ?? '',
46
+ extensions: [
47
+ basicSetup,
48
+ QFormula(),
49
+ ...
50
+ ]
51
+ })
52
+
53
+ // On every edit update you can calculate the AST
54
+ private dispatchTextUpdate(state: EditorState) {
55
+ const tree = (state as any).tree;
56
+ const text = ((state.doc as any).text as Array<string>).join('\n');
57
+ const ast = calculateAST(text, tree.topNode);
58
+ // dispatch event after return
59
+ return { text, ast }
60
+ }
61
+ ```
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from "./grammar/qformula.grammar";
2
+ export * from "./parser/json-parser";
package/dist/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export * from "./grammar/qformula.grammar";
2
+ export * from "./parser/json-parser";
@@ -0,0 +1,29 @@
1
+ export interface AstNode {
2
+ type: string;
3
+ }
4
+ export interface AstBinaryExpressionNode extends AstNode {
5
+ operator: string;
6
+ left: AstNode;
7
+ right: AstNode;
8
+ }
9
+ export interface AstUnaryExpressionNode extends AstNode {
10
+ operator: string;
11
+ right: AstNode;
12
+ }
13
+ export interface AstValueNode extends AstNode {
14
+ value: string | boolean | number | AstNode[];
15
+ dataType: string;
16
+ }
17
+ export interface AstVariableNode extends AstNode {
18
+ value: string;
19
+ }
20
+ export interface AstFunctionNode extends AstNode {
21
+ name: string;
22
+ arguments: AstNode[];
23
+ }
24
+ export interface AstProgramNode extends AstNode {
25
+ exp: string;
26
+ lang: string;
27
+ version: string;
28
+ body: AstNode;
29
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { AstNode } from "../models/ast.models";
2
+ import { SyntaxNode } from "@lezer/common";
3
+ export declare function calculateAST(program: string, startNode: SyntaxNode): AstNode;
@@ -0,0 +1,90 @@
1
+ import { getNodeValue } from "../utils/utils";
2
+ const PARSER_VERSION = "0.0.0";
3
+ const LANG_NAME = "QrveyLang";
4
+ export function calculateAST(program, startNode) {
5
+ if (!startNode)
6
+ return { type: 'undefined' };
7
+ return {
8
+ "type": "Program",
9
+ "exp": program,
10
+ "lang": LANG_NAME,
11
+ "version": PARSER_VERSION,
12
+ "body": transformNode(program, startNode)
13
+ };
14
+ }
15
+ function transformNode(program, node) {
16
+ if (!node)
17
+ return { type: 'undefined' };
18
+ switch (node.name) {
19
+ case 'BinaryExpression':
20
+ return transformBinaryExpression(program, node);
21
+ case 'UnaryExpression':
22
+ return transformUnaryExpression(program, node);
23
+ case 'Function':
24
+ return transformFunctionExpression(program, node);
25
+ case 'Number':
26
+ return {
27
+ type: "Literal",
28
+ dataType: "number",
29
+ value: parseFloat(getNodeValue(program, node))
30
+ };
31
+ case 'String':
32
+ return {
33
+ type: "Literal",
34
+ dataType: "string",
35
+ value: getNodeValue(program, node).slice(1, -1)
36
+ };
37
+ case 'Boolean':
38
+ return {
39
+ type: "Literal",
40
+ dataType: "boolean",
41
+ value: getNodeValue(program, node) === 'true'
42
+ };
43
+ case 'Array':
44
+ return {
45
+ type: "Literal",
46
+ dataType: "array",
47
+ value: node.getChildren('Value')
48
+ .map(node => {
49
+ return transformNode(program, node);
50
+ })
51
+ };
52
+ case 'Variable':
53
+ return {
54
+ type: "Variable",
55
+ value: getNodeValue(program, node).slice(1, -1)
56
+ };
57
+ default:
58
+ return transformNode(program, node.firstChild);
59
+ }
60
+ }
61
+ function transformBinaryExpression(program, node) {
62
+ const [left, right] = node.getChildren('Expression');
63
+ const operator = node.getChild('ArithOp');
64
+ return {
65
+ operator: getNodeValue(program, operator),
66
+ type: "BinaryExpression",
67
+ left: transformNode(program, left),
68
+ right: transformNode(program, right)
69
+ };
70
+ }
71
+ function transformUnaryExpression(program, node) {
72
+ const [right] = node.getChildren('Expression');
73
+ const operator = node.getChild('ArithOp');
74
+ return {
75
+ operator: getNodeValue(program, operator),
76
+ type: "UnaryExpression",
77
+ right: transformNode(program, right)
78
+ };
79
+ }
80
+ function transformFunctionExpression(program, node) {
81
+ const args = node.getChild('FunctionArguments');
82
+ const nodeValue = node.getChild('FunctionIdentifier');
83
+ return {
84
+ type: "FunctionCall",
85
+ name: getNodeValue(program, nodeValue),
86
+ arguments: !!args ? args
87
+ .getChildren('Expression')
88
+ .map(node => transformNode(program, node)) : []
89
+ };
90
+ }
@@ -0,0 +1,4 @@
1
+ export declare function getNodeValue(str: string, { from, to }: {
2
+ from: number;
3
+ to: number;
4
+ }): string;
@@ -0,0 +1,3 @@
1
+ export function getNodeValue(str, { from, to }) {
2
+ return str.slice(from, to);
3
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qrvey/formula-lang",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "QFormula support for qrvey projects",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,6 +9,7 @@
9
9
  "test": "echo \"Error: no test specified\" && exit 1",
10
10
  "build": "tsc",
11
11
  "build:watch": "tsc -w",
12
+ "prepublishOnly": "npm run build",
12
13
  "prepare-lang": "rollup -c --bundleConfigAsCjs"
13
14
  },
14
15
  "repository": {
@@ -25,6 +26,7 @@
25
26
  "homepage": "https://bitbucket.org/qrvey/qrvey_formula_lang#readme",
26
27
  "dependencies": {
27
28
  "@codemirror/language": "^6.6.0",
29
+ "@lezer/common": "^1.0.2",
28
30
  "@lezer/highlight": "^1.1.4"
29
31
  },
30
32
  "devDependencies": {
@@ -34,4 +36,4 @@
34
36
  "rollup-plugin-ts": "^3.2.0",
35
37
  "typescript": "^5.0.4"
36
38
  }
37
- }
39
+ }
package/rollup.config.js DELETED
@@ -1,12 +0,0 @@
1
- import typescript from "rollup-plugin-ts"
2
- import { lezer } from "@lezer/generator/rollup"
3
-
4
- export default {
5
- input: "src/grammar/qformula.lang.ts",
6
- external: id => id != "tslib" && !/^(\.?\/|\w:)/.test(id),
7
- output: [
8
- { file: "src/grammar/generated/qformula.lang.cjs", format: "cjs" },
9
- { dir: "./src/grammar/generated", format: "es" }
10
- ],
11
- plugins: [lezer(), typescript()]
12
- }
@@ -1,48 +0,0 @@
1
- 'use strict';
2
-
3
- var lr = require('@lezer/lr');
4
- var language = require('@codemirror/language');
5
- var highlight = require('@lezer/highlight');
6
-
7
- // This file was generated by lezer-generator. You probably shouldn't edit it.
8
- const spec_identifier = {__proto__:null,true:14, false:14};
9
- const parser = lr.LRParser.deserialize({
10
- version: 14,
11
- states: "%jO]QPOOOwQPO'#CdOOQO'#C`'#C`OOQO'#Cf'#CfO!YQPO'#CeO!_QQO'#ChO]QPO'#CiQ!dQPOOO]QPO'#CnOOQO'#C_'#C_O!oQPO'#CxO!wQPO,59OO!|QPO,59PO#TQPO,59SOOQO,59T,59TO]QPO,59VO]QPO,59VO#YQPO,59YO#hQPO'#CoO#|QPO,59dOOQO1G.j1G.jO$UQPO'#C|OOQO'#Cg'#CgO$gQPO1G.kOOQO1G.n1G.nOOQO1G.q1G.qO$lQPO1G.qOOQO1G.t1G.tOOQO,59Z,59ZOOQO-E6m-E6mO%QQPO'#CpO%[QPO,59hOOQO7+$V7+$VO%dQPO,59[OOQO-E6n-E6n",
12
- stateData: "%|~OgOShOSPOS~OTQOUQOVQO^UOiROkPOoWOrTO~OTQOUQOVQOkPOjlP~Oo[O~Os]O~O^`O`_Oa_O~OmbOjlX~OjdO~OnpP~P]OqhO~O^`O`_Oa_OnkO~OTQOUQOVQOkPOjcXmcX~OmbOjla~O^`O`_Oa_OmnOnpX~OnpO~O`_Oa_O^_ie_in_im_i~OmdXndX~P]OmnOnpa~O^`O`_Oa_Omdanda~OP`ghig~",
13
- goto: "#lqPPPr!XPPP!h!s!|#V!s!sP!sPP!s#Y#`PPPPPPP#fPPP#iQVOQ^UQaWQe[Qi_Qj`Rqn^XOUW[_`nQYPRlbcQOPUW[_`bn_XOUW[_`n_SOUW[_`nRg[QcYRmcQoeRroRZPRf[",
14
- nodeNames: "⚠ LineComment Program Expression Value Number String Boolean Array Function FunctionIdentifier FunctionArguments Variable UnaryExpression ArithOp BinaryExpression ArithOp ArithOp ParenthesizedExpression",
15
- maxTerm: 35,
16
- skippedNodes: [0,1],
17
- repeatNodeCount: 2,
18
- tokenData: ")o~RoXY#SYZ#wZ[#S]^#wpq#Srs#|xy%jyz%oz{%t{|%y|}&{}!O%y!O!P'Q!P!Q'c!Q![(S!^!_(p!`!a(u!c!}(z!}#O)e#P#Q)j#R#S&d#T#o(z$f$g#S#BY#BZ#S$IS$I_#S$I|$I}#w$I}$JO#w$JT$JU#S$KV$KW#S&FU&FV#S?HT?HU#S~#XYg~XY#SZ[#Spq#S$f$g#S#BY#BZ#S$IS$I_#S$JT$JU#S$KV$KW#S&FU&FV#S?HT?HU#S~#|Oh~~$PVOr#|rs$fs#O#|#O#P$k#P;'S#|;'S;=`%d<%lO#|~$kOU~~$nRO;'S#|;'S;=`$w;=`O#|~$zWOr#|rs$fs#O#|#O#P$k#P;'S#|;'S;=`%d;=`<%l#|<%lO#|~%gP;=`<%l#|~%oOo~~%tOn~~%yOa~R&QU^PsQ{|&d}!O&d!Q![&d!c!}&d#R#S&d#T#o&dQ&iUsQ{|&d}!O&d!Q![&d!c!}&d#R#S&d#T#o&d~'QOm~P'TP!Q!['WP']QTP!Q!['W#R#S'W~'hP`~!P!Q'k~'pSP~OY'kZ;'S'k;'S;=`'|<%lO'k~(PP;=`<%l'kR(ZVTPsQ{|&d}!O&d!O!P'W!Q![(S!c!}&d#R#S(S#T#o&d~(uOk~~(zOj~R)RUsQiP{|&d}!O&d!Q![(z!c!}(z#R#S(z#T#o(z~)jOr~~)oOq~",
19
- tokenizers: [0, 1],
20
- topRules: {"Program":[0,2]},
21
- specialized: [{term: 25, get: value => spec_identifier[value] || -1}],
22
- tokenPrec: 221
23
- });
24
-
25
- const QFormulaLang = language.LRLanguage.define({
26
- parser: parser.configure({
27
- props: [
28
- highlight.styleTags({
29
- Boolean: highlight.tags.bool,
30
- String: highlight.tags.string,
31
- Number: highlight.tags.number,
32
- Variable: highlight.tags.keyword,
33
- LineComment: highlight.tags.lineComment,
34
- FunctionIdentifier: highlight.tags.lineComment,
35
- "( )": highlight.tags.paren
36
- })
37
- ]
38
- }),
39
- languageData: {
40
- commentTokens: { line: "//" }
41
- }
42
- });
43
- function QFormula() {
44
- return new language.LanguageSupport(QFormulaLang);
45
- }
46
-
47
- exports.QFormula = QFormula;
48
- exports.QFormulaLang = QFormulaLang;
@@ -1,4 +0,0 @@
1
- import { LRLanguage, LanguageSupport } from "@codemirror/language";
2
- declare const QFormulaLang: LRLanguage;
3
- declare function QFormula(): LanguageSupport;
4
- export { QFormulaLang, QFormula };
@@ -1,4 +0,0 @@
1
- import { LRLanguage, LanguageSupport } from "@codemirror/language";
2
- declare const QFormulaLang: LRLanguage;
3
- declare function QFormula(): LanguageSupport;
4
- export { QFormulaLang, QFormula };
@@ -1,45 +0,0 @@
1
- import { LRParser } from '@lezer/lr';
2
- import { LRLanguage, LanguageSupport } from '@codemirror/language';
3
- import { styleTags, tags } from '@lezer/highlight';
4
-
5
- // This file was generated by lezer-generator. You probably shouldn't edit it.
6
- const spec_identifier = {__proto__:null,true:14, false:14};
7
- const parser = LRParser.deserialize({
8
- version: 14,
9
- states: "%jO]QPOOOwQPO'#CdOOQO'#C`'#C`OOQO'#Cf'#CfO!YQPO'#CeO!_QQO'#ChO]QPO'#CiQ!dQPOOO]QPO'#CnOOQO'#C_'#C_O!oQPO'#CxO!wQPO,59OO!|QPO,59PO#TQPO,59SOOQO,59T,59TO]QPO,59VO]QPO,59VO#YQPO,59YO#hQPO'#CoO#|QPO,59dOOQO1G.j1G.jO$UQPO'#C|OOQO'#Cg'#CgO$gQPO1G.kOOQO1G.n1G.nOOQO1G.q1G.qO$lQPO1G.qOOQO1G.t1G.tOOQO,59Z,59ZOOQO-E6m-E6mO%QQPO'#CpO%[QPO,59hOOQO7+$V7+$VO%dQPO,59[OOQO-E6n-E6n",
10
- stateData: "%|~OgOShOSPOS~OTQOUQOVQO^UOiROkPOoWOrTO~OTQOUQOVQOkPOjlP~Oo[O~Os]O~O^`O`_Oa_O~OmbOjlX~OjdO~OnpP~P]OqhO~O^`O`_Oa_OnkO~OTQOUQOVQOkPOjcXmcX~OmbOjla~O^`O`_Oa_OmnOnpX~OnpO~O`_Oa_O^_ie_in_im_i~OmdXndX~P]OmnOnpa~O^`O`_Oa_Omdanda~OP`ghig~",
11
- goto: "#lqPPPr!XPPP!h!s!|#V!s!sP!sPP!s#Y#`PPPPPPP#fPPP#iQVOQ^UQaWQe[Qi_Qj`Rqn^XOUW[_`nQYPRlbcQOPUW[_`bn_XOUW[_`n_SOUW[_`nRg[QcYRmcQoeRroRZPRf[",
12
- nodeNames: "⚠ LineComment Program Expression Value Number String Boolean Array Function FunctionIdentifier FunctionArguments Variable UnaryExpression ArithOp BinaryExpression ArithOp ArithOp ParenthesizedExpression",
13
- maxTerm: 35,
14
- skippedNodes: [0,1],
15
- repeatNodeCount: 2,
16
- tokenData: ")o~RoXY#SYZ#wZ[#S]^#wpq#Srs#|xy%jyz%oz{%t{|%y|}&{}!O%y!O!P'Q!P!Q'c!Q![(S!^!_(p!`!a(u!c!}(z!}#O)e#P#Q)j#R#S&d#T#o(z$f$g#S#BY#BZ#S$IS$I_#S$I|$I}#w$I}$JO#w$JT$JU#S$KV$KW#S&FU&FV#S?HT?HU#S~#XYg~XY#SZ[#Spq#S$f$g#S#BY#BZ#S$IS$I_#S$JT$JU#S$KV$KW#S&FU&FV#S?HT?HU#S~#|Oh~~$PVOr#|rs$fs#O#|#O#P$k#P;'S#|;'S;=`%d<%lO#|~$kOU~~$nRO;'S#|;'S;=`$w;=`O#|~$zWOr#|rs$fs#O#|#O#P$k#P;'S#|;'S;=`%d;=`<%l#|<%lO#|~%gP;=`<%l#|~%oOo~~%tOn~~%yOa~R&QU^PsQ{|&d}!O&d!Q![&d!c!}&d#R#S&d#T#o&dQ&iUsQ{|&d}!O&d!Q![&d!c!}&d#R#S&d#T#o&d~'QOm~P'TP!Q!['WP']QTP!Q!['W#R#S'W~'hP`~!P!Q'k~'pSP~OY'kZ;'S'k;'S;=`'|<%lO'k~(PP;=`<%l'kR(ZVTPsQ{|&d}!O&d!O!P'W!Q![(S!c!}&d#R#S(S#T#o&d~(uOk~~(zOj~R)RUsQiP{|&d}!O&d!Q![(z!c!}(z#R#S(z#T#o(z~)jOr~~)oOq~",
17
- tokenizers: [0, 1],
18
- topRules: {"Program":[0,2]},
19
- specialized: [{term: 25, get: value => spec_identifier[value] || -1}],
20
- tokenPrec: 221
21
- });
22
-
23
- const QFormulaLang = LRLanguage.define({
24
- parser: parser.configure({
25
- props: [
26
- styleTags({
27
- Boolean: tags.bool,
28
- String: tags.string,
29
- Number: tags.number,
30
- Variable: tags.keyword,
31
- LineComment: tags.lineComment,
32
- FunctionIdentifier: tags.lineComment,
33
- "( )": tags.paren
34
- })
35
- ]
36
- }),
37
- languageData: {
38
- commentTokens: { line: "//" }
39
- }
40
- });
41
- function QFormula() {
42
- return new LanguageSupport(QFormulaLang);
43
- }
44
-
45
- export { QFormula, QFormulaLang };
@@ -1 +0,0 @@
1
- export * from "./generated/qformula.lang.js";
@@ -1,26 +0,0 @@
1
- import { parser } from "./syntax.grammar"
2
- import { LRLanguage, LanguageSupport } from "@codemirror/language"
3
- import { styleTags, tags as t } from "@lezer/highlight"
4
-
5
- export const QFormulaLang = LRLanguage.define({
6
- parser: parser.configure({
7
- props: [
8
- styleTags({
9
- Boolean: t.bool,
10
- String: t.string,
11
- Number: t.number,
12
- Variable: t.keyword,
13
- LineComment: t.lineComment,
14
- FunctionIdentifier: t.lineComment,
15
- "( )": t.paren
16
- })
17
- ]
18
- }),
19
- languageData: {
20
- commentTokens: { line: "//" }
21
- }
22
- })
23
-
24
- export function QFormula() {
25
- return new LanguageSupport(QFormulaLang)
26
- }
@@ -1,89 +0,0 @@
1
- @precedence{
2
- prefix,
3
- times @left,
4
- plus @left
5
- }
6
-
7
- @top Program { Expression }
8
-
9
- @skip { spaces | newline | LineComment}
10
-
11
- Expression {
12
- Value |
13
- Function |
14
- Variable |
15
- UnaryExpression |
16
- BinaryExpression |
17
- ParenthesizedExpression
18
- }
19
-
20
- Value {
21
- Number |
22
- String |
23
- boolean |
24
- Array
25
- }
26
-
27
- UnaryExpression{
28
- !prefix (ArithOp<"+" | "-">) Expression
29
- }
30
-
31
- BinaryExpression{
32
- Expression !times (divide | ArithOp<"*">) Expression |
33
- Expression !plus ArithOp<"+" | "-"> Expression
34
- }
35
-
36
- ParenthesizedExpression { "(" Expression ")" }
37
-
38
- Function {
39
- FunctionIdentifier "(" FunctionArguments ")"
40
- }
41
-
42
- FunctionIdentifier {
43
- identifier
44
- }
45
-
46
- FunctionArguments{
47
- commaSepAllowEmpty<Expression>
48
- }
49
-
50
- Array{
51
- "<" commaSepAllowEmpty<Value> ">"
52
- }
53
-
54
- Variable { "\[" variableId "\]" }
55
-
56
- commaSepAllowEmpty<content> {
57
- "" | content ("," content?)*
58
- }
59
-
60
- boolean { @specialize[@name=Boolean]<identifier, "true" | "false"> }
61
-
62
- @tokens {
63
- String { '"' (!["\\] | "\\" _)* '"' }
64
-
65
- Number {
66
- (@digit ("_" | @digit)* ("." ("_" | @digit)*)? | "." @digit ("_" | @digit)*)
67
- }
68
-
69
- LineComment { "//" ![\n]* }
70
-
71
- spaces[@export] { $[\u0009 \u000b\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]+ }
72
- newline[@export] { $[\r\n\u2028\u2029] }
73
-
74
- variableId { (@asciiLetter | @digit | $[_\-\+])+ }
75
-
76
- divide[@name=ArithOp] { "/" }
77
-
78
- @precedence { LineComment, divide }
79
-
80
- identifier { word }
81
-
82
- word { @asciiLetter (@asciiLetter | @digit | $[_])* }
83
-
84
- ArithOp<expr> { expr }
85
-
86
- @precedence { spaces, newline, identifier }
87
- }
88
-
89
- @detectDelim
@@ -1,3 +0,0 @@
1
- import { LRParser } from "@lezer/lr"
2
-
3
- export declare const parser: LRParser
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./grammar/qformula.grammar";
package/tsconfig.json DELETED
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "strict": true,
4
- "moduleResolution": "node",
5
- "module": "esnext",
6
- "target": "es2017",
7
- "declaration": true,
8
- "outDir": "./dist",
9
- "skipLibCheck": true,
10
- "sourceMap": false,
11
- "allowJs": true
12
- },
13
- "include": [
14
- "src"
15
- ],
16
- "exclude": [
17
- "src/grammar/qformula.lang.ts"
18
- ]
19
- }