naider 1.11.0 → 1.12.0
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 +102 -15
- package/SPEC.naide +74 -0
- package/lsp/server.js +15 -1
- package/package.json +16 -3
- package/src/generator-bun.js +89 -0
- package/src/generator-python.js +441 -2
- package/src/generator.js +425 -4
- package/src/parser.js +200 -2
- package/src/tokens.js +12 -0
- package/vscode-naide/syntaxes/naide.tmLanguage.json +1 -1
package/src/parser.js
CHANGED
|
@@ -109,7 +109,9 @@ export class Parser {
|
|
|
109
109
|
type === T.VALIDATE || type === T.TEST || type === T.ASSERT ||
|
|
110
110
|
type === T.QUEUE || type === T.JOB || type === T.OPENAPI ||
|
|
111
111
|
type === T.TYPEOF || type === T.INSTANCEOF || type === T.ENSURE ||
|
|
112
|
-
type === T.MODEL || type === T.PROMPT
|
|
112
|
+
type === T.MODEL || type === T.PROMPT ||
|
|
113
|
+
type === T.PAGE || type === T.CLI_APP || type === T.MAIL ||
|
|
114
|
+
type === T.GRAPHQL || type === T.DESKTOP || type === T.SCREEN;
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
expectPropertyName() {
|
|
@@ -166,6 +168,11 @@ export class Parser {
|
|
|
166
168
|
case T.TRY: return this.parseTry();
|
|
167
169
|
case T.SERVER: return this.parseServer();
|
|
168
170
|
case T.BOT: return this.parseBot();
|
|
171
|
+
case T.PAGE: return this.parsePage();
|
|
172
|
+
case T.CLI_APP: return this.parseCli();
|
|
173
|
+
case T.MAIL: return this.parseMail();
|
|
174
|
+
case T.DESKTOP: return this.parseDesktop();
|
|
175
|
+
case T.SCREEN: return this.parseScreen();
|
|
169
176
|
case T.MODEL: return this.parseModel();
|
|
170
177
|
case T.ON: return this.parseOn();
|
|
171
178
|
case T.LOG: return this.parseLog();
|
|
@@ -631,6 +638,8 @@ export class Parser {
|
|
|
631
638
|
routes.push(this.parseOpenapi());
|
|
632
639
|
} else if (this.at(T.QUEUE)) {
|
|
633
640
|
routes.push(this.parseQueue());
|
|
641
|
+
} else if (this.at(T.GRAPHQL)) {
|
|
642
|
+
routes.push(this.parseGraphql());
|
|
634
643
|
} else if (this.at(T.IDENT) && this.peek().value === 'error') {
|
|
635
644
|
routes.push(this.parseErrorHandler());
|
|
636
645
|
} else {
|
|
@@ -647,6 +656,12 @@ export class Parser {
|
|
|
647
656
|
this.advance(); // bot
|
|
648
657
|
const name = this.expect(T.IDENT).value;
|
|
649
658
|
|
|
659
|
+
let botType = null;
|
|
660
|
+
if (this.at(T.IDENT) && this.peek().value === 'type') {
|
|
661
|
+
this.advance();
|
|
662
|
+
botType = this.parseString();
|
|
663
|
+
}
|
|
664
|
+
|
|
650
665
|
let token = null;
|
|
651
666
|
if (this.at(T.IDENT) && this.peek().value === 'token') {
|
|
652
667
|
this.advance();
|
|
@@ -703,7 +718,7 @@ export class Parser {
|
|
|
703
718
|
}
|
|
704
719
|
this.match(T.DEDENT);
|
|
705
720
|
|
|
706
|
-
return new ASTNode('Bot', { name, token, prefix, handlers });
|
|
721
|
+
return new ASTNode('Bot', { name, token, prefix, botType, handlers });
|
|
707
722
|
}
|
|
708
723
|
|
|
709
724
|
parseRoute() {
|
|
@@ -1131,6 +1146,8 @@ export class Parser {
|
|
|
1131
1146
|
case T.QUEUE: case T.JOB: case T.OPENAPI:
|
|
1132
1147
|
case T.TYPEOF: case T.INSTANCEOF: case T.ENSURE:
|
|
1133
1148
|
case T.PROMPT:
|
|
1149
|
+
case T.PAGE: case T.CLI_APP: case T.MAIL:
|
|
1150
|
+
case T.GRAPHQL: case T.DESKTOP: case T.SCREEN:
|
|
1134
1151
|
case T.FROM: case T.AS: case T.IN:
|
|
1135
1152
|
this.advance();
|
|
1136
1153
|
return new ASTNode('Identifier', { name: tok.value });
|
|
@@ -1737,4 +1754,185 @@ export class Parser {
|
|
|
1737
1754
|
this.match(T.DEDENT);
|
|
1738
1755
|
return new ASTNode('PromptDecl', { name, defaults, lines });
|
|
1739
1756
|
}
|
|
1757
|
+
|
|
1758
|
+
parsePage() {
|
|
1759
|
+
this.advance(); // page
|
|
1760
|
+
const filename = this.parseString();
|
|
1761
|
+
this.expect(T.COLON);
|
|
1762
|
+
this.skipNewlines();
|
|
1763
|
+
this.expect(T.INDENT);
|
|
1764
|
+
const elements = [];
|
|
1765
|
+
this.skipNewlines();
|
|
1766
|
+
while (!this.at(T.DEDENT) && !this.at(T.EOF)) {
|
|
1767
|
+
elements.push(this.parsePageElement());
|
|
1768
|
+
this.skipNewlines();
|
|
1769
|
+
}
|
|
1770
|
+
this.match(T.DEDENT);
|
|
1771
|
+
return new ASTNode('Page', { filename, elements });
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
parsePageElement() {
|
|
1775
|
+
const tag = this.advance().value;
|
|
1776
|
+
const args = [];
|
|
1777
|
+
while (this.at(T.STRING)) {
|
|
1778
|
+
args.push(this.parseString());
|
|
1779
|
+
}
|
|
1780
|
+
let children = [];
|
|
1781
|
+
if (this.at(T.COLON)) {
|
|
1782
|
+
this.advance();
|
|
1783
|
+
this.skipNewlines();
|
|
1784
|
+
this.expect(T.INDENT);
|
|
1785
|
+
this.skipNewlines();
|
|
1786
|
+
while (!this.at(T.DEDENT) && !this.at(T.EOF)) {
|
|
1787
|
+
children.push(this.parsePageElement());
|
|
1788
|
+
this.skipNewlines();
|
|
1789
|
+
}
|
|
1790
|
+
this.match(T.DEDENT);
|
|
1791
|
+
}
|
|
1792
|
+
return new ASTNode('PageElement', { tag, args, children });
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
parseCli() {
|
|
1796
|
+
this.advance(); // cli
|
|
1797
|
+
const name = this.expect(T.IDENT).value;
|
|
1798
|
+
let description = null;
|
|
1799
|
+
if (this.at(T.STRING)) {
|
|
1800
|
+
description = this.parseString();
|
|
1801
|
+
}
|
|
1802
|
+
this.expect(T.COLON);
|
|
1803
|
+
this.skipNewlines();
|
|
1804
|
+
this.expect(T.INDENT);
|
|
1805
|
+
const args = [];
|
|
1806
|
+
const flags = [];
|
|
1807
|
+
let run = null;
|
|
1808
|
+
this.skipNewlines();
|
|
1809
|
+
while (!this.at(T.DEDENT) && !this.at(T.EOF)) {
|
|
1810
|
+
if (this.at(T.IDENT) && this.peek().value === 'arg') {
|
|
1811
|
+
this.advance();
|
|
1812
|
+
const argName = this.parseString();
|
|
1813
|
+
let argType = 'str';
|
|
1814
|
+
if (TYPE_TOKENS.has(this.peek().type)) {
|
|
1815
|
+
argType = this.advance().value;
|
|
1816
|
+
} else if (this.at(T.IDENT) && ['str', 'int', 'num', 'bool'].includes(this.peek().value)) {
|
|
1817
|
+
argType = this.advance().value;
|
|
1818
|
+
}
|
|
1819
|
+
let desc = null;
|
|
1820
|
+
if (this.at(T.STRING)) desc = this.parseString();
|
|
1821
|
+
args.push({ name: argName, type: argType, description: desc });
|
|
1822
|
+
} else if (this.at(T.IDENT) && this.peek().value === 'flag') {
|
|
1823
|
+
this.advance();
|
|
1824
|
+
const short = this.parseString();
|
|
1825
|
+
const long = this.parseString();
|
|
1826
|
+
let desc = null;
|
|
1827
|
+
if (this.at(T.STRING)) desc = this.parseString();
|
|
1828
|
+
flags.push({ short, long, description: desc });
|
|
1829
|
+
} else if (this.at(T.IDENT) && this.peek().value === 'run') {
|
|
1830
|
+
this.advance();
|
|
1831
|
+
let params = [];
|
|
1832
|
+
if (this.match(T.LPAREN)) {
|
|
1833
|
+
while (!this.at(T.RPAREN) && !this.at(T.EOF)) {
|
|
1834
|
+
params.push(this.expect(T.IDENT).value);
|
|
1835
|
+
this.match(T.COMMA);
|
|
1836
|
+
}
|
|
1837
|
+
this.expect(T.RPAREN);
|
|
1838
|
+
}
|
|
1839
|
+
this.expect(T.COLON);
|
|
1840
|
+
run = { params, body: this.parseBlock() };
|
|
1841
|
+
} else {
|
|
1842
|
+
this.advance();
|
|
1843
|
+
}
|
|
1844
|
+
this.skipNewlines();
|
|
1845
|
+
}
|
|
1846
|
+
this.match(T.DEDENT);
|
|
1847
|
+
return new ASTNode('CliApp', { name, description, args, flags, run });
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
parseMail() {
|
|
1851
|
+
this.advance(); // mail
|
|
1852
|
+
const host = this.parseString();
|
|
1853
|
+
const port = this.parseExpression();
|
|
1854
|
+
this.expect(T.COLON);
|
|
1855
|
+
this.skipNewlines();
|
|
1856
|
+
this.expect(T.INDENT);
|
|
1857
|
+
let user = null, pass = null;
|
|
1858
|
+
this.skipNewlines();
|
|
1859
|
+
while (!this.at(T.DEDENT) && !this.at(T.EOF)) {
|
|
1860
|
+
if (this.at(T.IDENT) && this.peek().value === 'user') {
|
|
1861
|
+
this.advance();
|
|
1862
|
+
user = this.parseExpression();
|
|
1863
|
+
} else if (this.at(T.IDENT) && this.peek().value === 'pass') {
|
|
1864
|
+
this.advance();
|
|
1865
|
+
pass = this.parseExpression();
|
|
1866
|
+
} else {
|
|
1867
|
+
this.advance();
|
|
1868
|
+
}
|
|
1869
|
+
this.skipNewlines();
|
|
1870
|
+
}
|
|
1871
|
+
this.match(T.DEDENT);
|
|
1872
|
+
return new ASTNode('MailConfig', { host, port, user, pass });
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
parseGraphql() {
|
|
1876
|
+
this.advance(); // graphql
|
|
1877
|
+
const path = this.parseString();
|
|
1878
|
+
return new ASTNode('GraphqlDecl', { path });
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
parseDesktop() {
|
|
1882
|
+
this.advance(); // desktop
|
|
1883
|
+
const name = this.expect(T.IDENT).value;
|
|
1884
|
+
this.expect(T.COLON);
|
|
1885
|
+
this.skipNewlines();
|
|
1886
|
+
this.expect(T.INDENT);
|
|
1887
|
+
let title = null, width = null, height = null, load = null;
|
|
1888
|
+
this.skipNewlines();
|
|
1889
|
+
while (!this.at(T.DEDENT) && !this.at(T.EOF)) {
|
|
1890
|
+
if (this.at(T.IDENT) && this.peek().value === 'title') {
|
|
1891
|
+
this.advance();
|
|
1892
|
+
title = this.parseString();
|
|
1893
|
+
} else if (this.at(T.IDENT) && this.peek().value === 'size') {
|
|
1894
|
+
this.advance();
|
|
1895
|
+
width = this.parseExpression();
|
|
1896
|
+
height = this.parseExpression();
|
|
1897
|
+
} else if (this.at(T.IDENT) && this.peek().value === 'load') {
|
|
1898
|
+
this.advance();
|
|
1899
|
+
load = this.parseExpression();
|
|
1900
|
+
} else {
|
|
1901
|
+
this.advance();
|
|
1902
|
+
}
|
|
1903
|
+
this.skipNewlines();
|
|
1904
|
+
}
|
|
1905
|
+
this.match(T.DEDENT);
|
|
1906
|
+
return new ASTNode('DesktopApp', { name, title, width, height, load });
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
parseScreen() {
|
|
1910
|
+
this.advance(); // screen
|
|
1911
|
+
const name = this.expect(T.IDENT).value;
|
|
1912
|
+
this.expect(T.COLON);
|
|
1913
|
+
this.skipNewlines();
|
|
1914
|
+
this.expect(T.INDENT);
|
|
1915
|
+
const elements = [];
|
|
1916
|
+
this.skipNewlines();
|
|
1917
|
+
while (!this.at(T.DEDENT) && !this.at(T.EOF)) {
|
|
1918
|
+
elements.push(this.parseScreenElement());
|
|
1919
|
+
this.skipNewlines();
|
|
1920
|
+
}
|
|
1921
|
+
this.match(T.DEDENT);
|
|
1922
|
+
return new ASTNode('Screen', { name, elements });
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
parseScreenElement() {
|
|
1926
|
+
const tag = this.advance().value;
|
|
1927
|
+
const args = [];
|
|
1928
|
+
while (this.at(T.STRING)) {
|
|
1929
|
+
args.push(this.parseString());
|
|
1930
|
+
}
|
|
1931
|
+
let body = [];
|
|
1932
|
+
if (this.at(T.COLON)) {
|
|
1933
|
+
this.advance();
|
|
1934
|
+
body = this.parseBlock();
|
|
1935
|
+
}
|
|
1936
|
+
return new ASTNode('ScreenElement', { tag, args, body });
|
|
1937
|
+
}
|
|
1740
1938
|
}
|
package/src/tokens.js
CHANGED
|
@@ -87,6 +87,12 @@ export const T = {
|
|
|
87
87
|
PROMPT: 'PROMPT',
|
|
88
88
|
BOT: 'BOT',
|
|
89
89
|
SLASH_CMD: 'SLASH_CMD',
|
|
90
|
+
PAGE: 'PAGE',
|
|
91
|
+
CLI_APP: 'CLI_APP',
|
|
92
|
+
MAIL: 'MAIL',
|
|
93
|
+
GRAPHQL: 'GRAPHQL',
|
|
94
|
+
DESKTOP: 'DESKTOP',
|
|
95
|
+
SCREEN: 'SCREEN',
|
|
90
96
|
|
|
91
97
|
// Operators
|
|
92
98
|
ASSIGN: 'ASSIGN',
|
|
@@ -202,6 +208,12 @@ export const KEYWORDS = {
|
|
|
202
208
|
'prompt': T.PROMPT,
|
|
203
209
|
'bot': T.BOT,
|
|
204
210
|
'slash': T.SLASH_CMD,
|
|
211
|
+
'page': T.PAGE,
|
|
212
|
+
'cli': T.CLI_APP,
|
|
213
|
+
'mail': T.MAIL,
|
|
214
|
+
'graphql': T.GRAPHQL,
|
|
215
|
+
'desktop': T.DESKTOP,
|
|
216
|
+
'screen': T.SCREEN,
|
|
205
217
|
'true': T.BOOL,
|
|
206
218
|
'false': T.BOOL,
|
|
207
219
|
'null': T.NULL,
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"name": "keyword.control.naide"
|
|
88
88
|
},
|
|
89
89
|
"keywords-server": {
|
|
90
|
-
"match": "\\b(server|bot|slash|get|post|put|del|patch|mid|cors|limit|auth|crud|static|ws|sse|group|upload|cookie|session|view|cache|validate|openapi|error|on)\\b",
|
|
90
|
+
"match": "\\b(server|bot|slash|get|post|put|del|patch|mid|cors|limit|auth|crud|static|ws|sse|group|upload|cookie|session|view|cache|validate|openapi|error|on|page|cli|mail|graphql|desktop|screen)\\b",
|
|
91
91
|
"name": "keyword.other.naide"
|
|
92
92
|
},
|
|
93
93
|
"keywords-declaration": {
|