@morphql/language-definitions 0.1.3 → 0.1.5

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/src/functions.ts DELETED
@@ -1,170 +0,0 @@
1
- import { FunctionDef } from "./types";
2
-
3
- /**
4
- * MorphQL Functions - Single source of truth
5
- *
6
- * When adding a new function:
7
- * 1. Add it here
8
- * 2. Implement in @morphql/core/src/functions.ts
9
- * 3. Run build to regenerate VSCode/Monaco configs
10
- */
11
- export const FUNCTIONS: FunctionDef[] = [
12
- {
13
- name: "substring",
14
- doc: {
15
- signature: "substring(str, start, [length])",
16
- description: "Extracts a portion of a string. Supports negative indices.",
17
- parameters: [
18
- { name: "str", description: "The source string" },
19
- {
20
- name: "start",
21
- description: "Starting index (0-based, negative counts from end)",
22
- },
23
- {
24
- name: "length",
25
- description: "(Optional) Number of characters to extract",
26
- },
27
- ],
28
- returns: "string",
29
- example:
30
- 'substring("Hello World", 0, 5) // "Hello"\nsubstring("Hello World", -5) // "World"',
31
- },
32
- },
33
- {
34
- name: "split",
35
- doc: {
36
- signature: "split(str, [separator], [limit])",
37
- description: "Splits a string into an array.",
38
- parameters: [
39
- { name: "str", description: "The string to split" },
40
- {
41
- name: "separator",
42
- description: '(Optional) Delimiter string. Default: ""',
43
- },
44
- { name: "limit", description: "(Optional) Maximum number of splits" },
45
- ],
46
- returns: "array",
47
- example: 'split("a,b,c", ",") // ["a", "b", "c"]',
48
- },
49
- },
50
- {
51
- name: "replace",
52
- doc: {
53
- signature: "replace(str, search, replacement)",
54
- description: "Replaces occurrences in a string.",
55
- parameters: [
56
- { name: "str", description: "The source string" },
57
- { name: "search", description: "The substring to find" },
58
- { name: "replacement", description: "The replacement string" },
59
- ],
60
- returns: "string",
61
- example: 'replace("Hello World", "World", "MorphQL") // "Hello MorphQL"',
62
- },
63
- },
64
- {
65
- name: "text",
66
- doc: {
67
- signature: "text(value)",
68
- description: "Converts a value to a string.",
69
- parameters: [{ name: "value", description: "The value to convert" }],
70
- returns: "string",
71
- example: 'text(123) // "123"',
72
- },
73
- },
74
- {
75
- name: "number",
76
- doc: {
77
- signature: "number(value)",
78
- description: "Converts a value to a number.",
79
- parameters: [{ name: "value", description: "The value to convert" }],
80
- returns: "number",
81
- example: 'number("42") // 42',
82
- },
83
- },
84
- {
85
- name: "uppercase",
86
- doc: {
87
- signature: "uppercase(str)",
88
- description: "Converts a string to uppercase.",
89
- parameters: [{ name: "str", description: "The string to convert" }],
90
- returns: "string",
91
- example: 'uppercase("hello") // "HELLO"',
92
- },
93
- },
94
- {
95
- name: "lowercase",
96
- doc: {
97
- signature: "lowercase(str)",
98
- description: "Converts a string to lowercase.",
99
- parameters: [{ name: "str", description: "The string to convert" }],
100
- returns: "string",
101
- example: 'lowercase("HELLO") // "hello"',
102
- },
103
- },
104
- {
105
- name: "extractnumber",
106
- doc: {
107
- signature: "extractnumber(str)",
108
- description: "Extracts the first numeric sequence from a string.",
109
- parameters: [{ name: "str", description: "The string to extract from" }],
110
- returns: "number",
111
- example: 'extractnumber("Price: 100USD") // 100',
112
- },
113
- },
114
- {
115
- name: "xmlnode",
116
- doc: {
117
- signature: "xmlnode(value, [attrKey, attrVal, ...])",
118
- description: "Wraps a value for XML output with optional attributes.",
119
- parameters: [
120
- { name: "value", description: "The node content" },
121
- {
122
- name: "attrKey, attrVal",
123
- description: "(Optional) Pairs of attribute keys and values",
124
- },
125
- ],
126
- returns: "XML node",
127
- example: 'xmlnode(content, "id", 1, "type", "text")',
128
- },
129
- },
130
- {
131
- name: "to_base64",
132
- doc: {
133
- signature: "to_base64(value)",
134
- description: "Encodes a string value to Base64.",
135
- parameters: [{ name: "value", description: "The string to encode" }],
136
- returns: "string",
137
- example: 'to_base64("hello") // "aGVsbG8="',
138
- },
139
- },
140
- {
141
- name: "from_base64",
142
- doc: {
143
- signature: "from_base64(value)",
144
- description: "Decodes a Base64 string value.",
145
- parameters: [
146
- { name: "value", description: "The Base64 string to decode" },
147
- ],
148
- returns: "string",
149
- example: 'from_base64("aGVsbG8=") // "hello"',
150
- },
151
- },
152
- {
153
- name: "aslist",
154
- doc: {
155
- signature: "aslist(value)",
156
- description:
157
- "Ensures a value is an array. Useful for XML nodes that might be a single object or an array.",
158
- parameters: [{ name: "value", description: "The value to normalize" }],
159
- returns: "array",
160
- example: "aslist(items) // Always returns an array",
161
- },
162
- },
163
- ];
164
-
165
- // Helper to get all function names
166
- export const getFunctionNames = () => FUNCTIONS.map((f) => f.name);
167
-
168
- // Helper to get function documentation
169
- export const getFunctionDoc = (name: string) =>
170
- FUNCTIONS.find((f) => f.name.toLowerCase() === name.toLowerCase())?.doc;
package/src/index.ts DELETED
@@ -1,202 +0,0 @@
1
- import {
2
- KEYWORDS,
3
- getKeywordNames,
4
- getKeywordsByCategory,
5
- getKeywordDoc,
6
- } from "./keywords";
7
- import { FUNCTIONS, getFunctionNames, getFunctionDoc } from "./functions";
8
- import {
9
- OPERATORS,
10
- getOperatorsByCategory,
11
- getOperatorSymbols,
12
- getMultiCharOperators,
13
- getSingleCharOperators,
14
- } from "./operators";
15
- import type {
16
- LanguageDefinition,
17
- KeywordDef,
18
- FunctionDef,
19
- OperatorDef,
20
- DocEntry,
21
- } from "./types";
22
-
23
- /**
24
- * Complete MorphQL language definition
25
- */
26
- export const MORPHQL_LANGUAGE: LanguageDefinition = {
27
- keywords: KEYWORDS,
28
- functions: FUNCTIONS,
29
- operators: OPERATORS,
30
- comments: {
31
- line: "//",
32
- blockStart: "/*",
33
- blockEnd: "*/",
34
- },
35
- };
36
-
37
- // Re-export everything
38
- export {
39
- // Data
40
- KEYWORDS,
41
- FUNCTIONS,
42
- OPERATORS,
43
-
44
- // Helpers
45
- getKeywordNames,
46
- getKeywordsByCategory,
47
- getKeywordDoc,
48
- getFunctionNames,
49
- getFunctionDoc,
50
- getOperatorsByCategory,
51
- getOperatorSymbols,
52
- getMultiCharOperators,
53
- getSingleCharOperators,
54
-
55
- // Types
56
- type LanguageDefinition,
57
- type KeywordDef,
58
- type FunctionDef,
59
- type OperatorDef,
60
- type DocEntry,
61
- };
62
-
63
- /**
64
- * Generators for different platforms
65
- */
66
-
67
- /**
68
- * Generate TextMate grammar keywords pattern
69
- */
70
- export function generateTextMateKeywordsPattern(): string {
71
- const controlKeywords = getKeywordsByCategory("control").map((k) => k.name);
72
- const actionKeywords = getKeywordsByCategory("action").map((k) => k.name);
73
-
74
- return JSON.stringify(
75
- {
76
- patterns: [
77
- {
78
- name: "keyword.control.morphql",
79
- match: `\\b(${controlKeywords.join("|")})\\b`,
80
- },
81
- {
82
- name: "keyword.other.morphql",
83
- match: `\\b(${actionKeywords.join("|")})\\b`,
84
- },
85
- ],
86
- },
87
- null,
88
- 2,
89
- );
90
- }
91
-
92
- /**
93
- * Generate TextMate grammar functions pattern
94
- */
95
- export function generateTextMateFunctionsPattern(): string {
96
- const functionNames = getFunctionNames();
97
-
98
- return JSON.stringify(
99
- {
100
- patterns: [
101
- {
102
- name: "entity.name.function.morphql",
103
- match: `\\b(${functionNames.join("|")})(?=\\s*\\()`,
104
- },
105
- ],
106
- },
107
- null,
108
- 2,
109
- );
110
- }
111
-
112
- /**
113
- * Generate Monaco language configuration
114
- */
115
- export function generateMonacoLanguageConfig() {
116
- return {
117
- keywords: getKeywordNames(),
118
- builtinFunctions: getFunctionNames(),
119
- operators: getOperatorSymbols(),
120
- symbols: /[=><!~?:&|+\-*\/\^%]+/,
121
- escapes:
122
- /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
123
-
124
- tokenizer: {
125
- root: [
126
- // Comments
127
- [/\/\/.*$/, "comment"],
128
- [/\/\*/, "comment", "@comment"],
129
-
130
- // Keywords
131
- [
132
- /[a-zA-Z_$][\w$]*/,
133
- {
134
- cases: {
135
- "@keywords": "keyword",
136
- "@builtinFunctions": "predefined",
137
- "@default": "identifier",
138
- },
139
- },
140
- ],
141
-
142
- // Strings
143
- [/"([^"\\]|\\.)*$/, "string.invalid"],
144
- [/'([^'\\]|\\.)*$/, "string.invalid"],
145
- [/"/, "string", "@string_double"],
146
- [/'/, "string", "@string_single"],
147
-
148
- // Numbers
149
- [/-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/, "number"],
150
-
151
- // Operators
152
- [/[{}()\[\]]/, "@brackets"],
153
- [
154
- /@symbols/,
155
- {
156
- cases: {
157
- "@operators": "operator",
158
- "@default": "",
159
- },
160
- },
161
- ],
162
- ],
163
-
164
- comment: [
165
- [/[^\/*]+/, "comment"],
166
- [/\*\//, "comment", "@pop"],
167
- [/[\/*]/, "comment"],
168
- ],
169
-
170
- string_double: [
171
- [/[^\\"]+/, "string"],
172
- [/@escapes/, "string.escape"],
173
- [/\\./, "string.escape.invalid"],
174
- [/"/, "string", "@pop"],
175
- ],
176
-
177
- string_single: [
178
- [/[^\\']+/, "string"],
179
- [/@escapes/, "string.escape"],
180
- [/\\./, "string.escape.invalid"],
181
- [/'/, "string", "@pop"],
182
- ],
183
- },
184
- };
185
- }
186
-
187
- /**
188
- * Generate hover documentation map for VSCode
189
- */
190
- export function generateHoverDocs() {
191
- const keywordDocs: Record<string, DocEntry> = {};
192
- KEYWORDS.forEach((k) => {
193
- keywordDocs[k.name] = k.doc;
194
- });
195
-
196
- const functionDocs: Record<string, DocEntry> = {};
197
- FUNCTIONS.forEach((f) => {
198
- functionDocs[f.name] = f.doc;
199
- });
200
-
201
- return { keywordDocs, functionDocs };
202
- }
package/src/keywords.ts DELETED
@@ -1,196 +0,0 @@
1
- import { KeywordDef } from "./types";
2
-
3
- /**
4
- * MorphQL Keywords - Single source of truth
5
- *
6
- * When adding a new keyword:
7
- * 1. Add it here
8
- * 2. Update the lexer in @morphql/core
9
- * 3. Run build to regenerate VSCode/Monaco configs
10
- */
11
- export const KEYWORDS: KeywordDef[] = [
12
- {
13
- name: "from",
14
- category: "control",
15
- doc: {
16
- signature: "from <format>",
17
- description: "Specifies the input data format.",
18
- parameters: [
19
- {
20
- name: "format",
21
- description:
22
- "If used as first keyword: The starting format, one of `json`, `xml`, or `object`. When used after a section, defines its source",
23
- },
24
- ],
25
- example: "from json to xml",
26
- },
27
- },
28
- {
29
- name: "to",
30
- category: "control",
31
- doc: {
32
- signature: "to <format>",
33
- description: "Specifies the output data format.",
34
- parameters: [
35
- { name: "format", description: "One of: `json`, `xml`, or `object`" },
36
- ],
37
- example: "from json to xml",
38
- },
39
- },
40
- {
41
- name: "transform",
42
- category: "control",
43
- doc: {
44
- signature: "transform",
45
- description: "Begins the transformation block containing actions.",
46
- example: "transform\n set name = firstName",
47
- },
48
- },
49
- {
50
- name: "set",
51
- category: "action",
52
- doc: {
53
- signature: "set <target> = <expression>",
54
- description: "Assigns a value to a field in the output.",
55
- parameters: [
56
- { name: "target", description: "The field name to set" },
57
- {
58
- name: "expression",
59
- description: "The value or expression to assign",
60
- },
61
- ],
62
- example: 'set fullName = firstName + " " + lastName',
63
- },
64
- },
65
- {
66
- name: "section",
67
- category: "action",
68
- doc: {
69
- signature:
70
- "section [multiple] <name>( [subquery] <actions> ) [from <path>]",
71
- description:
72
- "Creates a nested object or array in the output. Can optionally include a subquery for format conversion.",
73
- parameters: [
74
- { name: "multiple", description: "(Optional) Treat as array mapping" },
75
- { name: "name", description: "The section/field name" },
76
- {
77
- name: "subquery",
78
- description:
79
- "(Optional) Nested query: from <format> to <format> [transform]",
80
- },
81
- {
82
- name: "actions",
83
- description: "Actions to perform within the section",
84
- },
85
- {
86
- name: "from",
87
- description: "(Optional) Source path for the section data",
88
- },
89
- ],
90
- example:
91
- "section metadata(\n from xml to object\n transform\n set name = root.productName\n) from xmlString",
92
- },
93
- },
94
- {
95
- name: "multiple",
96
- category: "action",
97
- doc: {
98
- signature: "section multiple <name>(...)",
99
- description: "Modifier for `section` to map over an array.",
100
- example: "section multiple items(\n set id = itemId\n) from products",
101
- },
102
- },
103
- {
104
- name: "clone",
105
- category: "action",
106
- doc: {
107
- signature: "clone([field1, field2, ...])",
108
- description: "Copies fields from the source to the output.",
109
- parameters: [
110
- {
111
- name: "fields",
112
- description:
113
- "(Optional) Specific fields to clone. If omitted, clones all fields.",
114
- },
115
- ],
116
- example: "clone(id, name, email)",
117
- },
118
- },
119
- {
120
- name: "delete",
121
- category: "action",
122
- doc: {
123
- signature: "delete <field>",
124
- description: "Removes a field from the output (useful after `clone`).",
125
- parameters: [{ name: "field", description: "The field name to delete" }],
126
- example: "clone()\ndelete password",
127
- },
128
- },
129
- {
130
- name: "define",
131
- category: "action",
132
- doc: {
133
- signature: "define <alias> = <expression>",
134
- description:
135
- "Creates a local variable/alias for use in subsequent expressions.",
136
- parameters: [
137
- { name: "alias", description: "The variable name" },
138
- { name: "expression", description: "The value to assign" },
139
- ],
140
- example:
141
- "define taxRate = 0.22\nset totalWithTax = total * (1 + taxRate)",
142
- },
143
- },
144
- {
145
- name: "if",
146
- category: "control",
147
- doc: {
148
- signature: "if (condition) ( actions ) [else ( actions )]",
149
- description: "Conditional execution of action blocks.",
150
- parameters: [
151
- { name: "condition", description: "Boolean expression" },
152
- { name: "actions", description: "Actions to execute if true/false" },
153
- ],
154
- example:
155
- 'if (age >= 18) (\n set status = "adult"\n) else (\n set status = "minor"\n)',
156
- },
157
- },
158
- {
159
- name: "else",
160
- category: "control",
161
- doc: {
162
- signature: "else ( actions )",
163
- description: "Defines the else branch of an `if` statement.",
164
- example: "if (condition) (\n ...\n) else (\n ...\n)",
165
- },
166
- },
167
- {
168
- name: "modify",
169
- category: "action",
170
- doc: {
171
- signature: "modify <target> = <expression>",
172
- description:
173
- "Modifies a field in the output by reading from the target (not source). Useful for post-processing already-mapped values.",
174
- parameters: [
175
- { name: "target", description: "The field name to modify" },
176
- {
177
- name: "expression",
178
- description:
179
- "The expression to assign (reads from target, not source)",
180
- },
181
- ],
182
- example: "set total = price * quantity\nmodify total = total * 1.10",
183
- },
184
- },
185
- ];
186
-
187
- // Helper to get keywords by category
188
- export const getKeywordsByCategory = (category: "control" | "action") =>
189
- KEYWORDS.filter((k) => k.category === category);
190
-
191
- // Helper to get all keyword names
192
- export const getKeywordNames = () => KEYWORDS.map((k) => k.name);
193
-
194
- // Helper to get keyword documentation
195
- export const getKeywordDoc = (name: string) =>
196
- KEYWORDS.find((k) => k.name.toLowerCase() === name.toLowerCase())?.doc;
package/src/operators.ts DELETED
@@ -1,50 +0,0 @@
1
- import { OperatorDef } from "./types";
2
-
3
- /**
4
- * MorphQL Operators - Single source of truth
5
- *
6
- * When adding a new operator:
7
- * 1. Add it here
8
- * 2. Update the lexer in @morphql/core (MIND THE ORDER!)
9
- * 3. Run build to regenerate VSCode/Monaco configs
10
- */
11
- export const OPERATORS: OperatorDef[] = [
12
- // Comparison operators
13
- { symbol: "===", category: "comparison", precedence: 7 },
14
- { symbol: "!==", category: "comparison", precedence: 7 },
15
- { symbol: "==", category: "comparison", precedence: 7 },
16
- { symbol: "!=", category: "comparison", precedence: 7 },
17
- { symbol: "<=", category: "comparison", precedence: 6 },
18
- { symbol: ">=", category: "comparison", precedence: 6 },
19
- { symbol: "<", category: "comparison", precedence: 6 },
20
- { symbol: ">", category: "comparison", precedence: 6 },
21
-
22
- // Logical operators
23
- { symbol: "&&", category: "logical", precedence: 5 },
24
- { symbol: "||", category: "logical", precedence: 4 },
25
- { symbol: "!", category: "logical", precedence: 9 },
26
-
27
- // Arithmetic operators
28
- { symbol: "+", category: "arithmetic", precedence: 10 },
29
- { symbol: "-", category: "arithmetic", precedence: 10 },
30
- { symbol: "*", category: "arithmetic", precedence: 11 },
31
- { symbol: "/", category: "arithmetic", precedence: 11 },
32
-
33
- // Assignment
34
- { symbol: "=", category: "assignment", precedence: 1 },
35
- ];
36
-
37
- // Helper to get operators by category
38
- export const getOperatorsByCategory = (category: OperatorDef["category"]) =>
39
- OPERATORS.filter((op) => op.category === category);
40
-
41
- // Helper to get all operator symbols
42
- export const getOperatorSymbols = () => OPERATORS.map((op) => op.symbol);
43
-
44
- // Helper to get multi-character operators (for lexer ordering)
45
- export const getMultiCharOperators = () =>
46
- OPERATORS.filter((op) => op.symbol.length > 1).map((op) => op.symbol);
47
-
48
- // Helper to get single-character operators
49
- export const getSingleCharOperators = () =>
50
- OPERATORS.filter((op) => op.symbol.length === 1).map((op) => op.symbol);
package/src/types.ts DELETED
@@ -1,51 +0,0 @@
1
- /**
2
- * Documentation entry for a keyword or function
3
- */
4
- export interface DocEntry {
5
- signature: string;
6
- description: string;
7
- parameters?: { name: string; description: string }[];
8
- returns?: string;
9
- example?: string;
10
- category?: "control" | "action" | "function" | "operator";
11
- }
12
-
13
- /**
14
- * Keyword definition
15
- */
16
- export interface KeywordDef {
17
- name: string;
18
- category: "control" | "action";
19
- doc: DocEntry;
20
- }
21
-
22
- /**
23
- * Function definition
24
- */
25
- export interface FunctionDef {
26
- name: string;
27
- doc: DocEntry;
28
- }
29
-
30
- /**
31
- * Operator definition
32
- */
33
- export interface OperatorDef {
34
- symbol: string;
35
- category: "arithmetic" | "comparison" | "logical" | "assignment";
36
- precedence?: number;
37
- }
38
-
39
- /**
40
- * Complete language definition
41
- */
42
- export interface LanguageDefinition {
43
- keywords: KeywordDef[];
44
- functions: FunctionDef[];
45
- operators: OperatorDef[];
46
- comments: {
47
- line: string;
48
- blockStart: string;
49
- blockEnd: string;
50
- };
51
- }
package/tsconfig.json DELETED
@@ -1,16 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "lib": ["ES2020"],
6
- "moduleResolution": "node",
7
- "esModuleInterop": true,
8
- "strict": true,
9
- "skipLibCheck": true,
10
- "declaration": true,
11
- "outDir": "./dist",
12
- "rootDir": "./src"
13
- },
14
- "include": ["src"],
15
- "exclude": ["node_modules", "dist"]
16
- }