@ilha/router 0.11.0 → 0.11.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/oxlint.cjs +69 -25
- package/package.json +3 -3
package/oxlint.cjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
const PRIMITIVES = new Set(["atom", "
|
|
2
|
-
|
|
3
|
-
const INSTRUCTIONS = new Set(["when", "watch", "wait"]);
|
|
1
|
+
const PRIMITIVES = new Set(["atom", "watch", "when"]);
|
|
2
|
+
const INSTRUCTIONS = new Set(["when"]);
|
|
4
3
|
const CONDITIONAL = new Set([
|
|
5
4
|
"IfStatement",
|
|
6
5
|
"ForStatement",
|
|
@@ -38,8 +37,48 @@ function ancestorsOf(context, node) {
|
|
|
38
37
|
return [];
|
|
39
38
|
}
|
|
40
39
|
|
|
41
|
-
function
|
|
42
|
-
|
|
40
|
+
function blockBody(node) {
|
|
41
|
+
if (node.type === "BlockStatement") return node.body;
|
|
42
|
+
if (
|
|
43
|
+
node.type === "FunctionDeclaration" ||
|
|
44
|
+
node.type === "FunctionExpression" ||
|
|
45
|
+
node.type === "ArrowFunctionExpression"
|
|
46
|
+
) {
|
|
47
|
+
const body = node.body;
|
|
48
|
+
if (body?.type === "BlockStatement") return body.body;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function bindingInitType(name, ancestors) {
|
|
54
|
+
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
55
|
+
const a = ancestors[i];
|
|
56
|
+
if (a.type === "VariableDeclarator" && a.id?.type === "Identifier" && a.id.name === name) {
|
|
57
|
+
return a.init?.type ?? "none";
|
|
58
|
+
}
|
|
59
|
+
if (a.type === "FunctionDeclaration" && a.id?.name === name) {
|
|
60
|
+
return "FunctionDeclaration";
|
|
61
|
+
}
|
|
62
|
+
const stmts = blockBody(a);
|
|
63
|
+
if (stmts) {
|
|
64
|
+
for (const stmt of stmts) {
|
|
65
|
+
if (stmt.type !== "VariableDeclaration") continue;
|
|
66
|
+
for (const decl of stmt.declarations) {
|
|
67
|
+
if (decl.id?.type === "Identifier" && decl.id.name === name) {
|
|
68
|
+
return decl.init?.type ?? "none";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function isFunctionBinding(name, ancestors, moduleFns) {
|
|
78
|
+
const local = bindingInitType(name, ancestors);
|
|
79
|
+
if (local === "FunctionDeclaration") return true;
|
|
80
|
+
if (local !== null) return FN_TYPES.has(local);
|
|
81
|
+
return moduleFns.has(name);
|
|
43
82
|
}
|
|
44
83
|
|
|
45
84
|
function enclosingFunctions(ancestors) {
|
|
@@ -49,7 +88,7 @@ function enclosingFunctions(ancestors) {
|
|
|
49
88
|
const noConditionalPrimitive = {
|
|
50
89
|
meta: {
|
|
51
90
|
type: "problem",
|
|
52
|
-
docs: { description: "Disallow atom/
|
|
91
|
+
docs: { description: "Disallow atom/watch/when inside conditionals or loops" },
|
|
53
92
|
messages: {
|
|
54
93
|
conditional:
|
|
55
94
|
"Do not call {{name}}() inside a condition or loop. Primitive registration order must be stable — put the branch inside the primitive or the view.",
|
|
@@ -83,7 +122,7 @@ const noPrimitiveOutsideComponent = {
|
|
|
83
122
|
meta: {
|
|
84
123
|
type: "problem",
|
|
85
124
|
docs: {
|
|
86
|
-
description: "Call atom/
|
|
125
|
+
description: "Call atom/watch/when inside a component, never at module top level",
|
|
87
126
|
},
|
|
88
127
|
messages: {
|
|
89
128
|
outside:
|
|
@@ -112,7 +151,7 @@ const noPrimitiveOutsideComponent = {
|
|
|
112
151
|
const noInstructionOutsideGenerator = {
|
|
113
152
|
meta: {
|
|
114
153
|
type: "problem",
|
|
115
|
-
docs: { description: "Use when
|
|
154
|
+
docs: { description: "Use when only inside a generator, with yield*" },
|
|
116
155
|
messages: {
|
|
117
156
|
notGenerator:
|
|
118
157
|
"{{name}}() returns an instruction that only a generator frame can run. Make the enclosing component a generator and yield* it.",
|
|
@@ -186,18 +225,20 @@ const preferLowercaseEvents = {
|
|
|
186
225
|
const functionInAtom = {
|
|
187
226
|
meta: {
|
|
188
227
|
type: "problem",
|
|
189
|
-
docs: {
|
|
228
|
+
docs: {
|
|
229
|
+
description:
|
|
230
|
+
"atom(fn) and atom(() => …) are invalid — use atom.lazy, Atom.map, or Atom.transform",
|
|
231
|
+
},
|
|
190
232
|
messages: {
|
|
191
|
-
init: "atom({{name}})
|
|
192
|
-
|
|
233
|
+
init: "atom({{name}}) is not valid. Use atom.lazy(() => {{name}}) to store a function value.",
|
|
234
|
+
derived:
|
|
235
|
+
"atom(() => …) is not supported. Use atom(Atom.map(...)) or atom(Atom.transform(...)) for derived values, or atom.lazy() for one-time init.",
|
|
193
236
|
},
|
|
194
237
|
schema: [],
|
|
195
238
|
},
|
|
196
239
|
create(context) {
|
|
197
240
|
const b = bindings();
|
|
198
241
|
const fns = new Set();
|
|
199
|
-
const atoms = new Set();
|
|
200
|
-
const computed = new Set();
|
|
201
242
|
return {
|
|
202
243
|
ImportDeclaration(node) {
|
|
203
244
|
takeImport(b, node);
|
|
@@ -215,23 +256,26 @@ const functionInAtom = {
|
|
|
215
256
|
fns.add(node.id.name);
|
|
216
257
|
}
|
|
217
258
|
if (!init || primitiveName(init, b) !== "atom") return;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
259
|
+
const arg = init.arguments[0];
|
|
260
|
+
if (arg && FN_TYPES.has(arg.type)) {
|
|
261
|
+
context.report({ node: arg, messageId: "derived" });
|
|
262
|
+
}
|
|
263
|
+
if (
|
|
264
|
+
arg?.type === "Identifier" &&
|
|
265
|
+
isFunctionBinding(arg.name, ancestorsOf(context, arg), fns)
|
|
266
|
+
) {
|
|
267
|
+
context.report({ node: arg, messageId: "init", data: { name: arg.name } });
|
|
268
|
+
}
|
|
221
269
|
},
|
|
222
270
|
CallExpression(node) {
|
|
223
271
|
if (node.arguments.length === 0) return;
|
|
224
272
|
const arg = node.arguments[0];
|
|
225
|
-
if (arg.type !== "Identifier"
|
|
226
|
-
if (
|
|
273
|
+
if (arg.type !== "Identifier") return;
|
|
274
|
+
if (
|
|
275
|
+
primitiveName(node, b) === "atom" &&
|
|
276
|
+
isFunctionBinding(arg.name, ancestorsOf(context, arg), fns)
|
|
277
|
+
) {
|
|
227
278
|
context.report({ node: arg, messageId: "init", data: { name: arg.name } });
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
const setter = calleeName(node.callee);
|
|
231
|
-
// set(fn) on a computed atom never makes sense; on a writable atom it
|
|
232
|
-
// is the classic "I meant to store this function" mistake.
|
|
233
|
-
if (setter && atoms.has(setter) && computed.has(setter)) {
|
|
234
|
-
context.report({ node: arg, messageId: "set", data: { setter, name: arg.name } });
|
|
235
279
|
}
|
|
236
280
|
},
|
|
237
281
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ilha/router",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "A tiny SPA router for Ilha",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"frontend",
|
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
"unplugin": "3.3.0"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"ilha": "0.14.
|
|
76
|
+
"ilha": "0.14.1",
|
|
77
77
|
"vite": "^8.2.2"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
|
-
"ilha": ">=0.14.
|
|
80
|
+
"ilha": ">=0.14.1"
|
|
81
81
|
}
|
|
82
82
|
}
|