@dudousxd/nestjs-durable-eslint-plugin 0.2.0 → 0.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"no-nondeterminism.d.ts","sourceRoot":"","sources":["../src/no-nondeterminism.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAMtE,KAAK,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;AA4CnE,eAAO,MAAM,gBAAgB;;CA+C3B,CAAC"}
1
+ {"version":3,"file":"no-nondeterminism.d.ts","sourceRoot":"","sources":["../src/no-nondeterminism.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAiB,MAAM,0BAA0B,CAAC;AAMtE,KAAK,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;AAiEnE,eAAO,MAAM,gBAAgB;;CA+C3B,CAAC"}
@@ -4,10 +4,27 @@ exports.noNondeterminism = void 0;
4
4
  const utils_1 = require("@typescript-eslint/utils");
5
5
  const createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/DavideCarvalho/nestjs-durable#${name}`);
6
6
  /** True when `node` sits lexically inside the `run` method of a class decorated with `@Workflow`. */
7
+ /** A function/arrow passed as an argument to `ctx.step(...)` / `ctx.task(...)` — its body is run once
8
+ * and checkpointed, so non-determinism inside it is fine (only the orchestration body must be pure). */
9
+ function isCheckpointedCallback(fn) {
10
+ const call = fn.parent;
11
+ if (call?.type !== 'CallExpression' || !call.arguments.includes(fn))
12
+ return false;
13
+ const callee = call.callee;
14
+ return (callee.type === 'MemberExpression' &&
15
+ callee.property.type === 'Identifier' &&
16
+ (callee.property.name === 'step' || callee.property.name === 'task'));
17
+ }
7
18
  function isInWorkflowRun(node) {
8
19
  let cur = node;
9
20
  let runMethod;
10
21
  while (cur) {
22
+ // Crossing a `ctx.step`/`ctx.task` callback boundary before reaching `run` means the call is
23
+ // inside a checkpointed step — not the deterministic orchestration body — so don't flag it.
24
+ if ((cur.type === 'ArrowFunctionExpression' || cur.type === 'FunctionExpression') &&
25
+ isCheckpointedCallback(cur)) {
26
+ return false;
27
+ }
11
28
  if (cur.type === 'MethodDefinition' &&
12
29
  cur.key.type === 'Identifier' &&
13
30
  cur.key.name === 'run') {
@@ -1 +1 @@
1
- {"version":3,"file":"no-nondeterminism.js","sourceRoot":"","sources":["../src/no-nondeterminism.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"no-nondeterminism.js","sourceRoot":"","sources":["../src/no-nondeterminism.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  // Biome (>= 2.0) GritQL plugin: flag non-deterministic sources that corrupt a durable replay.
2
- // Biome plugins can't yet scope by decorator/method, so target it at your workflow files via
3
- // biome.json `overrides` (e.g. include "**/*.workflow.ts") and use ctx.now()/ctx.random()/ctx.uuid().
2
+ // Biome plugins can't scope by decorator/method, so target it at your workflow files via biome.json
3
+ // `overrides` (include "**/*.workflow.ts"). Calls inside a ctx.step(...) / ctx.task(...) callback are
4
+ // NOT flagged — those bodies run once and are checkpointed, so non-determinism there is replay-safe.
5
+ // In the orchestration body, use ctx.now() / ctx.random() / ctx.uuid() instead.
4
6
  language js
5
7
 
6
8
  or {
@@ -11,8 +13,10 @@ or {
11
13
  `globalThis.crypto.randomUUID()`,
12
14
  `new Date()`
13
15
  } as $bad where {
16
+ not $bad <: within `$_.step($...)`,
17
+ not $bad <: within `$_.task($...)`,
14
18
  register_diagnostic(
15
19
  span = $bad,
16
- message = "Non-deterministic source inside a durable workflow — it differs across replays and corrupts the run. Use ctx.now() / ctx.random() / ctx.uuid()."
20
+ message = "Non-deterministic source in a durable workflow body — it differs across replays and corrupts the run. Use ctx.now() / ctx.random() / ctx.uuid() (or move it inside a ctx.step, which is checkpointed)."
17
21
  )
18
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-durable-eslint-plugin",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "ESLint rule: flag non-deterministic calls (Date.now, Math.random, …) inside a @Workflow run",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",