@firsthandjs/compiler 0.6.3 → 0.7.1
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/api.d.ts +4 -4
- package/dist/api.d.ts.map +1 -1
- package/dist/{chunk-UYA7HB5G.js → chunk-7DU5USN7.js} +110 -1
- package/dist/index.js +1 -1
- package/dist/transform.d.ts +4 -4
- package/dist/transform.d.ts.map +1 -1
- package/dist/vite.d.ts +2 -2
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +1 -1
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export interface TransformOptions extends FirsthandPluginOptions {
|
|
|
19
19
|
* inside this repository and fails in the first application that puts the
|
|
20
20
|
* plugin into `vite.config.ts` — which is the one place it matters.
|
|
21
21
|
*/
|
|
22
|
-
export
|
|
22
|
+
export type SourceMap = {
|
|
23
23
|
version: number;
|
|
24
24
|
mappings: string;
|
|
25
25
|
names: string[];
|
|
@@ -27,9 +27,9 @@ export interface SourceMap {
|
|
|
27
27
|
sourcesContent?: string[];
|
|
28
28
|
sourceRoot?: string;
|
|
29
29
|
file?: string;
|
|
30
|
-
}
|
|
30
|
+
};
|
|
31
31
|
/** A compiled module, and the map back to what was written. */
|
|
32
|
-
export
|
|
32
|
+
export type Compiled = {
|
|
33
33
|
code: string;
|
|
34
34
|
/**
|
|
35
35
|
* A source map, when one was asked for.
|
|
@@ -40,7 +40,7 @@ export interface Compiled {
|
|
|
40
40
|
* cannot, so the Vite plugin always asks.
|
|
41
41
|
*/
|
|
42
42
|
map: SourceMap | null;
|
|
43
|
-
}
|
|
43
|
+
};
|
|
44
44
|
/**
|
|
45
45
|
* Compiles one module, and maps it back.
|
|
46
46
|
*
|
package/dist/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAGA,OAAwB,EAAE,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE9E,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,MAAM,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAGA,OAAwB,EAAE,KAAK,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE9E,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gFAAgF;IAChF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAKlB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,+DAA+D;AAC/D,MAAM,MAAM,QAAQ,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,QAAQ,CAqBpF;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAE9E"}
|
|
@@ -178,7 +178,9 @@ function annotateComponent(path, state, options) {
|
|
|
178
178
|
const name = declaredName(path);
|
|
179
179
|
rewritePropsDestructuring(path, name, state);
|
|
180
180
|
if (options.strictReactivity !== false) {
|
|
181
|
-
|
|
181
|
+
const setupPath = path.get("arguments.0");
|
|
182
|
+
checkKeptReads(setupPath, name);
|
|
183
|
+
checkDecidedOnce(setupPath, name);
|
|
182
184
|
}
|
|
183
185
|
path.node.arguments = [
|
|
184
186
|
setup,
|
|
@@ -213,6 +215,113 @@ Move the read into the part, handler, effect or computed that should re-read it
|
|
|
213
215
|
}
|
|
214
216
|
});
|
|
215
217
|
}
|
|
218
|
+
function checkDecidedOnce(setup, name) {
|
|
219
|
+
const report = (at) => {
|
|
220
|
+
throw at.buildCodeFrameError(
|
|
221
|
+
`${name}: this view is chosen once, here, from a value that changes. A setup runs one time per instance, so the other branch will never appear.
|
|
222
|
+
|
|
223
|
+
Put the choice inside the markup, where it is a part that can run again:
|
|
224
|
+
|
|
225
|
+
return <>{open.value ? <A /> : <B />}</>;`
|
|
226
|
+
);
|
|
227
|
+
};
|
|
228
|
+
const check = (returned, at) => {
|
|
229
|
+
if (t.isConditionalExpression(returned)) {
|
|
230
|
+
if (!hasView(returned.consequent) && !hasView(returned.alternate)) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (readsSignal(returned.test)) {
|
|
234
|
+
report(at);
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (t.isLogicalExpression(returned) && returned.operator !== "??") {
|
|
239
|
+
if (!hasView(returned.right) && !hasView(returned.left)) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (readsSignal(returned.left)) {
|
|
243
|
+
report(at);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
const body = setup.get("body");
|
|
248
|
+
if (!body.isBlockStatement()) {
|
|
249
|
+
check(setup.node.body, body);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
body.traverse({
|
|
253
|
+
Function(nested) {
|
|
254
|
+
nested.skip();
|
|
255
|
+
},
|
|
256
|
+
ReturnStatement(statement) {
|
|
257
|
+
const returned = statement.node.argument;
|
|
258
|
+
if (returned !== null && returned !== void 0) {
|
|
259
|
+
check(returned, statement);
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
/**
|
|
263
|
+
* The same mistake spelled with a keyword, and the one that actually
|
|
264
|
+
* shipped: a route guard that returned `<Navigate />` early left the page
|
|
265
|
+
* it was meant to hide on the screen after a sign-out.
|
|
266
|
+
*/
|
|
267
|
+
IfStatement(statement) {
|
|
268
|
+
if (!readsSignal(statement.node.test)) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (returnsView(statement.node.consequent) || returnsView(statement.node.alternate)) {
|
|
272
|
+
report(statement.get("test"));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function returnsView(node) {
|
|
278
|
+
if (node === null || node === void 0) {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
if (t.isReturnStatement(node)) {
|
|
282
|
+
return node.argument !== null && node.argument !== void 0 && hasView(node.argument);
|
|
283
|
+
}
|
|
284
|
+
if (t.isBlockStatement(node)) {
|
|
285
|
+
return node.body.some((inner) => returnsView(inner));
|
|
286
|
+
}
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
function hasView(node) {
|
|
290
|
+
if (t.isConditionalExpression(node)) {
|
|
291
|
+
return hasView(node.consequent) || hasView(node.alternate);
|
|
292
|
+
}
|
|
293
|
+
return t.isJSXElement(node) || t.isJSXFragment(node);
|
|
294
|
+
}
|
|
295
|
+
function readsSignal(node) {
|
|
296
|
+
let found = false;
|
|
297
|
+
const walk = (current) => {
|
|
298
|
+
if (current === null || current === void 0 || found) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (t.isMemberExpression(current)) {
|
|
302
|
+
if (!current.computed && t.isIdentifier(current.property, { name: "value" })) {
|
|
303
|
+
found = true;
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
walk(current.object);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (t.isUnaryExpression(current)) {
|
|
310
|
+
walk(current.argument);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (t.isBinaryExpression(current) || t.isLogicalExpression(current)) {
|
|
314
|
+
walk(current.left);
|
|
315
|
+
walk(current.right);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (t.isConditionalExpression(current)) {
|
|
319
|
+
walk(current.test);
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
walk(node);
|
|
323
|
+
return found;
|
|
324
|
+
}
|
|
216
325
|
function readsOnly(node, propsName) {
|
|
217
326
|
let read = false;
|
|
218
327
|
const walk = (current) => {
|
package/dist/index.js
CHANGED
package/dist/transform.d.ts
CHANGED
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import type { PluginObject } from '@babel/core';
|
|
15
15
|
import * as t from '@babel/types';
|
|
16
|
-
|
|
16
|
+
type FirsthandState = {
|
|
17
17
|
imports: Map<string, t.Identifier>;
|
|
18
18
|
templates: t.VariableDeclarator[];
|
|
19
19
|
counter: number;
|
|
20
20
|
moduleId: string;
|
|
21
|
-
}
|
|
21
|
+
};
|
|
22
22
|
declare module '@babel/core' {
|
|
23
23
|
interface PluginPass {
|
|
24
24
|
firsthand: FirsthandState;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
export
|
|
27
|
+
export type FirsthandPluginOptions = {
|
|
28
28
|
/** Package name used when hashing stable component ids (ADR-0004). */
|
|
29
29
|
packageName?: string;
|
|
30
30
|
/**
|
|
@@ -49,7 +49,7 @@ export interface FirsthandPluginOptions {
|
|
|
49
49
|
* production build emits nothing.
|
|
50
50
|
*/
|
|
51
51
|
devtools?: boolean;
|
|
52
|
-
}
|
|
52
|
+
};
|
|
53
53
|
export default function firsthandPlugin(_api: unknown, options?: FirsthandPluginOptions): PluginObject;
|
|
54
54
|
export {};
|
|
55
55
|
//# sourceMappingURL=transform.d.ts.map
|
package/dist/transform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAelC,
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAelC,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC;IACnC,SAAS,EAAE,CAAC,CAAC,kBAAkB,EAAE,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,OAAO,QAAQ,aAAa,CAAC;IAC3B,UAAU,UAAU;QAClB,SAAS,EAAE,cAAc,CAAC;KAC3B;CACF;AAUD,MAAM,MAAM,sBAAsB,GAAG;IACnC,sEAAsE;IACtE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,eAAe,CACrC,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,sBAA2B,GACnC,YAAY,CAsDd"}
|
package/dist/vite.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type SourceMap } from './api.js';
|
|
2
2
|
import type { FirsthandPluginOptions } from './transform.js';
|
|
3
3
|
/** Minimal shape of the Vite plugin contract, so the package needs no Vite dependency. */
|
|
4
|
-
export
|
|
4
|
+
export type VitePluginLike = {
|
|
5
5
|
name: string;
|
|
6
6
|
enforce: 'pre';
|
|
7
7
|
configResolved(config: {
|
|
@@ -11,7 +11,7 @@ export interface VitePluginLike {
|
|
|
11
11
|
code: string;
|
|
12
12
|
map: SourceMap | null;
|
|
13
13
|
} | null;
|
|
14
|
-
}
|
|
14
|
+
};
|
|
15
15
|
/**
|
|
16
16
|
* Vite/Rollup plugin.
|
|
17
17
|
*
|
package/dist/vite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,0FAA0F;AAC1F,MAAM,
|
|
1
|
+
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7D,0FAA0F;AAC1F,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,KAAK,CAAC;IACf,cAAc,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAC;CACrF,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,sBAA2B,GAAG,cAAc,CA0B9E"}
|
package/dist/vite.js
CHANGED
package/package.json
CHANGED