@typeonce/oxlint-plugin-effect-machine 0.26.2 → 0.27.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.
Files changed (55) hide show
  1. package/README.md +151 -9
  2. package/dist/index.d.ts +3 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +6 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/internal/ambient.d.ts +6 -0
  7. package/dist/internal/ambient.d.ts.map +1 -0
  8. package/dist/internal/ambient.js +118 -0
  9. package/dist/internal/ambient.js.map +1 -0
  10. package/dist/internal/ast.d.ts +7 -0
  11. package/dist/internal/ast.d.ts.map +1 -0
  12. package/dist/internal/ast.js +62 -0
  13. package/dist/internal/ast.js.map +1 -0
  14. package/dist/internal/imports.d.ts +1 -0
  15. package/dist/internal/imports.d.ts.map +1 -1
  16. package/dist/internal/imports.js +19 -9
  17. package/dist/internal/imports.js.map +1 -1
  18. package/dist/internal/planning.d.ts +3 -0
  19. package/dist/internal/planning.d.ts.map +1 -1
  20. package/dist/internal/planning.js +54 -7
  21. package/dist/internal/planning.js.map +1 -1
  22. package/dist/internal/rules/noAsyncPlanningCallback.d.ts.map +1 -1
  23. package/dist/internal/rules/noAsyncPlanningCallback.js +18 -3
  24. package/dist/internal/rules/noAsyncPlanningCallback.js.map +1 -1
  25. package/dist/internal/rules/noBrowserApiInPlanning.d.ts +3 -0
  26. package/dist/internal/rules/noBrowserApiInPlanning.d.ts.map +1 -0
  27. package/dist/internal/rules/noBrowserApiInPlanning.js +54 -0
  28. package/dist/internal/rules/noBrowserApiInPlanning.js.map +1 -0
  29. package/dist/internal/rules/noConflictingInvocationIdentity.d.ts +3 -0
  30. package/dist/internal/rules/noConflictingInvocationIdentity.d.ts.map +1 -0
  31. package/dist/internal/rules/noConflictingInvocationIdentity.js +289 -0
  32. package/dist/internal/rules/noConflictingInvocationIdentity.js.map +1 -0
  33. package/dist/internal/rules/noNondeterministicPlanning.d.ts +3 -0
  34. package/dist/internal/rules/noNondeterministicPlanning.d.ts.map +1 -0
  35. package/dist/internal/rules/noNondeterministicPlanning.js +33 -0
  36. package/dist/internal/rules/noNondeterministicPlanning.js.map +1 -0
  37. package/dist/internal/rules/noRedundantResolve.d.ts.map +1 -1
  38. package/dist/internal/rules/noRedundantResolve.js +41 -15
  39. package/dist/internal/rules/noRedundantResolve.js.map +1 -1
  40. package/dist/recommended.d.ts +3 -0
  41. package/dist/recommended.d.ts.map +1 -1
  42. package/dist/recommended.js +3 -0
  43. package/dist/recommended.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/index.ts +6 -0
  46. package/src/internal/ambient.ts +134 -0
  47. package/src/internal/ast.ts +83 -0
  48. package/src/internal/imports.ts +27 -8
  49. package/src/internal/planning.ts +69 -7
  50. package/src/internal/rules/noAsyncPlanningCallback.ts +21 -4
  51. package/src/internal/rules/noBrowserApiInPlanning.ts +57 -0
  52. package/src/internal/rules/noConflictingInvocationIdentity.ts +343 -0
  53. package/src/internal/rules/noNondeterministicPlanning.ts +39 -0
  54. package/src/internal/rules/noRedundantResolve.ts +48 -16
  55. package/src/recommended.ts +3 -0
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Effect Machine Oxlint plugin
2
2
 
3
3
  `@typeonce/oxlint-plugin-effect-machine` checks Effect Machine definitions for
4
- redundant resolvers, asynchronous planning, and one-use intermediate machine
5
- definitions.
4
+ invalid invocation identities, impure planning, redundant resolvers, and
5
+ one-use intermediate machine definitions.
6
6
 
7
7
  The plugin uses Oxlint's JavaScript plugin interface. Custom JavaScript plugins
8
8
  are currently alpha in Oxlint, so keep Oxlint and this package on versions that
