tova 0.7.0 → 0.9.4
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/bin/tova.js +1312 -139
- package/package.json +8 -1
- package/src/analyzer/analyzer.js +539 -11
- package/src/analyzer/browser-analyzer.js +56 -8
- package/src/analyzer/deploy-analyzer.js +44 -0
- package/src/analyzer/scope.js +7 -0
- package/src/analyzer/server-analyzer.js +33 -1
- package/src/codegen/base-codegen.js +1296 -23
- package/src/codegen/browser-codegen.js +725 -20
- package/src/codegen/codegen.js +87 -5
- package/src/codegen/deploy-codegen.js +49 -0
- package/src/codegen/server-codegen.js +54 -6
- package/src/codegen/shared-codegen.js +5 -0
- package/src/codegen/theme-codegen.js +69 -0
- package/src/codegen/wasm-codegen.js +6 -0
- package/src/config/edit-toml.js +6 -2
- package/src/config/git-resolver.js +128 -0
- package/src/config/lock-file.js +57 -0
- package/src/config/module-cache.js +58 -0
- package/src/config/module-entry.js +37 -0
- package/src/config/module-path.js +63 -0
- package/src/config/pkg-errors.js +62 -0
- package/src/config/resolve.js +26 -0
- package/src/config/resolver.js +139 -0
- package/src/config/search.js +28 -0
- package/src/config/semver.js +72 -0
- package/src/config/toml.js +61 -6
- package/src/deploy/deploy.js +217 -0
- package/src/deploy/infer.js +218 -0
- package/src/deploy/provision.js +315 -0
- package/src/diagnostics/security-scorecard.js +111 -0
- package/src/lexer/lexer.js +18 -3
- package/src/lsp/server.js +482 -0
- package/src/parser/animate-ast.js +45 -0
- package/src/parser/ast.js +39 -0
- package/src/parser/browser-ast.js +19 -1
- package/src/parser/browser-parser.js +221 -4
- package/src/parser/concurrency-ast.js +15 -0
- package/src/parser/concurrency-parser.js +236 -0
- package/src/parser/deploy-ast.js +37 -0
- package/src/parser/deploy-parser.js +132 -0
- package/src/parser/parser.js +42 -5
- package/src/parser/select-ast.js +39 -0
- package/src/parser/theme-ast.js +29 -0
- package/src/parser/theme-parser.js +70 -0
- package/src/registry/plugins/concurrency-plugin.js +32 -0
- package/src/registry/plugins/deploy-plugin.js +33 -0
- package/src/registry/plugins/theme-plugin.js +20 -0
- package/src/registry/register-all.js +6 -0
- package/src/runtime/charts.js +547 -0
- package/src/runtime/embedded.js +6 -2
- package/src/runtime/reactivity.js +60 -0
- package/src/runtime/router.js +703 -295
- package/src/runtime/table.js +606 -33
- package/src/stdlib/inline.js +365 -10
- package/src/stdlib/runtime-bridge.js +152 -0
- package/src/stdlib/string.js +84 -2
- package/src/stdlib/validation.js +1 -1
- package/src/version.js +1 -1
package/src/lsp/server.js
CHANGED
|
@@ -121,6 +121,7 @@ class TovaLanguageServer {
|
|
|
121
121
|
case 'textDocument/codeAction': return this._onCodeAction(msg);
|
|
122
122
|
case 'textDocument/references': return this._onReferences(msg);
|
|
123
123
|
case 'textDocument/inlayHint': return this._onInlayHint(msg);
|
|
124
|
+
case 'textDocument/semanticTokens/full': return this._onSemanticTokensFull(msg);
|
|
124
125
|
case 'workspace/symbol': return this._onWorkspaceSymbol(msg);
|
|
125
126
|
default: return this._respondError(msg.id, -32601, `Method not found: ${method}`);
|
|
126
127
|
}
|
|
@@ -165,6 +166,48 @@ class TovaLanguageServer {
|
|
|
165
166
|
referencesProvider: true,
|
|
166
167
|
inlayHintProvider: true,
|
|
167
168
|
workspaceSymbolProvider: true,
|
|
169
|
+
semanticTokensProvider: {
|
|
170
|
+
legend: {
|
|
171
|
+
tokenTypes: [
|
|
172
|
+
'namespace', // 0
|
|
173
|
+
'type', // 1
|
|
174
|
+
'class', // 2
|
|
175
|
+
'enum', // 3
|
|
176
|
+
'interface', // 4
|
|
177
|
+
'struct', // 5
|
|
178
|
+
'typeParameter', // 6
|
|
179
|
+
'parameter', // 7
|
|
180
|
+
'variable', // 8
|
|
181
|
+
'property', // 9
|
|
182
|
+
'enumMember', // 10
|
|
183
|
+
'event', // 11
|
|
184
|
+
'function', // 12
|
|
185
|
+
'method', // 13
|
|
186
|
+
'macro', // 14
|
|
187
|
+
'keyword', // 15
|
|
188
|
+
'modifier', // 16
|
|
189
|
+
'comment', // 17
|
|
190
|
+
'string', // 18
|
|
191
|
+
'number', // 19
|
|
192
|
+
'regexp', // 20
|
|
193
|
+
'decorator', // 21
|
|
194
|
+
],
|
|
195
|
+
tokenModifiers: [
|
|
196
|
+
'declaration', // 0
|
|
197
|
+
'definition', // 1
|
|
198
|
+
'readonly', // 2
|
|
199
|
+
'static', // 3
|
|
200
|
+
'deprecated', // 4
|
|
201
|
+
'abstract', // 5
|
|
202
|
+
'async', // 6
|
|
203
|
+
'modification', // 7
|
|
204
|
+
'documentation', // 8
|
|
205
|
+
'defaultLibrary', // 9
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
full: true,
|
|
209
|
+
range: false,
|
|
210
|
+
},
|
|
168
211
|
},
|
|
169
212
|
});
|
|
170
213
|
}
|
|
@@ -1901,6 +1944,445 @@ class TovaLanguageServer {
|
|
|
1901
1944
|
return positions;
|
|
1902
1945
|
}
|
|
1903
1946
|
|
|
1947
|
+
// ─── Semantic Tokens ─────────────────────────────────────
|
|
1948
|
+
|
|
1949
|
+
_onSemanticTokensFull(msg) {
|
|
1950
|
+
const { textDocument } = msg.params;
|
|
1951
|
+
const cached = this._diagnosticsCache.get(textDocument.uri);
|
|
1952
|
+
if (!cached?.ast || !cached?.analyzer) {
|
|
1953
|
+
return this._respond(msg.id, { data: [] });
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
const tokens = [];
|
|
1957
|
+
try {
|
|
1958
|
+
this._walkASTForSemanticTokens(cached.ast, cached.analyzer, tokens);
|
|
1959
|
+
} catch (e) {
|
|
1960
|
+
this._logError(`Semantic tokens error: ${e.message}`);
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
// Sort by position (line first, then character)
|
|
1964
|
+
tokens.sort((a, b) => a.line - b.line || a.char - b.char);
|
|
1965
|
+
|
|
1966
|
+
// Delta-encode into flat array [deltaLine, deltaChar, length, tokenType, tokenModifiers]
|
|
1967
|
+
const data = [];
|
|
1968
|
+
let prevLine = 0;
|
|
1969
|
+
let prevChar = 0;
|
|
1970
|
+
|
|
1971
|
+
for (const tok of tokens) {
|
|
1972
|
+
const deltaLine = tok.line - prevLine;
|
|
1973
|
+
const deltaChar = deltaLine === 0 ? tok.char - prevChar : tok.char;
|
|
1974
|
+
data.push(deltaLine, deltaChar, tok.length, tok.tokenType, tok.modifiers);
|
|
1975
|
+
prevLine = tok.line;
|
|
1976
|
+
prevChar = tok.char;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
this._respond(msg.id, { data });
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
_walkASTForSemanticTokens(node, analyzer, tokens) {
|
|
1983
|
+
if (!node || typeof node !== 'object') return;
|
|
1984
|
+
|
|
1985
|
+
// Token type indices (must match legend in capabilities)
|
|
1986
|
+
const TT_NAMESPACE = 0;
|
|
1987
|
+
const TT_TYPE = 1;
|
|
1988
|
+
const TT_INTERFACE = 4;
|
|
1989
|
+
const TT_PARAMETER = 7;
|
|
1990
|
+
const TT_VARIABLE = 8;
|
|
1991
|
+
const TT_PROPERTY = 9;
|
|
1992
|
+
const TT_ENUM_MEMBER = 10;
|
|
1993
|
+
const TT_FUNCTION = 12;
|
|
1994
|
+
const TT_DECORATOR = 21;
|
|
1995
|
+
|
|
1996
|
+
// Token modifier bitmasks
|
|
1997
|
+
const TM_DECLARATION = 1 << 0;
|
|
1998
|
+
const TM_READONLY = 1 << 2;
|
|
1999
|
+
const TM_ASYNC = 1 << 6;
|
|
2000
|
+
const TM_DEFAULT_LIBRARY = 1 << 9;
|
|
2001
|
+
|
|
2002
|
+
const loc = node.loc || node.location;
|
|
2003
|
+
|
|
2004
|
+
switch (node.type) {
|
|
2005
|
+
case 'FunctionDeclaration': {
|
|
2006
|
+
// Emit function name
|
|
2007
|
+
if (node.name && loc) {
|
|
2008
|
+
const nameOffset = node.async ? 'async fn '.length : 'fn '.length;
|
|
2009
|
+
let modifiers = TM_DECLARATION;
|
|
2010
|
+
if (node.async) modifiers |= TM_ASYNC;
|
|
2011
|
+
tokens.push({
|
|
2012
|
+
line: (loc.line || 1) - 1,
|
|
2013
|
+
char: (loc.column || 1) - 1 + nameOffset,
|
|
2014
|
+
length: node.name.length,
|
|
2015
|
+
tokenType: TT_FUNCTION,
|
|
2016
|
+
modifiers,
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
// Walk parameters
|
|
2020
|
+
if (node.params) {
|
|
2021
|
+
for (const param of node.params) {
|
|
2022
|
+
this._walkASTForSemanticTokens(param, analyzer, tokens);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
// Walk return type
|
|
2026
|
+
if (node.returnType) {
|
|
2027
|
+
this._walkTypeAnnotation(node.returnType, tokens);
|
|
2028
|
+
}
|
|
2029
|
+
// Walk body
|
|
2030
|
+
if (node.body) {
|
|
2031
|
+
this._walkASTForSemanticTokens(node.body, analyzer, tokens);
|
|
2032
|
+
}
|
|
2033
|
+
return;
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
case 'Parameter': {
|
|
2037
|
+
if (node.name && loc) {
|
|
2038
|
+
tokens.push({
|
|
2039
|
+
line: (loc.line || 1) - 1,
|
|
2040
|
+
char: (loc.column || 1) - 1,
|
|
2041
|
+
length: node.name.length,
|
|
2042
|
+
tokenType: TT_PARAMETER,
|
|
2043
|
+
modifiers: TM_DECLARATION,
|
|
2044
|
+
});
|
|
2045
|
+
}
|
|
2046
|
+
if (node.typeAnnotation) {
|
|
2047
|
+
this._walkTypeAnnotation(node.typeAnnotation, tokens);
|
|
2048
|
+
}
|
|
2049
|
+
if (node.default) {
|
|
2050
|
+
this._walkASTForSemanticTokens(node.default, analyzer, tokens);
|
|
2051
|
+
}
|
|
2052
|
+
return;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
case 'TypeDeclaration': {
|
|
2056
|
+
if (node.name && loc) {
|
|
2057
|
+
const nameOffset = 'type '.length;
|
|
2058
|
+
tokens.push({
|
|
2059
|
+
line: (loc.line || 1) - 1,
|
|
2060
|
+
char: (loc.column || 1) - 1 + nameOffset,
|
|
2061
|
+
length: node.name.length,
|
|
2062
|
+
tokenType: TT_TYPE,
|
|
2063
|
+
modifiers: TM_DECLARATION,
|
|
2064
|
+
});
|
|
2065
|
+
}
|
|
2066
|
+
if (node.variants) {
|
|
2067
|
+
for (const v of node.variants) {
|
|
2068
|
+
this._walkASTForSemanticTokens(v, analyzer, tokens);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
if (node.fields) {
|
|
2072
|
+
for (const f of node.fields) {
|
|
2073
|
+
this._walkASTForSemanticTokens(f, analyzer, tokens);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
return;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
case 'TypeVariant': {
|
|
2080
|
+
if (node.name && loc) {
|
|
2081
|
+
tokens.push({
|
|
2082
|
+
line: (loc.line || 1) - 1,
|
|
2083
|
+
char: (loc.column || 1) - 1,
|
|
2084
|
+
length: node.name.length,
|
|
2085
|
+
tokenType: TT_ENUM_MEMBER,
|
|
2086
|
+
modifiers: TM_DECLARATION,
|
|
2087
|
+
});
|
|
2088
|
+
}
|
|
2089
|
+
if (node.fields) {
|
|
2090
|
+
for (const f of node.fields) {
|
|
2091
|
+
this._walkASTForSemanticTokens(f, analyzer, tokens);
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
return;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
case 'TypeField': {
|
|
2098
|
+
if (node.name && loc) {
|
|
2099
|
+
tokens.push({
|
|
2100
|
+
line: (loc.line || 1) - 1,
|
|
2101
|
+
char: (loc.column || 1) - 1,
|
|
2102
|
+
length: node.name.length,
|
|
2103
|
+
tokenType: TT_PROPERTY,
|
|
2104
|
+
modifiers: TM_DECLARATION,
|
|
2105
|
+
});
|
|
2106
|
+
}
|
|
2107
|
+
if (node.typeAnnotation) {
|
|
2108
|
+
this._walkTypeAnnotation(node.typeAnnotation, tokens);
|
|
2109
|
+
}
|
|
2110
|
+
return;
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
case 'InterfaceDeclaration':
|
|
2114
|
+
case 'TraitDeclaration': {
|
|
2115
|
+
if (node.name && loc) {
|
|
2116
|
+
const keyword = node.type === 'InterfaceDeclaration' ? 'interface ' : 'trait ';
|
|
2117
|
+
tokens.push({
|
|
2118
|
+
line: (loc.line || 1) - 1,
|
|
2119
|
+
char: (loc.column || 1) - 1 + keyword.length,
|
|
2120
|
+
length: node.name.length,
|
|
2121
|
+
tokenType: TT_INTERFACE,
|
|
2122
|
+
modifiers: TM_DECLARATION,
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
if (node.methods) {
|
|
2126
|
+
for (const m of node.methods) {
|
|
2127
|
+
this._walkASTForSemanticTokens(m, analyzer, tokens);
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
if (node.body) {
|
|
2131
|
+
this._walkASTForSemanticTokens(node.body, analyzer, tokens);
|
|
2132
|
+
}
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2135
|
+
|
|
2136
|
+
case 'ComponentDeclaration': {
|
|
2137
|
+
if (node.name && loc) {
|
|
2138
|
+
const nameOffset = 'component '.length;
|
|
2139
|
+
tokens.push({
|
|
2140
|
+
line: (loc.line || 1) - 1,
|
|
2141
|
+
char: (loc.column || 1) - 1 + nameOffset,
|
|
2142
|
+
length: node.name.length,
|
|
2143
|
+
tokenType: TT_TYPE,
|
|
2144
|
+
modifiers: TM_DECLARATION,
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
if (node.body) {
|
|
2148
|
+
this._walkASTForSemanticTokens(node.body, analyzer, tokens);
|
|
2149
|
+
}
|
|
2150
|
+
return;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
case 'StateDeclaration':
|
|
2154
|
+
case 'ComputedDeclaration': {
|
|
2155
|
+
if (node.name && loc) {
|
|
2156
|
+
const keyword = node.type === 'StateDeclaration' ? 'state ' : 'computed ';
|
|
2157
|
+
tokens.push({
|
|
2158
|
+
line: (loc.line || 1) - 1,
|
|
2159
|
+
char: (loc.column || 1) - 1 + keyword.length,
|
|
2160
|
+
length: node.name.length,
|
|
2161
|
+
tokenType: TT_VARIABLE,
|
|
2162
|
+
modifiers: TM_DECLARATION,
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
2165
|
+
if (node.value) {
|
|
2166
|
+
this._walkASTForSemanticTokens(node.value, analyzer, tokens);
|
|
2167
|
+
}
|
|
2168
|
+
if (node.body) {
|
|
2169
|
+
this._walkASTForSemanticTokens(node.body, analyzer, tokens);
|
|
2170
|
+
}
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
case 'Assignment': {
|
|
2175
|
+
if (node.name && loc) {
|
|
2176
|
+
tokens.push({
|
|
2177
|
+
line: (loc.line || 1) - 1,
|
|
2178
|
+
char: (loc.column || 1) - 1,
|
|
2179
|
+
length: node.name.length,
|
|
2180
|
+
tokenType: TT_VARIABLE,
|
|
2181
|
+
modifiers: TM_DECLARATION | TM_READONLY,
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
if (node.typeAnnotation) {
|
|
2185
|
+
this._walkTypeAnnotation(node.typeAnnotation, tokens);
|
|
2186
|
+
}
|
|
2187
|
+
if (node.value) {
|
|
2188
|
+
this._walkASTForSemanticTokens(node.value, analyzer, tokens);
|
|
2189
|
+
}
|
|
2190
|
+
return;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
case 'VarDeclaration': {
|
|
2194
|
+
if (node.name && loc) {
|
|
2195
|
+
const nameOffset = 'var '.length;
|
|
2196
|
+
tokens.push({
|
|
2197
|
+
line: (loc.line || 1) - 1,
|
|
2198
|
+
char: (loc.column || 1) - 1 + nameOffset,
|
|
2199
|
+
length: node.name.length,
|
|
2200
|
+
tokenType: TT_VARIABLE,
|
|
2201
|
+
modifiers: TM_DECLARATION,
|
|
2202
|
+
});
|
|
2203
|
+
}
|
|
2204
|
+
if (node.typeAnnotation) {
|
|
2205
|
+
this._walkTypeAnnotation(node.typeAnnotation, tokens);
|
|
2206
|
+
}
|
|
2207
|
+
if (node.value) {
|
|
2208
|
+
this._walkASTForSemanticTokens(node.value, analyzer, tokens);
|
|
2209
|
+
}
|
|
2210
|
+
return;
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
case 'CallExpression': {
|
|
2214
|
+
// Emit callee as function
|
|
2215
|
+
if (node.callee) {
|
|
2216
|
+
if (node.callee.type === 'Identifier' && node.callee.name) {
|
|
2217
|
+
const calleeLoc = node.callee.loc || node.callee.location;
|
|
2218
|
+
if (calleeLoc) {
|
|
2219
|
+
let modifiers = 0;
|
|
2220
|
+
if (BUILTIN_NAMES.has(node.callee.name)) {
|
|
2221
|
+
modifiers |= TM_DEFAULT_LIBRARY;
|
|
2222
|
+
}
|
|
2223
|
+
tokens.push({
|
|
2224
|
+
line: (calleeLoc.line || 1) - 1,
|
|
2225
|
+
char: (calleeLoc.column || 1) - 1,
|
|
2226
|
+
length: node.callee.name.length,
|
|
2227
|
+
tokenType: TT_FUNCTION,
|
|
2228
|
+
modifiers,
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
} else {
|
|
2232
|
+
this._walkASTForSemanticTokens(node.callee, analyzer, tokens);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
// Walk arguments
|
|
2236
|
+
if (node.args) {
|
|
2237
|
+
for (const arg of node.args) {
|
|
2238
|
+
this._walkASTForSemanticTokens(arg, analyzer, tokens);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
if (node.arguments) {
|
|
2242
|
+
for (const arg of node.arguments) {
|
|
2243
|
+
this._walkASTForSemanticTokens(arg, analyzer, tokens);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
case 'MemberExpression': {
|
|
2250
|
+
// Walk object
|
|
2251
|
+
if (node.object) {
|
|
2252
|
+
this._walkASTForSemanticTokens(node.object, analyzer, tokens);
|
|
2253
|
+
}
|
|
2254
|
+
// Emit property
|
|
2255
|
+
if (node.property && typeof node.property === 'object' && node.property.name) {
|
|
2256
|
+
const propLoc = node.property.loc || node.property.location;
|
|
2257
|
+
if (propLoc) {
|
|
2258
|
+
tokens.push({
|
|
2259
|
+
line: (propLoc.line || 1) - 1,
|
|
2260
|
+
char: (propLoc.column || 1) - 1,
|
|
2261
|
+
length: node.property.name.length,
|
|
2262
|
+
tokenType: TT_PROPERTY,
|
|
2263
|
+
modifiers: 0,
|
|
2264
|
+
});
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
case 'ServerBlock':
|
|
2271
|
+
case 'BrowserBlock':
|
|
2272
|
+
case 'SharedBlock':
|
|
2273
|
+
case 'ClientBlock': {
|
|
2274
|
+
if (loc) {
|
|
2275
|
+
const keyword = node.type.replace('Block', '').toLowerCase();
|
|
2276
|
+
tokens.push({
|
|
2277
|
+
line: (loc.line || 1) - 1,
|
|
2278
|
+
char: (loc.column || 1) - 1,
|
|
2279
|
+
length: keyword.length,
|
|
2280
|
+
tokenType: TT_NAMESPACE,
|
|
2281
|
+
modifiers: 0,
|
|
2282
|
+
});
|
|
2283
|
+
}
|
|
2284
|
+
if (node.body) {
|
|
2285
|
+
if (Array.isArray(node.body)) {
|
|
2286
|
+
for (const child of node.body) {
|
|
2287
|
+
this._walkASTForSemanticTokens(child, analyzer, tokens);
|
|
2288
|
+
}
|
|
2289
|
+
} else {
|
|
2290
|
+
this._walkASTForSemanticTokens(node.body, analyzer, tokens);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
case 'Identifier': {
|
|
2297
|
+
if (node.name && loc) {
|
|
2298
|
+
const sym = this._findSymbolInScopes(analyzer, node.name);
|
|
2299
|
+
if (sym) {
|
|
2300
|
+
let tokenType = TT_VARIABLE;
|
|
2301
|
+
let modifiers = 0;
|
|
2302
|
+
|
|
2303
|
+
if (sym.kind === 'function') tokenType = TT_FUNCTION;
|
|
2304
|
+
else if (sym.kind === 'type') tokenType = TT_TYPE;
|
|
2305
|
+
else if (sym.kind === 'parameter') tokenType = TT_PARAMETER;
|
|
2306
|
+
|
|
2307
|
+
if (BUILTIN_NAMES.has(node.name)) {
|
|
2308
|
+
modifiers |= TM_DEFAULT_LIBRARY;
|
|
2309
|
+
}
|
|
2310
|
+
|
|
2311
|
+
tokens.push({
|
|
2312
|
+
line: (loc.line || 1) - 1,
|
|
2313
|
+
char: (loc.column || 1) - 1,
|
|
2314
|
+
length: node.name.length,
|
|
2315
|
+
tokenType,
|
|
2316
|
+
modifiers,
|
|
2317
|
+
});
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
case 'Decorator': {
|
|
2324
|
+
if (node.name && loc) {
|
|
2325
|
+
tokens.push({
|
|
2326
|
+
line: (loc.line || 1) - 1,
|
|
2327
|
+
char: (loc.column || 1) - 1,
|
|
2328
|
+
length: node.name.length + 1, // include @
|
|
2329
|
+
tokenType: TT_DECORATOR,
|
|
2330
|
+
modifiers: 0,
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
return;
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
// Default: recursively walk all children that have .type (AST nodes)
|
|
2338
|
+
for (const key of Object.keys(node)) {
|
|
2339
|
+
if (key === 'loc' || key === 'location' || key === 'type') continue;
|
|
2340
|
+
const child = node[key];
|
|
2341
|
+
if (Array.isArray(child)) {
|
|
2342
|
+
for (const item of child) {
|
|
2343
|
+
if (item && typeof item === 'object' && item.type) {
|
|
2344
|
+
this._walkASTForSemanticTokens(item, analyzer, tokens);
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
} else if (child && typeof child === 'object' && child.type) {
|
|
2348
|
+
this._walkASTForSemanticTokens(child, analyzer, tokens);
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
_walkTypeAnnotation(typeNode, tokens) {
|
|
2354
|
+
if (!typeNode || typeof typeNode !== 'object') return;
|
|
2355
|
+
const loc = typeNode.loc || typeNode.location;
|
|
2356
|
+
|
|
2357
|
+
// Named type reference
|
|
2358
|
+
if (typeNode.name && loc) {
|
|
2359
|
+
tokens.push({
|
|
2360
|
+
line: (loc.line || 1) - 1,
|
|
2361
|
+
char: (loc.column || 1) - 1,
|
|
2362
|
+
length: typeNode.name.length,
|
|
2363
|
+
tokenType: 1, // TT_TYPE
|
|
2364
|
+
modifiers: 0,
|
|
2365
|
+
});
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
// Generic type parameters: e.g. List<Int>
|
|
2369
|
+
if (typeNode.typeArgs) {
|
|
2370
|
+
for (const arg of typeNode.typeArgs) {
|
|
2371
|
+
this._walkTypeAnnotation(arg, tokens);
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
if (typeNode.params) {
|
|
2375
|
+
for (const p of typeNode.params) {
|
|
2376
|
+
this._walkTypeAnnotation(p, tokens);
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
// Union types, function types, etc.
|
|
2380
|
+
if (typeNode.left) this._walkTypeAnnotation(typeNode.left, tokens);
|
|
2381
|
+
if (typeNode.right) this._walkTypeAnnotation(typeNode.right, tokens);
|
|
2382
|
+
if (typeNode.returnType) this._walkTypeAnnotation(typeNode.returnType, tokens);
|
|
2383
|
+
if (typeNode.elementType) this._walkTypeAnnotation(typeNode.elementType, tokens);
|
|
2384
|
+
}
|
|
2385
|
+
|
|
1904
2386
|
// ─── Utilities ────────────────────────────────────────────
|
|
1905
2387
|
|
|
1906
2388
|
_uriToPath(uri) {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Animate-specific AST Node definitions for the Tova language
|
|
2
|
+
// Extracted for lazy loading — only loaded when animate { } blocks are used.
|
|
3
|
+
|
|
4
|
+
// ============================================================
|
|
5
|
+
// Animate-specific nodes
|
|
6
|
+
// ============================================================
|
|
7
|
+
|
|
8
|
+
export class AnimateDeclaration {
|
|
9
|
+
constructor(name, enter, exit, duration, easing, stagger, stay, loc) {
|
|
10
|
+
this.type = 'AnimateDeclaration';
|
|
11
|
+
this.name = name; // string — animation name, e.g. "fadeIn"
|
|
12
|
+
this.enter = enter; // AnimatePrimitive|AnimateSequence|AnimateParallel|null
|
|
13
|
+
this.exit = exit; // AnimatePrimitive|AnimateSequence|AnimateParallel|null
|
|
14
|
+
this.duration = duration; // number|null — duration in ms
|
|
15
|
+
this.easing = easing; // string|null — CSS easing function
|
|
16
|
+
this.stagger = stagger; // number|null — stagger delay in ms
|
|
17
|
+
this.stay = stay; // number|null — auto-dismiss delay in ms
|
|
18
|
+
this.loc = loc;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class AnimatePrimitive {
|
|
23
|
+
constructor(name, params, loc) {
|
|
24
|
+
this.type = 'AnimatePrimitive';
|
|
25
|
+
this.name = name; // 'fade'|'slide'|'scale'|'rotate'|'blur'
|
|
26
|
+
this.params = params; // object e.g. {from: 0, to: 1, y: 20}
|
|
27
|
+
this.loc = loc;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class AnimateSequence {
|
|
32
|
+
constructor(children, loc) {
|
|
33
|
+
this.type = 'AnimateSequence';
|
|
34
|
+
this.children = children; // AnimatePrimitive[] or AnimateParallel[]
|
|
35
|
+
this.loc = loc;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class AnimateParallel {
|
|
40
|
+
constructor(children, loc) {
|
|
41
|
+
this.type = 'AnimateParallel';
|
|
42
|
+
this.children = children; // AnimatePrimitive[]
|
|
43
|
+
this.loc = loc;
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/parser/ast.js
CHANGED
|
@@ -73,6 +73,16 @@ export class EdgeBlock {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
export class ConcurrentBlock {
|
|
77
|
+
constructor(mode, timeout, body, loc) {
|
|
78
|
+
this.type = 'ConcurrentBlock';
|
|
79
|
+
this.mode = mode; // "all" | "cancel_on_error" | "first"
|
|
80
|
+
this.timeout = timeout; // Expression | null
|
|
81
|
+
this.body = body; // Array of statements
|
|
82
|
+
this.loc = loc;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
76
86
|
// ============================================================
|
|
77
87
|
// Declarations
|
|
78
88
|
// ============================================================
|
|
@@ -694,6 +704,7 @@ export {
|
|
|
694
704
|
ComponentDeclaration, ComponentStyleBlock, StoreDeclaration,
|
|
695
705
|
JSXElement, JSXAttribute, JSXSpreadAttribute, JSXFragment,
|
|
696
706
|
JSXText, JSXExpression, JSXFor, JSXIf, JSXMatch,
|
|
707
|
+
FontDeclaration,
|
|
697
708
|
} from './browser-ast.js';
|
|
698
709
|
|
|
699
710
|
// ============================================================
|
|
@@ -735,6 +746,14 @@ export {
|
|
|
735
746
|
EdgeSecretDeclaration, EdgeScheduleDeclaration, EdgeConsumeDeclaration,
|
|
736
747
|
} from './edge-ast.js';
|
|
737
748
|
|
|
749
|
+
// ============================================================
|
|
750
|
+
// Deploy-specific nodes (lazy-loaded from deploy-ast.js, re-exported for backward compat)
|
|
751
|
+
// ============================================================
|
|
752
|
+
|
|
753
|
+
export {
|
|
754
|
+
DeployBlock, DeployConfigField, DeployEnvBlock, DeployDbBlock,
|
|
755
|
+
} from './deploy-ast.js';
|
|
756
|
+
|
|
738
757
|
// ============================================================
|
|
739
758
|
// Form-specific nodes (lazy-loaded from form-ast.js, re-exported for backward compat)
|
|
740
759
|
// ============================================================
|
|
@@ -744,6 +763,26 @@ export {
|
|
|
744
763
|
FormArrayDeclaration, FormValidator, FormStepsDeclaration, FormStep,
|
|
745
764
|
} from './form-ast.js';
|
|
746
765
|
|
|
766
|
+
// ============================================================
|
|
767
|
+
// Select-specific nodes (lazy-loaded from select-ast.js, re-exported for backward compat)
|
|
768
|
+
// ============================================================
|
|
769
|
+
|
|
770
|
+
export { SelectStatement, SelectCase } from './select-ast.js';
|
|
771
|
+
|
|
772
|
+
// ============================================================
|
|
773
|
+
// Theme-specific nodes (lazy-loaded from theme-ast.js, re-exported for backward compat)
|
|
774
|
+
// ============================================================
|
|
775
|
+
|
|
776
|
+
export { ThemeBlock, ThemeSection, ThemeToken } from './theme-ast.js';
|
|
777
|
+
|
|
778
|
+
// ============================================================
|
|
779
|
+
// Animate-specific nodes (lazy-loaded from animate-ast.js, re-exported for backward compat)
|
|
780
|
+
// ============================================================
|
|
781
|
+
|
|
782
|
+
export {
|
|
783
|
+
AnimateDeclaration, AnimatePrimitive, AnimateSequence, AnimateParallel,
|
|
784
|
+
} from './animate-ast.js';
|
|
785
|
+
|
|
747
786
|
export class TestBlock {
|
|
748
787
|
constructor(name, body, loc, options = {}) {
|
|
749
788
|
this.type = 'TestBlock';
|
|
@@ -39,13 +39,17 @@ export class ComponentDeclaration {
|
|
|
39
39
|
this.params = params;
|
|
40
40
|
this.body = body; // Array of JSX elements and statements
|
|
41
41
|
this.loc = loc;
|
|
42
|
+
// Compound component fields (set by parser for Dialog.Title etc.)
|
|
43
|
+
this.parent = null;
|
|
44
|
+
this.child = null;
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
export class ComponentStyleBlock {
|
|
46
|
-
constructor(css, loc) {
|
|
49
|
+
constructor(css, loc, config) {
|
|
47
50
|
this.type = 'ComponentStyleBlock';
|
|
48
51
|
this.css = css; // raw CSS string
|
|
52
|
+
this.config = config || null; // e.g. { motion: 'full' } from style(motion: full)
|
|
49
53
|
this.loc = loc;
|
|
50
54
|
}
|
|
51
55
|
}
|
|
@@ -145,3 +149,17 @@ export class JSXMatch {
|
|
|
145
149
|
this.loc = loc;
|
|
146
150
|
}
|
|
147
151
|
}
|
|
152
|
+
|
|
153
|
+
// ============================================================
|
|
154
|
+
// Font loading
|
|
155
|
+
// ============================================================
|
|
156
|
+
|
|
157
|
+
export class FontDeclaration {
|
|
158
|
+
constructor(name, source, config, loc) {
|
|
159
|
+
this.type = 'FontDeclaration';
|
|
160
|
+
this.name = name; // string - font identifier
|
|
161
|
+
this.source = source; // string - URL or local path
|
|
162
|
+
this.config = config; // { weight, style, display } or null
|
|
163
|
+
this.loc = loc;
|
|
164
|
+
}
|
|
165
|
+
}
|