@vesk/compiler 0.2.42 → 0.2.43
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/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +17 -1
- package/dist/client-codegen.d.ts +17 -0
- package/dist/client-codegen.d.ts.map +1 -1
- package/dist/client-codegen.js +211 -15
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +15 -0
- package/dist/ir-generator.d.ts.map +1 -1
- package/dist/ir-generator.js +303 -199
- package/dist/ir.d.ts +22 -1
- package/dist/ir.d.ts.map +1 -1
- package/dist/ir.js +18 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +25 -1
- package/dist/precompile-runtime.d.ts.map +1 -1
- package/dist/precompile-runtime.js +4 -0
- package/dist/precompile.js +6 -2
- package/dist/server-jsgen.d.ts.map +1 -1
- package/dist/server-jsgen.js +8 -1
- package/dist/server-render.d.ts.map +1 -1
- package/dist/server-render.js +9 -2
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +33 -5
- package/dist/tokens.d.ts +28 -0
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +200 -19
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/vesk-plugin.d.ts +2 -0
- package/dist/vesk-plugin.d.ts.map +1 -1
- package/dist/vesk-plugin.js +28 -1
- package/dist/vsk-imports.d.ts +51 -0
- package/dist/vsk-imports.d.ts.map +1 -1
- package/dist/vsk-imports.js +106 -9
- package/package.json +2 -2
package/dist/vesk-plugin.js
CHANGED
|
@@ -156,6 +156,24 @@ function matchKeywordSequence(input, words) {
|
|
|
156
156
|
const c = input.charCodeAt(p);
|
|
157
157
|
return isWsChar(c) || c === 123;
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* True only while `tokenizeCode` drives the tokenizer directly. Acorn's
|
|
161
|
+
* `getOptions` copies only known option keys, so the request cannot travel on
|
|
162
|
+
* the options object — it is scoped here instead. Tokenizing is synchronous,
|
|
163
|
+
* so the save/restore is safe.
|
|
164
|
+
*/
|
|
165
|
+
let standaloneTokens = false;
|
|
166
|
+
/** Runs `fn` with JSX tag recognition enabled without a parser driving it. */
|
|
167
|
+
export function withStandaloneTokens(fn) {
|
|
168
|
+
const prev = standaloneTokens;
|
|
169
|
+
standaloneTokens = true;
|
|
170
|
+
try {
|
|
171
|
+
return fn();
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
standaloneTokens = prev;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
159
177
|
export function VeskParserPlugin(config = {}) {
|
|
160
178
|
return (Parser) => {
|
|
161
179
|
const tt = Parser.tokTypes || acorn.tokTypes;
|
|
@@ -170,6 +188,15 @@ export function VeskParserPlugin(config = {}) {
|
|
|
170
188
|
#jsxChildDepthStack = [];
|
|
171
189
|
constructor(options, input) {
|
|
172
190
|
super(options, input);
|
|
191
|
+
// The standalone tokenizer (`tokenizeCode`) drives `getToken()` without
|
|
192
|
+
// ever running the parser, so `component X { … }` never raises
|
|
193
|
+
// #componentDepth and every JSX tag would be read as relational
|
|
194
|
+
// operators. Callers that only need a token stream still need JSX, so
|
|
195
|
+
// they opt in explicitly; parser-driven parses are unaffected.
|
|
196
|
+
}
|
|
197
|
+
/** True when JSX tags are recognised without parser-driven componentDepth. */
|
|
198
|
+
#jsxAllowed() {
|
|
199
|
+
return this.#componentDepth > 0 || standaloneTokens;
|
|
173
200
|
}
|
|
174
201
|
#isBlockContext() {
|
|
175
202
|
const ctx = this.curContext();
|
|
@@ -461,7 +488,7 @@ export function VeskParserPlugin(config = {}) {
|
|
|
461
488
|
}
|
|
462
489
|
return super.readToken(this.input.codePointAt(this.pos));
|
|
463
490
|
}
|
|
464
|
-
if (this.#
|
|
491
|
+
if (this.#jsxAllowed() && code === 60 && this.#isBlockContext()) {
|
|
465
492
|
const next = this.input.charCodeAt(this.pos + 1);
|
|
466
493
|
const startsNewStatement = this.hasPrecedingLineBreak();
|
|
467
494
|
const inType = this.inType;
|
package/dist/vsk-imports.d.ts
CHANGED
|
@@ -16,7 +16,58 @@ export declare function vskImportTarget(importText: string): string | null;
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function extractImportStatements(source: string): string[];
|
|
18
18
|
export declare function collectVskImportPaths(imports: string[], sourcePath: string): string[];
|
|
19
|
+
/**
|
|
20
|
+
* Resolves `export ... from './path.vsk'` targets the same way imports resolve,
|
|
21
|
+
* so a `.vsk` barrel re-export is followed and compiled into the importing
|
|
22
|
+
* file's component registry instead of being emitted as a bare re-export.
|
|
23
|
+
*/
|
|
24
|
+
export declare function collectVskReexportPaths(reexportSources: string[], sourcePath: string): string[];
|
|
25
|
+
/**
|
|
26
|
+
* Local names bound by *named* value imports from a `.vsk` module.
|
|
27
|
+
*
|
|
28
|
+
* `.vsk` imports are value-less for component resolution (components are
|
|
29
|
+
* registry entries), but a `.vsk` module may still export plain values —
|
|
30
|
+
* `export const MAX = 10`, `export function format(x) {}`. Those live in the
|
|
31
|
+
* sub-file's `__vesk` and are hoisted into the importer, so the importer's
|
|
32
|
+
* component scope must destructure them.
|
|
33
|
+
*
|
|
34
|
+
* Returned separately from `localValueImportNames` because a name bound this
|
|
35
|
+
* way must NOT be treated as a direct-call target at a JSX call site: it may be
|
|
36
|
+
* a component, which resolves through the registry, not through a scope local.
|
|
37
|
+
*/
|
|
38
|
+
export declare function vskImportValueNames(imports: string[]): string[];
|
|
19
39
|
export declare function vskImportLines(source: string): string[];
|
|
40
|
+
/**
|
|
41
|
+
* Registry aliases contributed by one file's export/import statements.
|
|
42
|
+
*
|
|
43
|
+
* `.vsk` modules are not real ES modules — a component is a registry entry
|
|
44
|
+
* keyed by its declared name, not a top-level binding — so neither
|
|
45
|
+
* `export { A as B }` nor `import { A as B } from './x.vsk'` can be satisfied
|
|
46
|
+
* by emitting JS. Both are instead recorded as registry aliases so `<B />`
|
|
47
|
+
* resolves to the same function as `<A />`. Each pair is
|
|
48
|
+
* `{ local: <canonical name>, exported: <name the tag uses> }`.
|
|
49
|
+
*
|
|
50
|
+
* `default` and `*` are deliberately skipped: the registry is keyed by the
|
|
51
|
+
* component's *declared* name, which is unrelated to the `default` specifier.
|
|
52
|
+
*/
|
|
53
|
+
export declare function vskRegistryAliases(importLines: string[], exportAliases: Array<{
|
|
54
|
+
local: string;
|
|
55
|
+
exported: string;
|
|
56
|
+
}>): Array<{
|
|
57
|
+
local: string;
|
|
58
|
+
exported: string;
|
|
59
|
+
}>;
|
|
60
|
+
/**
|
|
61
|
+
* Registers every alias in `aliases` against `componentMap`, pointing each
|
|
62
|
+
* exported name at the function its local name already resolves to. Names that
|
|
63
|
+
* do not resolve (a non-component value, or a component from a file that was
|
|
64
|
+
* not compiled) are left untouched so the original "not found" diagnostic
|
|
65
|
+
* still names the real missing component.
|
|
66
|
+
*/
|
|
67
|
+
export declare function applyVskRegistryAliases(componentMap: Map<string, Function>, aliases: Array<{
|
|
68
|
+
local: string;
|
|
69
|
+
exported: string;
|
|
70
|
+
}>): void;
|
|
20
71
|
/**
|
|
21
72
|
* True when an `ImportDeclaration` is type-only: an `import type { ... }`
|
|
22
73
|
* statement, or a value import whose specifiers are all `type` specifiers.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vsk-imports.d.ts","sourceRoot":"","sources":["../src/vsk-imports.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AAEH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAahE;AA0BD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"vsk-imports.d.ts","sourceRoot":"","sources":["../src/vsk-imports.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AAEH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQjE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAahE;AA0BD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAUrF;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ/F;AAWD;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAW/D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAEvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,aAAa,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GACxD,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgB5C;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,EACnC,OAAO,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAClD,IAAI,CAMN;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,GAAG,GAAG,OAAO,CAKnD;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAsBhE"}
|
package/dist/vsk-imports.js
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync } from 'node:fs';
|
|
|
3
3
|
import { print } from 'esrap';
|
|
4
4
|
import ts from 'esrap/languages/ts';
|
|
5
5
|
import { parse } from '@vesk/compiler/src/parser';
|
|
6
|
-
import { resolveImportPath } from '@vesk/compiler/src/module-imports';
|
|
6
|
+
import { importBindingPairs, resolveImportPath } from '@vesk/compiler/src/module-imports';
|
|
7
7
|
import { importModuleTarget, tokenizeCode } from '@vesk/compiler/src/tokens';
|
|
8
8
|
/**
|
|
9
9
|
* Resolve `import ... from './path.vsk'` statements so helper components can
|
|
@@ -88,21 +88,118 @@ export function collectVskImportPaths(imports, sourcePath) {
|
|
|
88
88
|
const target = vskImportTarget(imp);
|
|
89
89
|
if (!target)
|
|
90
90
|
continue;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
const full = resolveVskTarget(target, sourcePath);
|
|
92
|
+
if (full)
|
|
93
|
+
out.push(full);
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Resolves `export ... from './path.vsk'` targets the same way imports resolve,
|
|
99
|
+
* so a `.vsk` barrel re-export is followed and compiled into the importing
|
|
100
|
+
* file's component registry instead of being emitted as a bare re-export.
|
|
101
|
+
*/
|
|
102
|
+
export function collectVskReexportPaths(reexportSources, sourcePath) {
|
|
103
|
+
const out = [];
|
|
104
|
+
for (const spec of reexportSources) {
|
|
105
|
+
if (!spec.endsWith('.vsk'))
|
|
95
106
|
continue;
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
out.push(aliased);
|
|
107
|
+
const full = resolveVskTarget(spec, sourcePath);
|
|
108
|
+
if (full)
|
|
109
|
+
out.push(full);
|
|
100
110
|
}
|
|
101
111
|
return out;
|
|
102
112
|
}
|
|
113
|
+
function resolveVskTarget(target, sourcePath) {
|
|
114
|
+
if (target.startsWith('.')) {
|
|
115
|
+
const full = resolve(dirname(sourcePath), target);
|
|
116
|
+
return existsSync(full) ? full : null;
|
|
117
|
+
}
|
|
118
|
+
const aliased = resolveImportPath(target, dirname(sourcePath));
|
|
119
|
+
return aliased !== target && existsSync(aliased) ? aliased : null;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Local names bound by *named* value imports from a `.vsk` module.
|
|
123
|
+
*
|
|
124
|
+
* `.vsk` imports are value-less for component resolution (components are
|
|
125
|
+
* registry entries), but a `.vsk` module may still export plain values —
|
|
126
|
+
* `export const MAX = 10`, `export function format(x) {}`. Those live in the
|
|
127
|
+
* sub-file's `__vesk` and are hoisted into the importer, so the importer's
|
|
128
|
+
* component scope must destructure them.
|
|
129
|
+
*
|
|
130
|
+
* Returned separately from `localValueImportNames` because a name bound this
|
|
131
|
+
* way must NOT be treated as a direct-call target at a JSX call site: it may be
|
|
132
|
+
* a component, which resolves through the registry, not through a scope local.
|
|
133
|
+
*/
|
|
134
|
+
export function vskImportValueNames(imports) {
|
|
135
|
+
const names = [];
|
|
136
|
+
for (const imp of imports) {
|
|
137
|
+
if (stripTypeImport(imp) === null)
|
|
138
|
+
continue;
|
|
139
|
+
if (vskImportTarget(imp) === null)
|
|
140
|
+
continue;
|
|
141
|
+
for (const pair of importBindingPairs(imp)) {
|
|
142
|
+
if (pair.imported === 'default' || pair.imported === '*')
|
|
143
|
+
continue;
|
|
144
|
+
names.push(pair.local);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return names;
|
|
148
|
+
}
|
|
103
149
|
export function vskImportLines(source) {
|
|
104
150
|
return extractImportStatements(source).filter((imp) => vskImportTarget(imp) !== null && stripTypeImport(imp) !== null);
|
|
105
151
|
}
|
|
152
|
+
/**
|
|
153
|
+
* Registry aliases contributed by one file's export/import statements.
|
|
154
|
+
*
|
|
155
|
+
* `.vsk` modules are not real ES modules — a component is a registry entry
|
|
156
|
+
* keyed by its declared name, not a top-level binding — so neither
|
|
157
|
+
* `export { A as B }` nor `import { A as B } from './x.vsk'` can be satisfied
|
|
158
|
+
* by emitting JS. Both are instead recorded as registry aliases so `<B />`
|
|
159
|
+
* resolves to the same function as `<A />`. Each pair is
|
|
160
|
+
* `{ local: <canonical name>, exported: <name the tag uses> }`.
|
|
161
|
+
*
|
|
162
|
+
* `default` and `*` are deliberately skipped: the registry is keyed by the
|
|
163
|
+
* component's *declared* name, which is unrelated to the `default` specifier.
|
|
164
|
+
*/
|
|
165
|
+
export function vskRegistryAliases(importLines, exportAliases) {
|
|
166
|
+
const aliases = [];
|
|
167
|
+
for (const alias of exportAliases) {
|
|
168
|
+
if (alias.local !== alias.exported)
|
|
169
|
+
aliases.push({ local: alias.local, exported: alias.exported });
|
|
170
|
+
}
|
|
171
|
+
for (const imp of importLines) {
|
|
172
|
+
if (stripTypeImport(imp) === null)
|
|
173
|
+
continue;
|
|
174
|
+
if (vskImportTarget(imp) === null)
|
|
175
|
+
continue;
|
|
176
|
+
for (const pair of importBindingPairs(imp)) {
|
|
177
|
+
if (pair.imported === 'default' || pair.imported === '*')
|
|
178
|
+
continue;
|
|
179
|
+
// `import { A as B }` → the CANONICAL name is `pair.imported` ('A') and
|
|
180
|
+
// the ALIAS the tag actually uses is `pair.local` ('B').
|
|
181
|
+
if (pair.local !== pair.imported)
|
|
182
|
+
aliases.push({ local: pair.imported, exported: pair.local });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return aliases;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Registers every alias in `aliases` against `componentMap`, pointing each
|
|
189
|
+
* exported name at the function its local name already resolves to. Names that
|
|
190
|
+
* do not resolve (a non-component value, or a component from a file that was
|
|
191
|
+
* not compiled) are left untouched so the original "not found" diagnostic
|
|
192
|
+
* still names the real missing component.
|
|
193
|
+
*/
|
|
194
|
+
export function applyVskRegistryAliases(componentMap, aliases) {
|
|
195
|
+
for (const { local, exported } of aliases) {
|
|
196
|
+
if (componentMap.has(exported))
|
|
197
|
+
continue;
|
|
198
|
+
const fn = componentMap.get(local);
|
|
199
|
+
if (fn)
|
|
200
|
+
componentMap.set(exported, fn);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
106
203
|
/**
|
|
107
204
|
* True when an `ImportDeclaration` is type-only: an `import type { ... }`
|
|
108
205
|
* statement, or a value import whose specifiers are all `type` specifiers.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vesk/compiler",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.43",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Vesk compiler — lexer, parser, semantic analysis, IR, codegen",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@sveltejs/acorn-typescript": "^1.0.0",
|
|
23
|
-
"@vesk/types": "^0.2.
|
|
23
|
+
"@vesk/types": "^0.2.43",
|
|
24
24
|
"acorn": "^8.15.0",
|
|
25
25
|
"esrap": "^2.3.0",
|
|
26
26
|
"is-reference": "^3.0.0",
|