@@ -40,16 +40,24 @@ JSON configurations can list the same rules directly:
40
40
  "jsPlugins": ["@typeonce/oxlint-plugin-effect-machine"],
41
41
  "rules": {
42
42
  "effect-machine/no-async-planning-callback": "error",
43
+ "effect-machine/no-browser-api-in-planning": "error",
44
+ "effect-machine/no-conflicting-invocation-identity": "error",
45
+ "effect-machine/no-nondeterministic-planning": "error",
43
46
  "effect-machine/no-redundant-resolve": "error",
44
47
  "effect-machine/prefer-inline-handle": "error"
45
48
  }
46
49
  }
47
50
  ```
48
51
 
49
- The rules are syntax-based. They recognize `Machine.make(...)`, direct chained
50
- `.handle(...)` calls, and `.handle(...)` calls on definitions declared in the
51
- same module. They do not resolve a machine definition imported from another
52
- module.
52
+ The rules are syntax-based and deliberately conservative. They recognize
53
+ `Machine.make(...)`, direct chained `.handle(...)` calls, and `.handle(...)`
54
+ calls on definitions declared in the same module. They do not resolve an
55
+ imported machine definition or guess the result of an arbitrary function call.
56
+
57
+ Planning checks cover initial, transition, resolution, lifecycle, choice,
58
+ initialization, output, history fallback, and invocation declaration
59
+ callbacks. A nested invocation source is state-owned work and is not treated
60
+ as planning.
53
61
 
54
62
  ## Rules
55
63
 
@@ -72,11 +80,145 @@ const handlers = {
72
80
  The fixer does not run when the resolver has options, comments, construction
73
81
  input, or any other work.
74
82
 
83
+ Resolver-only reentry uses `.reenter()`:
84
+
85
+ ```ts
86
+ // Before
87
+ to.local.Ready().resolve(({ target }) => target.from(), { reenter: true })
88
+
89
+ // After `oxlint --fix`
90
+ to.local.Ready().reenter()
91
+ ```
92
+
93
+ An empty `to.none.resolve(() => {})` is similarly reduced to `to.none`.
94
+
75
95
  ### `effect-machine/no-async-planning-callback`
76
96
 
77
- Rejects asynchronous transition, lifecycle, initial, choice, entry, exit, and
78
- invocation-planning callbacks. A machine plans synchronously. Put asynchronous
79
- work in state-owned `invoke` sources instead.
97
+ Rejects `async` planning callbacks and direct Promise, fetch, timer, or
98
+ scheduling operations during planning. A machine plans synchronously and has
99
+ no lifetime in which to own work started by a transition.
100
+
101
+ ```ts
102
+ // Incorrect: the transition starts unowned work.
103
+ const incorrect = {
104
+ Submit: (to) => {
105
+ fetch("/orders", { method: "POST" })
106
+ return to.full.Complete()
107
+ }
108
+ }
109
+
110
+ // Correct: the state owns and cancels the work.
111
+ const correct = {
112
+ Submitting: {
113
+ invoke: (from) =>
114
+ from.effect("submit-order", () => submitOrder())
115
+ .onDone((to) => to.full.Complete())
116
+ .onFailure((to) => to.full.Failed())
117
+ }
118
+ }
119
+ ```
120
+
121
+ The rule only reports known unshadowed globals. Calls inside the source passed
122
+ to `from.effect`, `from.stream`, or another invocation builder remain valid.
123
+
124
+ ### `effect-machine/no-conflicting-invocation-identity`
125
+
126
+ Requires every invocation declared by one state to have a unique lifecycle ID
127
+ and every concurrently owned logic or child process to have a unique runtime
128
+ address.
129
+
130
+ ```ts
131
+ // Incorrect: both outcomes use the "load" lifecycle ID.
132
+ const incorrect = {
133
+ invoke: (from) => [
134
+ from.effect("load", loadAccount),
135
+ from.timer("load", "10 seconds")
136
+ ]
137
+ }
138
+
139
+ // Correct
140
+ const correct = {
141
+ invoke: (from) => [
142
+ from.effect("load-account", loadAccount),
143
+ from.timer("load-timeout", "10 seconds")
144
+ ]
145
+ }
146
+ ```
147
+
148
+ Duplicate lifecycle IDs make outcome routing ambiguous. Duplicate active
149
+ addresses fail at runtime. If two operations must run sequentially, put them
150
+ in separate states and transition from the first invocation's outcome instead
151
+ of relying on completion timing.
152
+
153
+ The rule compares only identities it can prove equal, such as literals, the
154
+ same binding, static `Machine.childAddress(...)` values, and local
155
+ `Machine.child(...)` descriptors. It checks one state's invocation declaration
156
+ at a time and does not guess whether separate states can be active together.
157
+
158
+ ### `effect-machine/no-browser-api-in-planning`
159
+
160
+ Rejects direct access to stateful browser APIs such as `document`,
161
+ `localStorage`, `navigator`, `location`, workers, and browser event APIs during
162
+ planning.
163
+
164
+ ```ts
165
+ // Incorrect: transition planning reads ambient storage.
166
+ const incorrect = {
167
+ Restore: (to) =>
168
+ localStorage.getItem("draft") === null
169
+ ? to.full.Empty()
170
+ : to.full.Editing()
171
+ }
172
+
173
+ // Correct: state-owned work reads storage and reports an outcome.
174
+ const correct = {
175
+ Restoring: {
176
+ invoke: (from) =>
177
+ from.effect("restore-draft", () => restoreDraft())
178
+ .onDone((to) => to.full.Editing())
179
+ .onFailure((to) => to.full.Empty())
180
+ }
181
+ }
182
+ ```
183
+
184
+ If browser work affects the workflow, move it into a state-owned invocation.
185
+ If it only focuses, measures, or renders UI, keep it in the UI adapter. Pure
186
+ data utilities such as `URL`, `URLSearchParams`, `TextEncoder`, and
187
+ `structuredClone` are not reported.
188
+
189
+ ### `effect-machine/no-nondeterministic-planning`
190
+
191
+ Rejects direct reads of ambient time or randomness during planning, including
192
+ `Date.now()`, zero-argument `new Date()`, `Math.random()`, crypto randomness,
193
+ performance clocks, `Temporal.Now`, and process clocks.
194
+
195
+ ```ts
196
+ // Incorrect: the same event and snapshot can select different results.
197
+ const incorrect = {
198
+ Check: (to) =>
199
+ Date.now() >= deadline
200
+ ? to.full.Expired()
201
+ : to.none
202
+ }
203
+
204
+ // Correct: receive the external fact as part of the event protocol.
205
+ const correct = {
206
+ Check: (to) =>
207
+ to.branches({
208
+ expired: { target: to.full.Expired() },
209
+ current: { target: to.full.Current() }
210
+ }).resolve(({ event, select }) =>
211
+ event.now >= event.deadline
212
+ ? select.expired.from()
213
+ : select.current.from()
214
+ )
215
+ }
216
+ ```
217
+
218
+ Pass the value through machine input or an event when it is already known. If
219
+ the machine must obtain it, produce it in a state-owned invocation and
220
+ transition from the invocation outcome. Deterministic operations such as
221
+ `new Date(event.timestamp)` and `Date.parse(state.createdAt)` remain valid.
80
222
 
81
223
  ### `effect-machine/prefer-inline-handle`
82
224
 
package/dist/index.d.ts CHANGED
@@ -4,6 +4,9 @@ declare const plugin: {
4
4
  };
5
5
  rules: {
6
6
  "no-async-planning-callback": import("@oxlint/plugins").Rule;
7
+ "no-browser-api-in-planning": import("@oxlint/plugins").Rule;
8
+ "no-conflicting-invocation-identity": import("@oxlint/plugins").Rule;
9
+ "no-nondeterministic-planning": import("@oxlint/plugins").Rule;
7
10
  "no-redundant-resolve": import("@oxlint/plugins").Rule;
8
11
  "prefer-inline-handle": import("@oxlint/plugins").Rule;
9
12
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,MAAM;;;;;;;;;CASM,CAAA;AAElB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,MAAM;;;;;;;;;;;;CAYM,CAAA;AAElB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,eAAe,MAAM,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import { noAsyncPlanningCallback } from "./internal/rules/noAsyncPlanningCallback.js";
2
+ import { noBrowserApiInPlanning } from "./internal/rules/noBrowserApiInPlanning.js";
3
+ import { noConflictingInvocationIdentity } from "./internal/rules/noConflictingInvocationIdentity.js";
4
+ import { noNondeterministicPlanning } from "./internal/rules/noNondeterministicPlanning.js";
2
5
  import { noRedundantResolve } from "./internal/rules/noRedundantResolve.js";
3
6
  import { preferInlineHandle } from "./internal/rules/preferInlineHandle.js";
4
7
  const plugin = {
@@ -7,6 +10,9 @@ const plugin = {
7
10
  },
8
11
  rules: {
9
12
  "no-async-planning-callback": noAsyncPlanningCallback,
13
+ "no-browser-api-in-planning": noBrowserApiInPlanning,
14
+ "no-conflicting-invocation-identity": noConflictingInvocationIdentity,
15
+ "no-nondeterministic-planning": noNondeterministicPlanning,
10
16
  "no-redundant-resolve": noRedundantResolve,
11
17
  "prefer-inline-handle": preferInlineHandle
12
18
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,6CAA6C,CAAA;AACrF,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAA;AAE3E,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,gBAAgB;KACvB;IACD,KAAK,EAAE;QACL,4BAA4B,EAAE,uBAAuB;QACrD,sBAAsB,EAAE,kBAAkB;QAC1C,sBAAsB,EAAE,kBAAkB;KAC3C;CACe,CAAA;AAElB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,6CAA6C,CAAA;AACrF,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAA;AACnF,OAAO,EAAE,+BAA+B,EAAE,MAAM,qDAAqD,CAAA;AACrG,OAAO,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAA;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAA;AAE3E,MAAM,MAAM,GAAG;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,gBAAgB;KACvB;IACD,KAAK,EAAE;QACL,4BAA4B,EAAE,uBAAuB;QACrD,4BAA4B,EAAE,sBAAsB;QACpD,oCAAoC,EAAE,+BAA+B;QACrE,8BAA8B,EAAE,0BAA0B;QAC1D,sBAAsB,EAAE,kBAAkB;QAC1C,sBAAsB,EAAE,kBAAkB;KAC3C;CACe,CAAA;AAElB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,eAAe,MAAM,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { Context, ESTree } from "@oxlint/plugins";
2
+ export declare const asyncOperation: (context: Context, node: ESTree.CallExpression | ESTree.NewExpression) => string | undefined;
3
+ export declare const nondeterministicOperation: (context: Context, node: ESTree.CallExpression | ESTree.NewExpression) => string | undefined;
4
+ export declare const nondeterministicProperty: (context: Context, node: ESTree.MemberExpression) => string | undefined;
5
+ export declare const browserApi: (context: Context, node: ESTree.Expression) => string | undefined;
6
+ //# sourceMappingURL=ambient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ambient.d.ts","sourceRoot":"","sources":["../../src/internal/ambient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAuBtD,eAAO,MAAM,cAAc,GACzB,SAAS,OAAO,EAChB,MAAM,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,aAAa,KACjD,MAAM,GAAG,SAaX,CAAA;AAED,eAAO,MAAM,yBAAyB,GACpC,SAAS,OAAO,EAChB,MAAM,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,aAAa,KACjD,MAAM,GAAG,SA6BX,CAAA;AAED,eAAO,MAAM,wBAAwB,GACnC,SAAS,OAAO,EAChB,MAAM,MAAM,CAAC,gBAAgB,KAC5B,MAAM,GAAG,SAKX,CAAA;AAwCD,eAAO,MAAM,UAAU,GACrB,SAAS,OAAO,EAChB,MAAM,MAAM,CAAC,UAAU,KACtB,MAAM,GAAG,SAOX,CAAA"}
@@ -0,0 +1,118 @@
1
+ import { canonicalGlobalPath } from "./ast.js";
2
+ const scheduledFunctions = new Set([
3
+ "fetch",
4
+ "queueMicrotask",
5
+ "requestAnimationFrame",
6
+ "requestIdleCallback",
7
+ "setImmediate",
8
+ "setInterval",
9
+ "setTimeout"
10
+ ]);
11
+ const promiseMethods = new Set([
12
+ "all",
13
+ "allSettled",
14
+ "any",
15
+ "race",
16
+ "reject",
17
+ "resolve",
18
+ "try"
19
+ ]);
20
+ export const asyncOperation = (context, node) => {
21
+ const path = canonicalGlobalPath(context, node.callee);
22
+ if (path === undefined)
23
+ return undefined;
24
+ if (node.type === "NewExpression") {
25
+ return path.length === 1 && path[0] === "Promise" ? "new Promise(...)" : undefined;
26
+ }
27
+ if (path.length === 1 && scheduledFunctions.has(path[0]))
28
+ return `${path[0]}(...)`;
29
+ if (path.length === 2 && path[0] === "Promise" && promiseMethods.has(path[1])) {
30
+ return `Promise.${path[1]}(...)`;
31
+ }
32
+ return path.length === 2 && path[0] === "process" && path[1] === "nextTick"
33
+ ? "process.nextTick(...)"
34
+ : undefined;
35
+ };
36
+ export const nondeterministicOperation = (context, node) => {
37
+ const path = canonicalGlobalPath(context, node.callee);
38
+ if (path === undefined)
39
+ return undefined;
40
+ if (node.type === "NewExpression") {
41
+ return path.length === 1 && path[0] === "Date" && node.arguments.length === 0
42
+ ? "new Date()"
43
+ : undefined;
44
+ }
45
+ if (path.length === 1 && path[0] === "Date")
46
+ return "Date()";
47
+ if (path.length === 2 && path[0] === "Date" && path[1] === "now")
48
+ return "Date.now()";
49
+ if (path.length === 2 && path[0] === "Math" && path[1] === "random")
50
+ return "Math.random()";
51
+ if (path.length === 2 &&
52
+ path[0] === "crypto" &&
53
+ (path[1] === "getRandomValues" || path[1] === "randomUUID"))
54
+ return `crypto.${path[1]}(...)`;
55
+ if (path.length === 2 && path[0] === "performance" && path[1] === "now") {
56
+ return "performance.now()";
57
+ }
58
+ if (path.length >= 3 && path[0] === "Temporal" && path[1] === "Now") {
59
+ return `${path.join(".")}()`;
60
+ }
61
+ if (path[0] === "process" &&
62
+ (path.join(".") === "process.hrtime" ||
63
+ path.join(".") === "process.hrtime.bigint" ||
64
+ path.join(".") === "process.uptime"))
65
+ return `${path.join(".")}()`;
66
+ return undefined;
67
+ };
68
+ export const nondeterministicProperty = (context, node) => {
69
+ const path = canonicalGlobalPath(context, node);
70
+ return path?.length === 2 && path[0] === "performance" && path[1] === "timeOrigin"
71
+ ? "performance.timeOrigin"
72
+ : undefined;
73
+ };
74
+ const browserRoots = new Set([
75
+ "caches",
76
+ "cookieStore",
77
+ "document",
78
+ "history",
79
+ "indexedDB",
80
+ "localStorage",
81
+ "location",
82
+ "navigator",
83
+ "screen",
84
+ "self",
85
+ "sessionStorage",
86
+ "visualViewport",
87
+ "window"
88
+ ]);
89
+ const browserFunctions = new Set([
90
+ "addEventListener",
91
+ "alert",
92
+ "confirm",
93
+ "dispatchEvent",
94
+ "getComputedStyle",
95
+ "matchMedia",
96
+ "open",
97
+ "postMessage",
98
+ "prompt",
99
+ "removeEventListener"
100
+ ]);
101
+ const browserConstructors = new Set([
102
+ "BroadcastChannel",
103
+ "EventSource",
104
+ "SharedWorker",
105
+ "WebSocket",
106
+ "Worker",
107
+ "XMLHttpRequest"
108
+ ]);
109
+ export const browserApi = (context, node) => {
110
+ const path = canonicalGlobalPath(context, node);
111
+ if (path === undefined || path.length === 0)
112
+ return undefined;
113
+ if (browserRoots.has(path[0]) || browserFunctions.has(path[0]) || browserConstructors.has(path[0])) {
114
+ return path.join(".");
115
+ }
116
+ return undefined;
117
+ };
118
+ //# sourceMappingURL=ambient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ambient.js","sourceRoot":"","sources":["../../src/internal/ambient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Context, ESTree, Variable } from "@oxlint/plugins";
2
+ export declare const unwrapExpression: (node: ESTree.Expression) => ESTree.Expression;
3
+ export declare const resolvedVariable: (context: Context, node: ESTree.IdentifierReference) => Variable | undefined;
4
+ export declare const isUnshadowedGlobal: (context: Context, node: ESTree.Expression, name: string) => node is ESTree.IdentifierReference;
5
+ export declare const globalPath: (context: Context, node: ESTree.Expression) => ReadonlyArray<string> | undefined;
6
+ export declare const canonicalGlobalPath: (context: Context, node: ESTree.Expression) => ReadonlyArray<string> | undefined;
7
+ //# sourceMappingURL=ast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/internal/ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAS,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAGvE,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,CAAC,UAAU,KAAG,MAAM,CAAC,UAWjE,CAAA;AASD,eAAO,MAAM,gBAAgB,GAC3B,SAAS,OAAO,EAChB,MAAM,MAAM,CAAC,mBAAmB,KAC/B,QAAQ,GAAG,SAQb,CAAA;AAED,eAAO,MAAM,kBAAkB,GAC7B,SAAS,OAAO,EAChB,MAAM,MAAM,CAAC,UAAU,EACvB,MAAM,MAAM,KACX,IAAI,IAAI,MAAM,CAAC,mBAYjB,CAAA;AAED,eAAO,MAAM,UAAU,GACrB,SAAS,OAAO,EAChB,MAAM,MAAM,CAAC,UAAU,KACtB,aAAa,CAAC,MAAM,CAAC,GAAG,SAa1B,CAAA;AAID,eAAO,MAAM,mBAAmB,GAC9B,SAAS,OAAO,EAChB,MAAM,MAAM,CAAC,UAAU,KACtB,aAAa,CAAC,MAAM,CAAC,GAAG,SAK1B,CAAA"}
@@ -0,0 +1,62 @@
1
+ import { staticMemberName } from "./imports.js";
2
+ export const unwrapExpression = (node) => {
3
+ let current = node;
4
+ while (current.type === "ChainExpression" ||
5
+ current.type === "ParenthesizedExpression" ||
6
+ current.type === "TSAsExpression" ||
7
+ current.type === "TSNonNullExpression" ||
8
+ current.type === "TSSatisfiesExpression" ||
9
+ current.type === "TSTypeAssertion")
10
+ current = current.expression;
11
+ return current;
12
+ };
13
+ const referenceIn = (scope, node) => scope.references.find((reference) => reference.identifier === node) ??
14
+ scope.through.find((reference) => reference.identifier === node);
15
+ export const resolvedVariable = (context, node) => {
16
+ let scope = context.sourceCode.getScope(node);
17
+ while (scope !== null) {
18
+ const reference = referenceIn(scope, node);
19
+ if (reference !== undefined)
20
+ return reference.resolved ?? undefined;
21
+ scope = scope.upper;
22
+ }
23
+ return undefined;
24
+ };
25
+ export const isUnshadowedGlobal = (context, node, name) => {
26
+ const expression = unwrapExpression(node);
27
+ if (expression.type !== "Identifier" || expression.name !== name)
28
+ return false;
29
+ if (context.sourceCode.isGlobalReference(expression))
30
+ return true;
31
+ let scope = context.sourceCode.getScope(expression);
32
+ while (scope !== null) {
33
+ const reference = referenceIn(scope, expression);
34
+ if (reference !== undefined)
35
+ return reference.resolved === null;
36
+ scope = scope.upper;
37
+ }
38
+ return false;
39
+ };
40
+ export const globalPath = (context, node) => {
41
+ const expression = unwrapExpression(node);
42
+ if (expression.type === "Identifier") {
43
+ return isUnshadowedGlobal(context, expression, expression.name)
44
+ ? [expression.name]
45
+ : undefined;
46
+ }
47
+ if (expression.type !== "MemberExpression")
48
+ return undefined;
49
+ const member = staticMemberName(expression);
50
+ if (member === undefined)
51
+ return undefined;
52
+ const owner = globalPath(context, expression.object);
53
+ return owner === undefined ? undefined : [...owner, member];
54
+ };
55
+ const ambientQualifiers = new Set(["globalThis", "self", "window"]);
56
+ export const canonicalGlobalPath = (context, node) => {
57
+ const path = globalPath(context, node);
58
+ return path !== undefined && path.length > 1 && ambientQualifiers.has(path[0])
59
+ ? path.slice(1)
60
+ : path;
61
+ };
62
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/internal/ast.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ export declare const makeMachineBindings: () => MachineBindings;
8
8
  export declare const recordMachineImport: (bindings: MachineBindings, node: ESTree.ImportDeclaration) => void;
9
9
  export declare const hasMachineImport: (bindings: MachineBindings) => boolean;
10
10
  export declare const staticMemberName: (node: ESTree.Node) => string | undefined;
11
+ export declare const isMachineMemberCall: (node: ESTree.Node, member: string, bindings: MachineBindings) => node is ESTree.CallExpression;
11
12
  export declare const isMachineMakeCall: (node: ESTree.CallExpression, bindings: MachineBindings) => boolean;
12
13
  export declare const recordMachineDefinition: (bindings: MachineBindings, node: ESTree.VariableDeclarator) => void;
13
14
  export declare const isMachineHandleCall: (node: ESTree.CallExpression, bindings: MachineBindings) => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/internal/imports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAI7C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC7B,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACjC;AAED,eAAO,MAAM,mBAAmB,QAAO,eAIrC,CAAA;AAIF,eAAO,MAAM,mBAAmB,GAC9B,UAAU,eAAe,EACzB,MAAM,MAAM,CAAC,iBAAiB,KAC7B,IAaF,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,UAAU,eAAe,KAAG,OACF,CAAA;AAE3D,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,CAAC,IAAI,KAAG,MAAM,GAAG,SAK/C,CAAA;AAaf,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,CAAC,cAAc,EAC3B,UAAU,eAAe,KACxB,OAUF,CAAA;AAED,eAAO,MAAM,uBAAuB,GAClC,UAAU,eAAe,EACzB,MAAM,MAAM,CAAC,kBAAkB,KAC9B,IAMF,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC9B,MAAM,MAAM,CAAC,cAAc,EAC3B,UAAU,eAAe,KACxB,OAUF,CAAA;AAED,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,CAAC,IAAI,EACjB,QAAQ,MAAM,KACb,IAAI,IAAI,MAAM,CAAC,cAGwB,CAAA"}
1
+ {"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/internal/imports.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAI7C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC7B,QAAQ,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CACjC;AAED,eAAO,MAAM,mBAAmB,QAAO,eAIrC,CAAA;AAIF,eAAO,MAAM,mBAAmB,GAC9B,UAAU,eAAe,EACzB,MAAM,MAAM,CAAC,iBAAiB,KAC7B,IAaF,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,UAAU,eAAe,KAAG,OACF,CAAA;AAE3D,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,CAAC,IAAI,KAAG,MAAM,GAAG,SAS7D,CAAA;AAqBD,eAAO,MAAM,mBAAmB,GAC9B,MAAM,MAAM,CAAC,IAAI,EACjB,QAAQ,MAAM,EACd,UAAU,eAAe,KACxB,IAAI,IAAI,MAAM,CAAC,cAIgC,CAAA;AAElD,eAAO,MAAM,iBAAiB,GAC5B,MAAM,MAAM,CAAC,cAAc,EAC3B,UAAU,eAAe,KACxB,OAOF,CAAA;AAED,eAAO,MAAM,uBAAuB,GAClC,UAAU,eAAe,EACzB,MAAM,MAAM,CAAC,kBAAkB,KAC9B,IAMF,CAAA;AAED,eAAO,MAAM,mBAAmB,GAC9B,MAAM,MAAM,CAAC,cAAc,EAC3B,UAAU,eAAe,KACxB,OAUF,CAAA;AAED,eAAO,MAAM,YAAY,GACvB,MAAM,MAAM,CAAC,IAAI,EACjB,QAAQ,MAAM,KACb,IAAI,IAAI,MAAM,CAAC,cAGwB,CAAA"}
@@ -19,25 +19,35 @@ export const recordMachineImport = (bindings, node) => {
19
19
  }
20
20
  };
21
21
  export const hasMachineImport = (bindings) => bindings.machine.size > 0 || bindings.namespaces.size > 0;
22
- export const staticMemberName = (node) => node.type === "MemberExpression" &&
23
- !node.computed &&
24
- node.property.type === "Identifier"
25
- ? node.property.name
26
- : undefined;
22
+ export const staticMemberName = (node) => {
23
+ if (node.type !== "MemberExpression")
24
+ return undefined;
25
+ return node.computed
26
+ ? node.property.type === "Literal" && typeof node.property.value === "string"
27
+ ? node.property.value
28
+ : undefined
29
+ : node.property.type === "Identifier"
30
+ ? node.property.name
31
+ : undefined;
32
+ };
27
33
  const isNamespaceMachine = (node, bindings) => node.type === "MemberExpression" &&
28
34
  !node.computed &&
29
35
  node.object.type === "Identifier" &&
30
36
  bindings.namespaces.has(node.object.name) &&
31
37
  node.property.type === "Identifier" &&
32
38
  node.property.name === "Machine";
39
+ const isMachineReference = (node, bindings) => node.type === "Identifier"
40
+ ? bindings.machine.has(node.name)
41
+ : isNamespaceMachine(node, bindings);
42
+ export const isMachineMemberCall = (node, member, bindings) => node.type === "CallExpression" &&
43
+ node.callee.type === "MemberExpression" &&
44
+ staticMemberName(node.callee) === member &&
45
+ isMachineReference(node.callee.object, bindings);
33
46
  export const isMachineMakeCall = (node, bindings) => {
34
47
  if (node.callee.type !== "MemberExpression" ||
35
48
  staticMemberName(node.callee) !== "make")
36
49
  return false;
37
- const receiver = node.callee.object;
38
- return receiver.type === "Identifier"
39
- ? bindings.machine.has(receiver.name)
40
- : isNamespaceMachine(receiver, bindings);
50
+ return isMachineReference(node.callee.object, bindings);
41
51
  };
42
52
  export const recordMachineDefinition = (bindings, node) => {
43
53
  if (node.id.type === "Identifier" &&
@@ -1 +1 @@
1
- {"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/internal/imports.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/internal/imports.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,8 @@
1
1
  import type { ESTree } from "@oxlint/plugins";
2
2
  import { type MachineBindings } from "./imports.js";
3
3
  export type PlanningFunction = ESTree.ArrowFunctionExpression | ESTree.Function;
4
+ export declare const enclosingFunction: (node: ESTree.Node) => PlanningFunction | undefined;
5
+ export declare const enclosingPlanningCallback: (node: ESTree.Node, bindings: MachineBindings) => PlanningFunction | undefined;
6
+ export declare const isInvokePlanningCallback: (node: PlanningFunction, bindings: MachineBindings) => boolean;
4
7
  export declare const isPlanningCallback: (node: PlanningFunction, bindings: MachineBindings) => boolean;
5
8
  //# sourceMappingURL=planning.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../src/internal/planning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAA0C,KAAK,eAAe,EAAoB,MAAM,cAAc,CAAA;AAE7G,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,uBAAuB,GAAG,MAAM,CAAC,QAAQ,CAAA;AAuG/E,eAAO,MAAM,kBAAkB,GAC7B,MAAM,gBAAgB,EACtB,UAAU,eAAe,KACxB,OAcF,CAAA"}
1
+ {"version":3,"file":"planning.d.ts","sourceRoot":"","sources":["../../src/internal/planning.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C,OAAO,EAA0C,KAAK,eAAe,EAAoB,MAAM,cAAc,CAAA;AAE7G,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,uBAAuB,GAAG,MAAM,CAAC,QAAQ,CAAA;AAmH/E,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,CAAC,IAAI,KAAG,gBAAgB,GAAG,SAUxE,CAAA;AAcD,eAAO,MAAM,yBAAyB,GACpC,MAAM,MAAM,CAAC,IAAI,EACjB,UAAU,eAAe,KACxB,gBAAgB,GAAG,SAKrB,CAAA;AAED,eAAO,MAAM,wBAAwB,GACnC,MAAM,gBAAgB,EACtB,UAAU,eAAe,KACxB,OAOF,CAAA;AAED,eAAO,MAAM,kBAAkB,GAC7B,MAAM,gBAAgB,EACtB,UAAU,eAAe,KACxB,OAiBF,CAAA"}