@opetope/lint 0.14.0 → 0.16.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 (137) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +75 -87
  3. package/dist/ast.d.ts +14 -2
  4. package/dist/ast.js +1 -1
  5. package/dist/ast.js.map +1 -1
  6. package/dist/command-hooks.d.ts +7 -6
  7. package/dist/command-hooks.js +1 -1
  8. package/dist/command-hooks.js.map +1 -1
  9. package/dist/context-members.d.ts +8 -7
  10. package/dist/context-members.js +1 -1
  11. package/dist/context-members.js.map +1 -1
  12. package/dist/declaration-ingress.d.ts +43 -11
  13. package/dist/declaration-ingress.js +1 -1
  14. package/dist/declaration-ingress.js.map +1 -1
  15. package/dist/declarations.d.ts +1 -1
  16. package/dist/declarations.js +1 -1
  17. package/dist/declarations.js.map +1 -1
  18. package/dist/effect-declarations.d.ts +3 -2
  19. package/dist/effect-declarations.js +1 -1
  20. package/dist/effect-declarations.js.map +1 -1
  21. package/dist/entry-move-rows.d.ts +21 -0
  22. package/dist/entry-move-rows.js +2 -0
  23. package/dist/entry-move-rows.js.map +1 -0
  24. package/dist/entry-moves.d.ts +25 -0
  25. package/dist/entry-moves.js +10 -0
  26. package/dist/entry-moves.js.map +1 -0
  27. package/dist/feature-body-records.d.ts +5 -3
  28. package/dist/feature-body-records.js +1 -1
  29. package/dist/feature-body-records.js.map +1 -1
  30. package/dist/index.d.ts +65 -58
  31. package/dist/index.js +1 -1
  32. package/dist/index.js.map +1 -1
  33. package/dist/lazy-body-migration.d.ts +5 -5
  34. package/dist/lazy-body-migration.js +1 -1
  35. package/dist/lazy-body-migration.js.map +1 -1
  36. package/dist/model-bindings.d.ts +21 -13
  37. package/dist/model-bindings.js +1 -1
  38. package/dist/model-bindings.js.map +1 -1
  39. package/dist/resource-vocabulary.d.ts +17 -0
  40. package/dist/resource-vocabulary.js +2 -0
  41. package/dist/resource-vocabulary.js.map +1 -0
  42. package/dist/retired-vocabulary-messages.d.ts +6 -0
  43. package/dist/retired-vocabulary-messages.js +2 -0
  44. package/dist/retired-vocabulary-messages.js.map +1 -0
  45. package/dist/retired-vocabulary.d.ts +10 -8
  46. package/dist/retired-vocabulary.js +1 -1
  47. package/dist/retired-vocabulary.js.map +1 -1
  48. package/dist/rule.d.ts +94 -5
  49. package/dist/rule.js +1 -1
  50. package/dist/rule.js.map +1 -1
  51. package/dist/rules/capture-command-cleanup.d.ts +1 -4
  52. package/dist/rules/capture-command-cleanup.js +1 -1
  53. package/dist/rules/capture-command-cleanup.js.map +1 -1
  54. package/dist/rules/define-feature-property-order.d.ts +1 -4
  55. package/dist/rules/define-feature-property-order.js +1 -1
  56. package/dist/rules/define-feature-property-order.js.map +1 -1
  57. package/dist/rules/enabled-predicate.d.ts +1 -4
  58. package/dist/rules/enabled-predicate.js +1 -1
  59. package/dist/rules/enabled-predicate.js.map +1 -1
  60. package/dist/rules/id-naming.d.ts +1 -3
  61. package/dist/rules/layer-placement.d.ts +1 -3
  62. package/dist/rules/no-behavior-in-integration.d.ts +8 -0
  63. package/dist/rules/no-behavior-in-integration.js +2 -0
  64. package/dist/rules/no-behavior-in-integration.js.map +1 -0
  65. package/dist/rules/no-command-in-deps.d.ts +1 -4
  66. package/dist/rules/no-command-in-deps.js +1 -1
  67. package/dist/rules/no-command-in-deps.js.map +1 -1
  68. package/dist/rules/no-dead-abort-check.d.ts +8 -0
  69. package/dist/rules/no-dead-abort-check.js +2 -0
  70. package/dist/rules/no-dead-abort-check.js.map +1 -0
  71. package/dist/rules/no-event-without-emit.d.ts +10 -0
  72. package/dist/rules/no-event-without-emit.js +2 -0
  73. package/dist/rules/no-event-without-emit.js.map +1 -0
  74. package/dist/rules/no-inline-requires-models.d.ts +8 -0
  75. package/dist/rules/no-inline-requires-models.js +5 -0
  76. package/dist/rules/no-inline-requires-models.js.map +1 -0
  77. package/dist/rules/no-internal-imports.d.ts +1 -3
  78. package/dist/rules/no-internal-imports.js +1 -1
  79. package/dist/rules/no-internal-imports.js.map +1 -1
  80. package/dist/rules/no-redundant-const-tuple.d.ts +1 -4
  81. package/dist/rules/no-redundant-const-tuple.js +1 -1
  82. package/dist/rules/no-redundant-const-tuple.js.map +1 -1
  83. package/dist/rules/no-retired-vocabulary.d.ts +2 -4
  84. package/dist/rules/no-retired-vocabulary.js +1 -1
  85. package/dist/rules/no-retired-vocabulary.js.map +1 -1
  86. package/dist/rules/no-single-command-lane.d.ts +10 -0
  87. package/dist/rules/no-single-command-lane.js +2 -0
  88. package/dist/rules/no-single-command-lane.js.map +1 -0
  89. package/dist/rules/no-snapshot-in-update.d.ts +1 -4
  90. package/dist/rules/no-snapshot-in-update.js.map +1 -1
  91. package/dist/rules/no-snapshot-read-in-render.d.ts +2 -3
  92. package/dist/rules/no-snapshot-read-in-render.js +1 -1
  93. package/dist/rules/no-snapshot-read-in-render.js.map +1 -1
  94. package/dist/rules/no-subscribe-outside-models.d.ts +1 -3
  95. package/dist/rules/no-subscribe-outside-models.js +1 -1
  96. package/dist/rules/no-subscribe-outside-models.js.map +1 -1
  97. package/dist/rules/no-write-after-source-write.d.ts +1 -4
  98. package/dist/rules/no-write-after-source-write.js +1 -1
  99. package/dist/rules/no-write-after-source-write.js.map +1 -1
  100. package/dist/rules/prefer-derive.d.ts +7 -0
  101. package/dist/rules/prefer-derive.js +2 -0
  102. package/dist/rules/prefer-derive.js.map +1 -0
  103. package/dist/rules/prefer-effect-current.d.ts +1 -4
  104. package/dist/rules/prefer-effect-current.js +1 -1
  105. package/dist/rules/prefer-effect-current.js.map +1 -1
  106. package/dist/rules/prefer-lazy-body-record.d.ts +1 -4
  107. package/dist/rules/prefer-lazy-body-record.js +1 -1
  108. package/dist/rules/prefer-lazy-body-record.js.map +1 -1
  109. package/dist/rules/prefer-model-selection.d.ts +1 -3
  110. package/dist/rules/prefer-model-selection.js +1 -1
  111. package/dist/rules/prefer-model-selection.js.map +1 -1
  112. package/dist/rules/prefer-read.d.ts +2 -0
  113. package/dist/rules/prefer-read.js +2 -0
  114. package/dist/rules/prefer-read.js.map +1 -0
  115. package/dist/rules/prefer-when-over-enabled.d.ts +7 -0
  116. package/dist/rules/prefer-when-over-enabled.js +2 -0
  117. package/dist/rules/prefer-when-over-enabled.js.map +1 -0
  118. package/dist/rules/require-declared-models.d.ts +1 -3
  119. package/dist/rules/require-declared-models.js +1 -1
  120. package/dist/rules/require-declared-models.js.map +1 -1
  121. package/dist/rules/require-literal-id.d.ts +2 -3
  122. package/dist/rules/require-literal-id.js +1 -1
  123. package/dist/rules/require-literal-id.js.map +1 -1
  124. package/dist/rules/require-static-feature.d.ts +9 -0
  125. package/dist/rules/require-static-feature.js +2 -0
  126. package/dist/rules/require-static-feature.js.map +1 -0
  127. package/dist/rules/scope-builder-releases-subscriptions.d.ts +10 -0
  128. package/dist/rules/scope-builder-releases-subscriptions.js +2 -0
  129. package/dist/rules/scope-builder-releases-subscriptions.js.map +1 -0
  130. package/dist/snapshot-updates.d.ts +4 -3
  131. package/dist/snapshot-updates.js +1 -1
  132. package/dist/snapshot-updates.js.map +1 -1
  133. package/dist/static-value.d.ts +3 -2
  134. package/dist/static-value.js +1 -1
  135. package/dist/static-value.js.map +1 -1
  136. package/oxlintrc.json +10 -0
  137. package/package.json +13 -3
@@ -1,5 +1,2 @@
1
- import type { TSESLint } from '@typescript-eslint/utils';
2
- declare const noRedundantConstTuple: TSESLint.RuleModule<"redundantConstTuple", [], unknown, TSESLint.RuleListener> & {
3
- name: string;
4
- };
1
+ declare const noRedundantConstTuple: import("../rule.js").RuleModule<"redundantConstTuple", []>;
5
2
  export { noRedundantConstTuple };
@@ -1,2 +1,2 @@
1
- import{AST_NODE_TYPES as s}from"@typescript-eslint/utils";import{isApi as o}from"../model-bindings.js";import{createRule as i}from"../rule.js";function a(e){if(e?.type!==s.TSAsExpression)return;const{typeAnnotation:n}=e;return n.type===s.TSTypeReference&&n.typeName.type===s.Identifier&&n.typeName.name==="const"&&e.expression.type===s.ArrayExpression?e:void 0}function p(e,n){const t=n.expression.range[1];return e.getCommentsInside(n).some(r=>r.range[0]>=t)}const u=i({create(e){return{CallExpression(n){const t=a(n.arguments[0]);t===void 0||!o(e.sourceCode,n.callee,"@opetope/core","derive",!0)||e.report({fix:p(e.sourceCode,t)?null:r=>r.removeRange([t.expression.range[1],t.range[1]]),messageId:"redundantConstTuple",node:t.typeAnnotation})}}},meta:{docs:{description:"The tuple source of `derive` infers itself, so `as const` on it states nothing."},fixable:"code",messages:{redundantConstTuple:"The tuple source of `derive` is a `const` type parameter, so it already infers exact values: `as const` here changes nothing (D279, D309)."},schema:[],type:"suggestion"},name:"no-redundant-const-tuple"});export{u as noRedundantConstTuple};
1
+ import{AST_NODE_TYPES as s}from"@typescript-eslint/types";import{isApi as o}from"../model-bindings.js";import{createRule as i}from"../rule.js";function a(e){if(e?.type!==s.TSAsExpression)return;const{typeAnnotation:n}=e;return n.type===s.TSTypeReference&&n.typeName.type===s.Identifier&&n.typeName.name==="const"&&e.expression.type===s.ArrayExpression?e:void 0}function p(e,n){const t=n.expression.range[1];return e.getCommentsInside(n).some(r=>r.range[0]>=t)}const u=i({create(e){return{CallExpression(n){const t=a(n.arguments[0]);t===void 0||!o(e.sourceCode,n.callee,"@opetope/core","derive",!0)||e.report({fix:p(e.sourceCode,t)?null:r=>r.removeRange([t.expression.range[1],t.range[1]]),messageId:"redundantConstTuple",node:t.typeAnnotation})}}},meta:{docs:{description:"The tuple source of `derive` infers itself, so `as const` on it states nothing."},fixable:"code",messages:{redundantConstTuple:"The tuple source of `derive` is a `const` type parameter, so it already infers exact values: `as const` here changes nothing (D279, D309)."},schema:[],type:"suggestion"},name:"no-redundant-const-tuple"});export{u as noRedundantConstTuple};
2
2
  //# sourceMappingURL=no-redundant-const-tuple.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-redundant-const-tuple.js","sources":["../../src/rules/no-redundant-const-tuple.ts"],"sourcesContent":["import type { TSESLint, TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nimport { isApi } from '../model-bindings';\nimport { createRule } from '../rule';\n\ntype MessageIds = 'redundantConstTuple';\n\n/** `as const` and nothing else: any other assertion on the same tuple says something this rule is not about. */\nfunction constAssertionOf(node: TSESTree.Node | undefined): TSESTree.TSAsExpression | undefined {\n if (node?.type !== AST_NODE_TYPES.TSAsExpression) return undefined;\n\n const { typeAnnotation } = node;\n const named =\n typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&\n typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&\n typeAnnotation.typeName.name === 'const';\n\n return named && node.expression.type === AST_NODE_TYPES.ArrayExpression ? node : undefined;\n}\n\n/**\n * A comment between the tuple and the assertion belongs to neither, and removing the range would take it with the\n * words it explains, so such an assertion is reported without a fix.\n */\nfunction hasTrailingComment(source: TSESLint.SourceCode, node: TSESTree.TSAsExpression): boolean {\n const from = node.expression.range[1];\n\n return source.getCommentsInside(node).some(comment => comment.range[0] >= from);\n}\n\nconst noRedundantConstTuple = createRule<[], MessageIds>({\n create(context) {\n return {\n CallExpression(node): void {\n // The shape decides first and the import second: a call that cannot be a tuple `derive` pays for nothing.\n const assertion = constAssertionOf(node.arguments[0]);\n\n // The package name exactly, unlike `no-command-in-deps`: this rule rewrites code, and a host's own `derive`\n // has no const type parameter to make the assertion redundant, so removing it there would change inference\n // in silence.\n if (assertion === undefined || !isApi(context.sourceCode, node.callee, '@opetope/core', 'derive', true)) return;\n\n context.report({\n fix: hasTrailingComment(context.sourceCode, assertion)\n ? null\n : fixer => fixer.removeRange([assertion.expression.range[1], assertion.range[1]]),\n messageId: 'redundantConstTuple',\n node: assertion.typeAnnotation,\n });\n },\n };\n },\n meta: {\n docs: {\n description: 'The tuple source of `derive` infers itself, so `as const` on it states nothing.',\n },\n fixable: 'code',\n messages: {\n redundantConstTuple:\n 'The tuple source of `derive` is a `const` type parameter, so it already infers exact values: `as const` here changes nothing (D279, D309).',\n },\n schema: [],\n type: 'suggestion',\n },\n name: 'no-redundant-const-tuple',\n});\n\nexport { noRedundantConstTuple };\n"],"names":["constAssertionOf","node","AST_NODE_TYPES","typeAnnotation","hasTrailingComment","source","from","comment","noRedundantConstTuple","createRule","context","assertion","isApi","fixer"],"mappings":"+IASA,SAASA,EAAiBC,EAA+B,CACvD,GAAIA,GAAM,OAASC,EAAe,eAAgB,OAElD,KAAM,CAAE,eAAAC,CAAc,EAAKF,EAM3B,OAJEE,EAAe,OAASD,EAAe,iBACvCC,EAAe,SAAS,OAASD,EAAe,YAChDC,EAAe,SAAS,OAAS,SAEnBF,EAAK,WAAW,OAASC,EAAe,gBAAkBD,EAAO,MACnF,CAMA,SAASG,EAAmBC,EAA6BJ,EAA6B,CACpF,MAAMK,EAAOL,EAAK,WAAW,MAAM,CAAC,EAEpC,OAAOI,EAAO,kBAAkBJ,CAAI,EAAE,KAAKM,GAAWA,EAAQ,MAAM,CAAC,GAAKD,CAAI,CAChF,CAEA,MAAME,EAAwBC,EAA2B,CACvD,OAAOC,EAAO,CACZ,MAAO,CACL,eAAeT,EAAI,CAEjB,MAAMU,EAAYX,EAAiBC,EAAK,UAAU,CAAC,CAAC,EAKhDU,IAAc,QAAa,CAACC,EAAMF,EAAQ,WAAYT,EAAK,OAAQ,gBAAiB,SAAU,EAAI,GAEtGS,EAAQ,OAAO,CACb,IAAKN,EAAmBM,EAAQ,WAAYC,CAAS,EACjD,KACAE,GAASA,EAAM,YAAY,CAACF,EAAU,WAAW,MAAM,CAAC,EAAGA,EAAU,MAAM,CAAC,CAAC,CAAC,EAClF,UAAW,sBACX,KAAMA,EAAU,cACjB,CAAA,CACH,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YAAa,iFACd,EACD,QAAS,OACT,SAAU,CACR,oBACE,4IACH,EACD,OAAQ,CAAA,EACR,KAAM,YACP,EACD,KAAM,0BACP,CAAA"}
1
+ {"version":3,"file":"no-redundant-const-tuple.js","sources":["../../src/rules/no-redundant-const-tuple.ts"],"sourcesContent":["import { AST_NODE_TYPES } from '@typescript-eslint/types';\nimport type { TSESTree } from '@typescript-eslint/types';\n\nimport { isApi } from '../model-bindings';\nimport type { SourceCode } from '../rule';\nimport { createRule } from '../rule';\n\ntype MessageIds = 'redundantConstTuple';\n\n/** `as const` and nothing else: any other assertion on the same tuple says something this rule is not about. */\nfunction constAssertionOf(node: TSESTree.Node | undefined): TSESTree.TSAsExpression | undefined {\n if (node?.type !== AST_NODE_TYPES.TSAsExpression) return undefined;\n\n const { typeAnnotation } = node;\n const named =\n typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&\n typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&\n typeAnnotation.typeName.name === 'const';\n\n return named && node.expression.type === AST_NODE_TYPES.ArrayExpression ? node : undefined;\n}\n\n/**\n * A comment between the tuple and the assertion belongs to neither, and removing the range would take it with the\n * words it explains, so such an assertion is reported without a fix.\n */\nfunction hasTrailingComment(source: SourceCode, node: TSESTree.TSAsExpression): boolean {\n const from = node.expression.range[1];\n\n return source.getCommentsInside(node).some(comment => comment.range[0] >= from);\n}\n\nconst noRedundantConstTuple = createRule<[], MessageIds>({\n create(context) {\n return {\n CallExpression(node): void {\n // The shape decides first and the import second: a call that cannot be a tuple `derive` pays for nothing.\n const assertion = constAssertionOf(node.arguments[0]);\n\n // The package name exactly, unlike `no-command-in-deps`: this rule rewrites code, and a host's own `derive`\n // has no const type parameter to make the assertion redundant, so removing it there would change inference\n // in silence.\n if (assertion === undefined || !isApi(context.sourceCode, node.callee, '@opetope/core', 'derive', true)) return;\n\n context.report({\n fix: hasTrailingComment(context.sourceCode, assertion)\n ? null\n : fixer => fixer.removeRange([assertion.expression.range[1], assertion.range[1]]),\n messageId: 'redundantConstTuple',\n node: assertion.typeAnnotation,\n });\n },\n };\n },\n meta: {\n docs: {\n description: 'The tuple source of `derive` infers itself, so `as const` on it states nothing.',\n },\n fixable: 'code',\n messages: {\n redundantConstTuple:\n 'The tuple source of `derive` is a `const` type parameter, so it already infers exact values: `as const` here changes nothing (D279, D309).',\n },\n schema: [],\n type: 'suggestion',\n },\n name: 'no-redundant-const-tuple',\n});\n\nexport { noRedundantConstTuple };\n"],"names":["constAssertionOf","node","AST_NODE_TYPES","typeAnnotation","hasTrailingComment","source","from","comment","noRedundantConstTuple","createRule","context","assertion","isApi","fixer"],"mappings":"+IAUA,SAASA,EAAiBC,EAA+B,CACvD,GAAIA,GAAM,OAASC,EAAe,eAAgB,OAElD,KAAM,CAAE,eAAAC,CAAc,EAAKF,EAM3B,OAJEE,EAAe,OAASD,EAAe,iBACvCC,EAAe,SAAS,OAASD,EAAe,YAChDC,EAAe,SAAS,OAAS,SAEnBF,EAAK,WAAW,OAASC,EAAe,gBAAkBD,EAAO,MACnF,CAMA,SAASG,EAAmBC,EAAoBJ,EAA6B,CAC3E,MAAMK,EAAOL,EAAK,WAAW,MAAM,CAAC,EAEpC,OAAOI,EAAO,kBAAkBJ,CAAI,EAAE,KAAKM,GAAWA,EAAQ,MAAM,CAAC,GAAKD,CAAI,CAChF,CAEA,MAAME,EAAwBC,EAA2B,CACvD,OAAOC,EAAO,CACZ,MAAO,CACL,eAAeT,EAAI,CAEjB,MAAMU,EAAYX,EAAiBC,EAAK,UAAU,CAAC,CAAC,EAKhDU,IAAc,QAAa,CAACC,EAAMF,EAAQ,WAAYT,EAAK,OAAQ,gBAAiB,SAAU,EAAI,GAEtGS,EAAQ,OAAO,CACb,IAAKN,EAAmBM,EAAQ,WAAYC,CAAS,EACjD,KACAE,GAASA,EAAM,YAAY,CAACF,EAAU,WAAW,MAAM,CAAC,EAAGA,EAAU,MAAM,CAAC,CAAC,CAAC,EAClF,UAAW,sBACX,KAAMA,EAAU,cACjB,CAAA,CACH,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YAAa,iFACd,EACD,QAAS,OACT,SAAU,CACR,oBACE,4IACH,EACD,OAAQ,CAAA,EACR,KAAM,YACP,EACD,KAAM,0BACP,CAAA"}
@@ -1,5 +1,3 @@
1
- type MessageIds = 'commandLane' | 'commandLatest' | 'commandName' | 'commandOnce' | 'commandOutcomeStatus' | 'commandPolicy' | 'commandQueueBy' | 'conditionFrom' | 'contextCall' | 'contextCalls' | 'contributionWhen' | 'deliveryKey' | 'deliveryKind' | 'deliveryReject' | 'effectOnDispose' | 'effectSkipInitial' | 'effectWhen' | 'eventBackpressure' | 'fromExternal' | 'navigatorPolicy' | 'resourceActivity' | 'resourceDisposer' | 'resourceInvalidate' | 'runtimeInternalEntry' | 'scopeKeyed' | 'stateActivity' | 'useCommands';
2
- declare const noRetiredVocabulary: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
3
- name: string;
4
- };
1
+ import type { MessageIds } from '../retired-vocabulary-messages.js';
2
+ declare const noRetiredVocabulary: import("../rule.js").RuleModule<MessageIds, []>;
5
3
  export { noRetiredVocabulary };
@@ -1,2 +1,2 @@
1
- import{AST_NODE_TYPES as s}from"@typescript-eslint/utils";import{propertyName as u,findProperty as O}from"../ast.js";import{methodPath as v,isContextFunction as M}from"../declaration-ingress.js";import{isFeatureSection as N,isApi as T,localValue as m}from"../model-bindings.js";import{isResourceValue as A,isResourceHook as S,isStateActivity as x,isSurfaceValue as P,isCommandOutcome as V}from"../retired-vocabulary.js";import{createRule as _}from"../rule.js";const d=new Map([["lane","commandLane"],["once","commandOnce"],["policy","commandPolicy"],["queueBy","commandQueueBy"]]),c=new Map([["concurrency",new Map([["latest","commandLatest"]])]]),W=new Map([["onDispose","effectOnDispose"],["skipInitial","effectSkipInitial"],["when","effectWhen"]]),B=new Map([["backpressure","eventBackpressure"]]),L=new Map([["key","deliveryKey"],["kind","deliveryKind"]]),j=new Map,g=["backpressure","delivery"],F=new Map([["overflow",new Map([["reject","deliveryReject"]])]]),p=new Map([["when","contributionWhen"]]),q=new Map([["pipe",{at:[2],carries:[],words:p}],["register",{at:[2],carries:[],words:p}],["slot",{at:[2],carries:[],words:p}]]),K=new Map([["from","conditionFrom"]]),U=new Map([["call",{at:[1,2],carries:[],values:c,words:d}],["calls",{at:[2],carries:[],values:c,words:d}],["command",{at:[1,2],carries:[],values:c,words:d}],["effect",{at:[2],carries:[],words:W}],["event",{at:[3],carries:g,words:B}],["resource.live",{at:[0],carriedValues:F,carries:g,words:j}],["select",{at:[2],carries:[],values:c,words:d}]]),Y=new Map([["activity","stateActivity"],["invalidate","resourceInvalidate"],["policy","navigatorPolicy"],["status","commandOutcomeStatus"]]),z=new Map([["call","contextCall"],["calls","contextCalls"],["scope.keyed","scopeKeyed"]]),H=new Map([["ApplicationConditionBinding",{messageId:"runtimeInternalEntry",module:"@opetope/runtime/internal",replacement:"@opetope/runtime"}],["ApplicationExecution",{messageId:"runtimeInternalEntry",module:"@opetope/runtime/internal",replacement:"@opetope/runtime"}],["ApplicationImportBinding",{messageId:"runtimeInternalEntry",module:"@opetope/runtime/internal",replacement:"@opetope/runtime"}],["Call",{messageId:"commandName",replacement:"Command"}],["CallError",{messageId:"commandName",replacement:"CommandError"}],["CallInputArgs",{messageId:"commandName",replacement:"CommandInputArgs"}],["CallTimeoutError",{messageId:"commandName",replacement:"CommandTimeoutError"}],["NavigatorPolicy",{messageId:"navigatorPolicy",replacement:"NavigatorCatalogue"}],["ResourceActivity",{messageId:"resourceActivity",replacement:"ResourceNodeActivity"}],["ResourceDisposer",{messageId:"resourceDisposer",replacement:"Disposer"}],["RunCallOptions",{messageId:"commandName",replacement:"RunCommandOptions"}],["externalReadable",{messageId:"fromExternal",replacement:"fromExternal"}],["runCall",{messageId:"commandName",replacement:"runCommand"}],["useCommands",{messageId:"useCommands",replacement:"useModel"}]]);function Q(a){return a.type===s.MemberExpression?a.property:a}function G(a){return a.imported.type===s.Identifier?a.imported.name:a.imported.value}const J=_({create(a){const r=a.sourceCode,b=e=>{const t=v(r,e.callee);if(t===void 0)return;const n={modifiers:U.get(t.method),word:z.get(t.method)};if(!(n.modifiers===void 0&&n.word===void 0))return M(r,t.fn)?n:void 0},h=(e,t)=>{const n=e.arguments[t];if(n===void 0||n.type===s.SpreadElement)return;const o=m(r,n);return o.type===s.ObjectExpression?o:void 0},D=e=>{const t=v(r,e.callee),n=t===void 0?void 0:q.get(t.method);if(!(t===void 0||n===void 0))return N(r,t.fn,"provides",!0)?n:void 0},I=e=>{if(T(r,e.callee,"@opetope/runtime","defineCondition",!0))return h(e,1)},l=(e,t)=>{for(const n of e.properties){if(n.type!==s.Property)continue;const o=u(n),i=o===void 0?void 0:t.get(o);i!==void 0&&a.report({messageId:i,node:n.key})}},C=(e,t)=>{const n=u(e),o=n===void 0?void 0:t.get(n);if(o===void 0)return;const i=m(r,e.value);return i.type===s.Literal&&typeof i.value=="string"?o.get(i.value):void 0},f=(e,t)=>{for(const n of e.properties){if(n.type!==s.Property)continue;const o=C(n,t);o!==void 0&&a.report({messageId:o,node:n.value})}},k=(e,t,n)=>{const o=O(e,t),i=o===void 0?void 0:m(r,o.value);i?.type===s.ObjectExpression&&(l(i,L),n.carriedValues!==void 0&&f(i,n.carriedValues))},w=(e,t)=>{for(const n of t.at){const o=h(e,n);if(o!==void 0){l(o,t.words),t.values!==void 0&&f(o,t.values);for(const i of t.carries)k(o,i,t)}}},y=e=>A(r,e)||S(r,e),R=(e,t)=>t==="resourceInvalidate"?y(e.object):t==="stateActivity"?x(r,e):t==="navigatorPolicy"?P(r,e.object):V(r,e.object),E=(e,t)=>{const n=Y.get(t);return n!==void 0&&R(e,n)?n:void 0};return{CallExpression(e){const t=D(e);t!==void 0&&w(e,t);const n=I(e);n!==void 0&&l(n,K);const o=b(e);o!==void 0&&(o.word!==void 0&&a.report({messageId:o.word,node:Q(e.callee)}),o.modifiers!==void 0&&w(e,o.modifiers))},ImportDeclaration(e){if(e.source.value.startsWith("@opetope/"))for(const t of e.specifiers){if(t.type!==s.ImportSpecifier)continue;const n=G(t),o=H.get(n);o!==void 0&&(o.module===void 0||o.module===e.source.value)&&a.report({data:{replacement:o.replacement,word:n},messageId:o.messageId,node:t.imported})}},MemberExpression(e){if(e.computed||e.property.type!==s.Identifier)return;const t=E(e,e.property.name);t!==void 0&&a.report({messageId:t,node:e.property})},Property(e){if(u(e)!=="invalidate"||e.parent.type!==s.ObjectPattern)return;const t=e.parent.parent;t.type!==s.VariableDeclarator||t.init===null||y(t.init)&&a.report({messageId:"resourceInvalidate",node:e.key})}}},meta:{docs:{description:"A word the D365\u2013D411 wave or a decision after it retired is named with its replacement, never rewritten."},messages:{commandLane:'`lane` is now a member of `concurrency`: write `concurrency: lane`, `concurrency: { by, lane }` for a keyed queue, or `concurrency: { lane, pending: "latest" }` where `policy: "latest"` stood beside it. Which of the three this record meant is in what it wrote together, so nothing here is rewritten for you (D387).',commandLatest:'`concurrency: "latest"` is now `concurrency: { pending: "latest" }`, and `{ lane, pending: "latest" }` where the queue is shared. The word named the input that wins and never named what it wins, so the place is written out: one waiting slot at the end of the lane, taken by a newer input while the body in flight is left to finish. Nothing else about the policy moved (D459).',commandName:"`{{word}}` is now `{{replacement}}`: one word for a command, everywhere. The primitive was the last place the vocabulary still said `Call`, while the hook was already `useCommand` and the outcome `CommandOutcome`. There is no alias (D385).",commandOnce:"`once` is now `memoize`: it caches a successful result, it does not stop after one run. `addEventListener(type, handler, { once: true })` is what the platform means by the word, and it is not what this option ever did (D389).",commandOutcomeStatus:'`status` is now `kind` on a `CommandOutcome`: one word for the discriminant of a settled answer, the one `ResourceState`, `ResourceOperationOutcome`, `ResourceCommitOutcome`, `PaginationOutcome` and a screen result already carry. The three branches are unchanged \u2014 `{ kind: "ok", value }`, `{ kind: "failed", error }`, `{ kind: "cancelled", reason }` (D411).',commandPolicy:'`policy` is now `concurrency`: one word for the order the runs take, written as `queue`, `parallel`, a lane or `{ pending: "latest" }`. Where `queueBy` or `lane` stood beside it the three collapse into one value \u2014 `{ by }`, `{ by, lane }` or `{ lane, pending: "latest" }` \u2014 so the shape depends on which of them this record wrote, and that is why this rule names the word instead of rewriting it (D387, D459).',commandQueueBy:"`queueBy` is now a member of `concurrency`: write `concurrency: { by: input => key }`, or `concurrency: { by, lane }` where a lane stood beside it (D387).",conditionFrom:"`from` of `defineCondition` is now `source`: write `defineCondition(id, { select, source })`. One word names the dependency a node reads \u2014 `resource.load({ source })` and `attach(source)` already say it, and this node's own refusals said `Condition source` about the field they called `from` (D410, D411).",contextCall:"`call` is now `command`: `ctx.command(run, options?)` in a model, `own.command(within, run, options?)` in a feature. The body takes one argument, its context, and reads the declared input off it as `input` \u2014 and `Input` is inferred from every position of the call except the body, so it is written in the cheapest that fits: the result type of a model factory names it in the literal it returns, an annotated option names it (`dedupe: (deposit: Deposit) => \u2026`), a constant names it (`const refill: Command<Refill, void> = ctx.command(\u2026)`), and the annotation of that context \u2014 `({ input, update }: ModelCommandContext<Deposit>)` in a model, `({ input, source }: FeatureCommandContext<typeof within, Deposit>)` in a feature \u2014 is what is left; a feature has the last two only. `command<Deposit>(\u2026)` is not a position: it pins `Output` to its default (D385, D386, D444, D455).",contextCalls:'`ctx.calls` and `own.calls` are now `ctx.select` and `own.select`: declaring a body and selecting a command a dependency already declares are two mechanisms, so they are two words. `select(source, "name")` answers one command and `select(source, ["a", "b"])` a record of them (D388).',contributionWhen:"`when` of a contribution is now `enabled`: write `slot(target, value, { enabled })`, and the same at `pipe` and `register`. A truth the runtime reads while the node exists is `enabled`, at a contribution and at a Resource alike; `when` names the other mechanism \u2014 the declared `Condition`s of `defineFeature({ when })`, which the application resolves before anything exists. `scope.while` keeps its own `when` (D378, D411).",deliveryKey:'Inside a delivery record `key` is now `by`: `{ pending: "latest", by }` keeps one waiting place per key instead of one for the whole node (D374).',deliveryKind:'Inside a delivery record `kind` is now `pending`: `kind: "latest"` is `pending: "latest"`, and `kind: "queue"` is `pending: "all"` \u2014 the backlog only an event has. The discriminant moved because with one dimension shared by both nodes, the discriminant is that dimension (D374).',deliveryReject:'`overflow: "reject"` is now `overflow: "drop"`: one word at both nodes for \xABthe new one does not enter and `emit` answers `false`\xBB. `"flush-oldest"` is unchanged and still the default of a keyed delivery (D369, D411).',effectOnDispose:"`onDispose` is now `finalize`: an effect has two releases \u2014 the disposer a run returns, and the one the node itself gets once \u2014 and an `on*` prefix did not tell them apart. No word of the authoring vocabulary carries that prefix any more (D379).",effectSkipInitial:"`skipInitial` is now `initial`, and the polarity is inverted: `skipInitial: true` is `initial: false`, and `initial` defaults to `true`. Both words are booleans, so carrying the value across unchanged compiles and means the opposite \u2014 which is why this rule names it and leaves the rewrite to you (D379).",effectWhen:"`when` at an effect is now `filter` or `initial`, and which one depends on what the predicate asks. A predicate that selects values is `filter: (current, previous) => \u2026`; a predicate whose whole job is to refuse the first run \u2014 `(_current, previous) => previous !== undefined` \u2014 is `initial: false`. This rule does not guess between them. The word `when` is untouched at a feature and at `scope.while`; at a contribution it is now `enabled` (D379, D411).",eventBackpressure:'`backpressure` is now `delivery`: one word at both nodes that admit a producer. Write `delivery: "latest"` for one waiting place that the newest payload takes, or the record \u2014 `{ pending, by }`, `{ pending, capacity, overflow }` \u2014 for the rest (D374).',fromExternal:"`externalReadable` is now `fromExternal`: `from*` names where a `Readable` comes from, beside `fromMaybe`. The old name was built from its result, which every word of that module already answers (D380).",navigatorPolicy:"`NavigatorPolicy` is now `NavigatorCatalogue`, and `surface.policy` is now `surface.catalogue`: this is four callbacks a navigator asks, and D291 made a policy data \u2014 a word when it has no parameters, a record when it has them (D411).",resourceActivity:"`ResourceActivity` is retired at both entries that spelled it. From `@opetope/devtools` it is `ResourceNodeActivity` (D411). From `@opetope/core` it is gone: a state answers what failed and what is working in two fields of its own, so read `state.failure` and `state.pending` instead of a union that flattened them (D462).",resourceDisposer:"`ResourceDisposer` is now `Disposer`: one name for `() => Awaitable<void>`, which three of them used to spell \u2014 `Disposer`, `ResourceDisposer` and `FeatureDisposer`. It travels on `@opetope/core/internal` beside `Awaitable` (D411).",resourceInvalidate:"`invalidate()` is now `reset()`: it clears the whole cache, drops the current data, opens a new epoch and restarts every configured channel. Everywhere else `invalidate` means \xABmark stale, keep the data\xBB, so the old name promised the opposite of what the verb does; it now names no operation of a Resource at all (D373).",runtimeInternalEntry:"`{{word}}` is published by `{{replacement}}`: import it from there. Three names were published by both entries and every consumer took the internal copy, so the copies are gone and the names are not (D411, D415).",scopeKeyed:"`scope.keyed(source, open, { key })` is now `scope.each(source, key, open)`: `each` says what the node does, one child per element, and the key is required \u2014 so it stands between the list it identifies and the child it opens. The trailing record is gone, which makes this a move and not only a rename (D378).",stateActivity:"No `ResourceState` carries `activity` any more: the union said what a channel was doing and what had failed in one word. Read `state.failure` \u2014 `undefined` is \xABnothing failed\xBB, and otherwise `channel` names the channel that died and `error` carries its failure \u2014 and `state.pending` for the channel with work in flight. Both are declared on every member, so neither needs a narrowing by `kind` first (D462).",useCommands:"`useCommands` is gone: a record of command consumers comes from `useModel(Declaration, select)`, which has an owner and a lifetime. One command is still `useCommand` (D388)."},schema:[],type:"problem"},name:"no-retired-vocabulary"});export{J as noRetiredVocabulary};
1
+ import{DefinitionType as H}from"@typescript-eslint/scope-manager";import{AST_NODE_TYPES as o}from"@typescript-eslint/types";import{propertyName as p,findProperty as Q}from"../ast.js";import{methodPath as g,isContextFunction as q}from"../declaration-ingress.js";import{namespaceTypeMove as z,typeImportMove as J,namespaceMemberMove as X,staticMemberName as Z,dynamicMove as ee,reexportMove as re,starMove as te,importMove as ne}from"../entry-moves.js";import{importName as ie,isFeatureSection as D,isApi as S,localValue as l,hasWritesBeyondDefinition as oe}from"../model-bindings.js";import{isResourceValue as ae,isResourceHook as se,isStateActivity as ce,isSurfaceValue as C,isLinkSourceValue as de,isCommandOutcome as ue}from"../retired-vocabulary.js";import{RETIRED_MESSAGES as pe}from"../retired-vocabulary-messages.js";import{createResourceVocabulary as le}from"../resource-vocabulary.js";import{createRule as me,findVariable as fe}from"../rule.js";const m=new Map([["lane","commandLane"],["once","commandOnce"],["policy","commandPolicy"],["queueBy","commandQueueBy"]]),f=new Map([["concurrency",new Map([["latest","commandLatest"]])]]),ye=new Map([["onDispose","effectOnDispose"],["skipInitial","effectSkipInitial"],["when","effectWhen"]]),ge=new Map([["when","scopeWhileWhen"]]),Ie=new Map([["backpressure","eventBackpressure"]]),Ee=new Map([["key","deliveryKey"],["kind","deliveryKind"]]),x=new Map([["pagination","resourcePagination"]]),we=new Map([["nextCursor","paginateNextCursor"]]),O=["backpressure","delivery"],ve=new Map([["overflow",new Map([["reject","deliveryReject"]])]]),I=new Map([["when","contributionWhen"]]),Re=new Map([["pipe",{at:[2],carries:[],words:I}],["register",{at:[2],carries:[],words:I}],["slot",{at:[2],carries:[],words:I}]]),be=new Map([["from","conditionFrom"]]),Me=new Map([["call",{at:[1,2],carries:[],values:f,words:m}],["calls",{at:[2],carries:[],values:f,words:m}],["command",{at:[1,2],carries:[],values:f,words:m}],["effect",{at:[2],carries:[],words:ye}],["event",{at:[3],carries:O,words:Ie}],["resource.live",{at:[0],carriedValues:ve,carries:O,words:x}],["resource.load",{at:[0],carries:[],words:x}],["resource.paginate",{at:[1],carries:[],words:we}],["select",{at:[2],carries:[],values:f,words:m}],["scope.while",{at:[2],carries:[],words:ge}]]),De=new Map([["activity","stateActivity"],["invalidate","resourceInvalidate"],["pending","linkSourcePending"],["policy","navigatorPolicy"],["status","commandOutcomeStatus"],["view","surfaceView"]]),Se=new Map([["call","contextCall"],["calls","contextCalls"],["scope.keyed","scopeKeyed"]]),Ce=new Map([["effect","write `ctx.effect(...)`"],["event","write `ctx.event(...)`"],["resource","write `ctx.resource.load(...)` or `ctx.resource.live(...)`"],["scope","write `ctx.scope.switch(...)`, `ctx.scope.while(...)` or `ctx.scope.each(...)`"],["lane","declare a lane and use `ctx.command(\u2026, { concurrency: lane })`"]]),xe=["@opetope/core/testing","@opetope/react/testing","@opetope/runtime/testing"],Oe=new Map([["useSelector",{messageId:"reactUseSelector",module:"@opetope/react",replacement:"useReadable"}],["FeatureBodyOf",{messageId:"featureBodyOf",module:"@opetope/runtime",replacement:"defineFeature.body"}],...["FeatureBoundary","FeatureBoundaryError","useFeature","useFeatureRetry","FeatureBoundaryProps","FeatureDemandLease","FeatureDemandResult","FeatureDemandSource","FeatureDemandState"].map(a=>[a,{messageId:"reactFeatureDemand",module:"@opetope/react/integration",replacement:"ContributionBoundary"}]),["ApplicationConditionBinding",{messageId:"runtimeInternalEntry",module:"@opetope/runtime/internal",replacement:"@opetope/runtime"}],["ApplicationExecution",{messageId:"runtimeInternalEntry",module:"@opetope/runtime/internal",replacement:"@opetope/runtime"}],["ApplicationImportBinding",{messageId:"runtimeInternalEntry",module:"@opetope/runtime/internal",replacement:"@opetope/runtime"}],["Call",{messageId:"commandName",replacement:"Command"}],["CallError",{messageId:"commandName",replacement:"CommandError"}],["CallInputArgs",{messageId:"commandInputArgs",replacement:"RunCommandArgs"}],["CommandInputArgs",{messageId:"commandInputArgs",module:xe,replacement:"RunCommandArgs"}],["CallTimeoutError",{messageId:"commandName",replacement:"CommandTimeoutError"}],["NavigatorPolicy",{messageId:"navigatorPolicy",replacement:"NavigatorCatalogue"}],["ResourceActivity",{messageId:"resourceActivity",replacement:"ResourceNodeActivity"}],["ResourceDisposer",{messageId:"resourceDisposer",replacement:"Disposer"}],["RunCallOptions",{messageId:"commandName",replacement:"RunCommandOptions"}],["externalReadable",{messageId:"fromExternal",replacement:"fromExternal"}],["runCall",{messageId:"commandName",replacement:"runCommand"}],["useCommands",{messageId:"useCommands",replacement:"useModel"}]]);function Te(a,i){const u=Oe.get(a),d=u?.module;return d===void 0||d===i||typeof d!="string"&&d.includes(i)?u:void 0}function he(a){return a.type===o.MemberExpression?a.property:a}const Ae=me({create(a){const i=a.sourceCode,u=le(i,(e,r,t)=>{a.report({...t===void 0?{}:{fix:t},messageId:r,node:e})}),d=e=>{const r=g(i,e.callee);if(r===void 0)return;const t={modifiers:Me.get(r.method),word:Se.get(r.method)};if(!(t.modifiers===void 0&&t.word===void 0))return q(i,r.fn)?t:void 0},E=(e,r)=>{const t=e.arguments[r];if(t===void 0||t.type===o.SpreadElement)return;const n=l(i,t);return n.type===o.ObjectExpression?n:void 0},T=e=>{const r=g(i,e.callee),t=r===void 0?void 0:Re.get(r.method);if(!(r===void 0||t===void 0))return D(i,r.fn,"provides",!0)?t:void 0},h=e=>{if(S(i,e.callee,"@opetope/runtime","defineCondition",!0))return E(e,1)},A=(e,r)=>{if(!r||e.computed)return;if(e.shorthand)return i.getCommentsInside(e).length>0?void 0:s=>s.replaceText(e,`filter: ${i.getText(e.value)}`);const t=i.getText(e.key),n=e.key.type===o.Literal?`${t.charAt(0)}filter${t.charAt(0)}`:"filter";return s=>s.replaceText(e.key,n)},N=(e,r,t)=>{const n=p(e);if(n===void 0)return;const s=r.get(n);if(s===void 0)return;const M=s==="scopeWhileWhen"?A(e,t):void 0;M===void 0?a.report({messageId:s,node:e.key}):a.report({fix:M,messageId:s,node:e.key})},y=(e,r,t=!1)=>{for(const n of e.properties)n.type===o.Property&&N(n,r,t)},k=(e,r)=>{const t=p(e),n=t===void 0?void 0:r.get(t);if(n===void 0)return;const s=l(i,e.value);return s.type===o.Literal&&typeof s.value=="string"?n.get(s.value):void 0},w=(e,r)=>{for(const t of e.properties){if(t.type!==o.Property)continue;const n=k(t,r);n!==void 0&&a.report({messageId:n,node:t.value})}},V=(e,r,t)=>{const n=Q(e,r),s=n===void 0?void 0:l(i,n.value);s?.type===o.ObjectExpression&&(y(s,Ee),t.carriedValues!==void 0&&w(s,t.carriedValues))},v=(e,r)=>{for(const t of r.at){const n=E(e,t);if(n!==void 0){y(n,r.words,e.arguments[t]===n),r.values!==void 0&&w(n,r.values);for(const s of r.carries)V(n,s,r)}}},R=e=>ae(i,e)||se(i,e),P=(e,r)=>r==="resourceInvalidate"?R(e.object):r==="stateActivity"?ce(i,e):r==="navigatorPolicy"?C(i,e.object):r==="surfaceView"?C(i,e.object):r==="linkSourcePending"?de(i,e.object):ue(i,e.object),_=(e,r)=>{const t=De.get(r);return t!==void 0&&P(e,t)?t:void 0},W=(e,r)=>{if(e.computed)return;const t=r==="surfaceView"?"regions":r==="linkSourcePending"?"intent":void 0;return t===void 0?void 0:n=>n.replaceText(e.property,t)},c=e=>{if(e===void 0)return;const r=e.data.to===`\`${e.data.from}\``;a.report({data:e.data,fix:e.fix,messageId:r?"entryRenamed":"entryMoved",node:e.node})},F=(e,r)=>{let t=e;for(;t.type===o.MemberExpression&&t.property.type===o.Identifier&&t.property.name!==r;)t=t.object;return t.type===o.MemberExpression?t.property:t},B=e=>{const r=g(i,e.callee);if(r===void 0)return!1;const t=r.method.split(".")[0];if(t===void 0)return!1;const n=Ce.get(t);return n===void 0||!D(i,r.fn,"own",!0)?!1:(a.report({data:{replacement:n,word:`own.${t}`},messageId:"featureOwnMember",node:F(e.callee,t)}),!0)},L=e=>{const r=fe(i.getScope(e),e);if(r===null)return;const[t]=r.defs;if(!(r.defs.length!==1||t?.type!==H.Variable)&&t.node.id.type===o.Identifier)return{definition:t,variable:r}},j=e=>{const r=L(e);if(r===void 0)return;const{definition:t,variable:n}=r;if(!oe(n,t))return{binding:t.parent.kind==="const"?"fix":"report",candidate:t.node.init??e}},b=e=>{const r=e.type===o.Identifier?j(e):{binding:"report",candidate:e};if(r===void 0)return;const t=l(i,r.candidate);return t.type===o.CallExpression&&S(i,t.callee,"@opetope/kit","createExternalSource",!0)?r.binding==="fix"&&t===r.candidate?"fix":"report":void 0},U=e=>e.parent.type===o.AssignmentExpression&&e.parent.left===e||e.parent.type===o.UpdateExpression&&e.parent.argument===e||e.parent.type===o.UnaryExpression&&e.parent.operator==="delete",K=(e,r)=>{if(r!=="publish")return!1;const t=b(e.object);return t===void 0?!1:(a.report({...t==="fix"&&!e.computed&&!U(e)?{fix:n=>n.replaceText(e.property,"set")}:{},messageId:"externalPublish",node:e.property}),!0)},$=e=>e.computed&&e.key.type===o.Literal&&typeof e.key.value=="string"?e.key.value:p(e),Y=e=>{if($(e)!=="publish"||e.parent.type!==o.ObjectPattern)return;const r=e.parent.parent;r.type!==o.VariableDeclarator||r.init===null||b(r.init)!==void 0&&a.report({messageId:"externalPublish",node:e.key})},G=e=>{if(p(e)!=="invalidate"||e.parent.type!==o.ObjectPattern)return;const r=e.parent.parent;r.type!==o.VariableDeclarator||r.init===null||R(r.init)&&a.report({messageId:"resourceInvalidate",node:e.key})};return{CallExpression(e){if(u.visitCall(e),B(e))return;const r=T(e);r!==void 0&&v(e,r);const t=h(e);t!==void 0&&y(t,be);const n=d(e);n!==void 0&&(n.word!==void 0&&a.report({messageId:n.word,node:he(e.callee)}),n.modifiers!==void 0&&v(e,n.modifiers))},ImportDeclaration(e){if(e.source.value.startsWith("@opetope/")){c(ne(i,e));for(const r of e.specifiers){if(r.type!==o.ImportSpecifier)continue;const t=ie(r),n=Te(t,e.source.value);n!==void 0&&a.report({data:{replacement:n.replacement,word:t},messageId:n.messageId,node:r.imported})}}},ExportAllDeclaration(e){c(te(e))},ExportNamedDeclaration(e){c(re(i,e))},ImportExpression(e){c(ee(i,e))},MemberExpression(e){c(X(i,e));const r=Z(e);if(r===void 0||K(e,r))return;const t=_(e,r);if(t!==void 0){const n=W(e,t);a.report({...n===void 0?{}:{fix:n},messageId:t,node:e.property})}},Property(e){Y(e),G(e)},TSImportType(e){c(J(e))},TSQualifiedName(e){c(z(i,e))},TSTypeReference(e){u.visitType(e)}}},meta:{docs:{description:"A retired word is named with its replacement; entry moves and locally proven Resource spellings are rewritten."},fixable:"code",messages:pe,schema:[],type:"problem"},name:"no-retired-vocabulary"});export{Ae as noRetiredVocabulary};
2
2
  //# sourceMappingURL=no-retired-vocabulary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-retired-vocabulary.js","sources":["../../src/rules/no-retired-vocabulary.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nimport { findProperty, propertyName } from '../ast';\nimport { isContextFunction, methodPath } from '../declaration-ingress';\nimport { isApi, isFeatureSection, localValue } from '../model-bindings';\nimport {\n isCommandOutcome,\n isResourceHook,\n isResourceValue,\n isStateActivity,\n isSurfaceValue,\n} from '../retired-vocabulary';\nimport { createRule } from '../rule';\n\ntype MessageIds =\n | 'commandLane'\n | 'commandLatest'\n | 'commandName'\n | 'commandOnce'\n | 'commandOutcomeStatus'\n | 'commandPolicy'\n | 'commandQueueBy'\n | 'conditionFrom'\n | 'contextCall'\n | 'contextCalls'\n | 'contributionWhen'\n | 'deliveryKey'\n | 'deliveryKind'\n | 'deliveryReject'\n | 'effectOnDispose'\n | 'effectSkipInitial'\n | 'effectWhen'\n | 'eventBackpressure'\n | 'fromExternal'\n | 'navigatorPolicy'\n | 'resourceActivity'\n | 'resourceDisposer'\n | 'resourceInvalidate'\n | 'runtimeInternalEntry'\n | 'scopeKeyed'\n | 'stateActivity'\n | 'useCommands';\n\n/**\n * One name a package no longer exports, and the word that carries its meaning now. D411: `module` is written where\n * the name is retired at one entry and live at another — `ApplicationConditionBinding` is still the name, on the\n * entry an author is meant to take it from. D462 took the scope off `ResourceActivity`: the name is now retired at\n * both entries it was ever written from, so asking the module would only let one of them through.\n */\ntype Retired = { readonly messageId: MessageIds; readonly module?: string; readonly replacement: string };\n/**\n * Where one node keeps its modifiers, and which retired words live there. `at` holds every position the record is\n * written in across the two surfaces — `ctx.command(run, options)` and `own.command(within, run, options)` — and\n * nothing else at those positions is an object literal, so one list answers both. `carries` names the members whose\n * own record is read in turn: a delivery policy is a record inside a record.\n */\ntype Modifiers = {\n readonly at: readonly number[];\n readonly carries: readonly string[];\n /** D411: a word of a carried record whose **value** was retired, not its key: `overflow: 'reject'` is one. */\n readonly carriedValues?: ReadonlyMap<string, ReadonlyMap<string, MessageIds>>;\n /** D459: the same fact one record higher — a word retired as the **value** of a field of this record itself. */\n readonly values?: ReadonlyMap<string, ReadonlyMap<string, MessageIds>>;\n readonly words: ReadonlyMap<string, MessageIds>;\n};\n\n/** D387, D389: the four words the options record of a command declaration and of a selection retired. */\nconst COMMAND_WORDS = new Map<string, MessageIds>([\n ['lane', 'commandLane'],\n ['once', 'commandOnce'],\n ['policy', 'commandPolicy'],\n ['queueBy', 'commandQueueBy'],\n]);\n/** D459: the one value of that record that moved — the waiting place is written as the record that names it. */\nconst COMMAND_VALUES = new Map<string, ReadonlyMap<string, MessageIds>>([\n ['concurrency', new Map<string, MessageIds>([['latest', 'commandLatest']])],\n]);\n/** D379: the three modifiers of an effect run. */\nconst EFFECT_WORDS = new Map<string, MessageIds>([\n ['onDispose', 'effectOnDispose'],\n ['skipInitial', 'effectSkipInitial'],\n ['when', 'effectWhen'],\n]);\nconst EVENT_WORDS = new Map<string, MessageIds>([['backpressure', 'eventBackpressure']]);\n/** D374: the two fields inside the record, whichever of the two words the record itself is still written under. */\nconst DELIVERY_WORDS = new Map<string, MessageIds>([\n ['key', 'deliveryKey'],\n ['kind', 'deliveryKind'],\n]);\nconst NO_WORDS = new Map<string, MessageIds>();\nconst DELIVERY = ['backpressure', 'delivery'];\n/** D411: the one field of a delivery whose value moved: a full keyed capacity answers `drop`, not `reject`. */\nconst LIVE_DELIVERY_VALUES = new Map<string, ReadonlyMap<string, MessageIds>>([\n ['overflow', new Map<string, MessageIds>([['reject', 'deliveryReject']])],\n]);\n/** D411: the words a contribution writes beside its value, on the `provides` section that declares it. */\nconst CONTRIBUTION_WORDS = new Map<string, MessageIds>([['when', 'contributionWhen']]);\nconst CONTRIBUTION_RECORDS = new Map<string, Modifiers>([\n ['pipe', { at: [2], carries: [], words: CONTRIBUTION_WORDS }],\n ['register', { at: [2], carries: [], words: CONTRIBUTION_WORDS }],\n ['slot', { at: [2], carries: [], words: CONTRIBUTION_WORDS }],\n]);\n/** D411: the record `defineCondition` takes second; the word it named its source by is the one that moved. */\nconst CONDITION_WORDS = new Map<string, MessageIds>([['from', 'conditionFrom']]);\n\nconst OPTION_RECORDS = new Map<string, Modifiers>([\n ['call', { at: [1, 2], carries: [], values: COMMAND_VALUES, words: COMMAND_WORDS }],\n ['calls', { at: [2], carries: [], values: COMMAND_VALUES, words: COMMAND_WORDS }],\n ['command', { at: [1, 2], carries: [], values: COMMAND_VALUES, words: COMMAND_WORDS }],\n ['effect', { at: [2], carries: [], words: EFFECT_WORDS }],\n ['event', { at: [3], carries: DELIVERY, words: EVENT_WORDS }],\n ['resource.live', { at: [0], carriedValues: LIVE_DELIVERY_VALUES, carries: DELIVERY, words: NO_WORDS }],\n ['select', { at: [2], carries: [], values: COMMAND_VALUES, words: COMMAND_WORDS }],\n]);\n\n/** D411, D415, D462: the members whose name is retired, each with the object it has to have been read on. */\nconst RETIRED_MEMBERS = new Map<string, MessageIds>([\n ['activity', 'stateActivity'],\n ['invalidate', 'resourceInvalidate'],\n ['policy', 'navigatorPolicy'],\n ['status', 'commandOutcomeStatus'],\n]);\n\n/** D378, D385, D388: the methods themselves, named on a declaring context of this library. */\nconst RETIRED_METHODS = new Map<string, MessageIds>([\n ['call', 'contextCall'],\n ['calls', 'contextCalls'],\n ['scope.keyed', 'scopeKeyed'],\n]);\n\n/** D380, D385, D388: the names an `@opetope/*` entry no longer exports. The module itself is the proof. */\nconst RETIRED_IMPORTS = new Map<string, Retired>([\n [\n 'ApplicationConditionBinding',\n { messageId: 'runtimeInternalEntry', module: '@opetope/runtime/internal', replacement: '@opetope/runtime' },\n ],\n /** D411, D415: the entry retired three copies, and a table that held one left two migrations unnamed. */\n [\n 'ApplicationExecution',\n { messageId: 'runtimeInternalEntry', module: '@opetope/runtime/internal', replacement: '@opetope/runtime' },\n ],\n [\n 'ApplicationImportBinding',\n { messageId: 'runtimeInternalEntry', module: '@opetope/runtime/internal', replacement: '@opetope/runtime' },\n ],\n ['Call', { messageId: 'commandName', replacement: 'Command' }],\n ['CallError', { messageId: 'commandName', replacement: 'CommandError' }],\n ['CallInputArgs', { messageId: 'commandName', replacement: 'CommandInputArgs' }],\n ['CallTimeoutError', { messageId: 'commandName', replacement: 'CommandTimeoutError' }],\n ['NavigatorPolicy', { messageId: 'navigatorPolicy', replacement: 'NavigatorCatalogue' }],\n ['ResourceActivity', { messageId: 'resourceActivity', replacement: 'ResourceNodeActivity' }],\n ['ResourceDisposer', { messageId: 'resourceDisposer', replacement: 'Disposer' }],\n ['RunCallOptions', { messageId: 'commandName', replacement: 'RunCommandOptions' }],\n ['externalReadable', { messageId: 'fromExternal', replacement: 'fromExternal' }],\n ['runCall', { messageId: 'commandName', replacement: 'runCommand' }],\n ['useCommands', { messageId: 'useCommands', replacement: 'useModel' }],\n]);\n\n/** What one call of a declaring context is, as far as this rule reads it: a retired word, retired modifiers, both. */\ntype Declared = { readonly modifiers: Modifiers | undefined; readonly word: MessageIds | undefined };\n\n/** The word a callee ends in: `keyed` of `own.scope.keyed`, or the plain name a destructured member is called by. */\nfunction calleeWord(callee: TSESTree.Node): TSESTree.Node {\n return callee.type === AST_NODE_TYPES.MemberExpression ? callee.property : callee;\n}\n\n/** The name an import carries in the module that exports it, past the local alias this file gave it. */\nfunction importedName(specifier: TSESTree.ImportSpecifier): string {\n return specifier.imported.type === AST_NODE_TYPES.Identifier ? specifier.imported.name : specifier.imported.value;\n}\n\nconst noRetiredVocabulary = createRule<[], MessageIds>({\n create(context) {\n const source = context.sourceCode;\n\n /**\n * The shape decides first and the context second: a call whose method this rule has nothing to say about never\n * pays for resolving the parameter it was written on (D309, D323).\n */\n const declaredCall = (node: TSESTree.CallExpression): Declared | undefined => {\n const named = methodPath(source, node.callee);\n\n if (named === undefined) return undefined;\n\n const declared: Declared = {\n modifiers: OPTION_RECORDS.get(named.method),\n word: RETIRED_METHODS.get(named.method),\n };\n\n if (declared.modifiers === undefined && declared.word === undefined) return undefined;\n\n return isContextFunction(source, named.fn) ? declared : undefined;\n };\n /** The record written at one of the positions this node takes its modifiers in, past the name it was given. */\n const recordAt = (node: TSESTree.CallExpression, position: number): TSESTree.ObjectExpression | undefined => {\n const argument = node.arguments[position];\n\n if (argument === undefined || argument.type === AST_NODE_TYPES.SpreadElement) return undefined;\n\n const value = localValue(source, argument);\n\n return value.type === AST_NODE_TYPES.ObjectExpression ? value : undefined;\n };\n /**\n * D411: a contribution is declared on `provides`, not on `own`, so the section that proves it is its own. The\n * shape decides first here too: nothing resolves a section for a method this rule has nothing to say about.\n */\n const contributionCall = (node: TSESTree.CallExpression): Modifiers | undefined => {\n const named = methodPath(source, node.callee);\n const modifiers = named === undefined ? undefined : CONTRIBUTION_RECORDS.get(named.method);\n\n if (named === undefined || modifiers === undefined) return undefined;\n\n return isFeatureSection(source, named.fn, 'provides', true) ? modifiers : undefined;\n };\n /** D411: `defineCondition(id, options)` is a name this package exports, so the import is what proves it. */\n const conditionRecord = (node: TSESTree.CallExpression): TSESTree.ObjectExpression | undefined => {\n if (!isApi(source, node.callee, '@opetope/runtime', 'defineCondition', true)) return undefined;\n\n return recordAt(node, 1);\n };\n const reportRecord = (record: TSESTree.ObjectExpression, words: ReadonlyMap<string, MessageIds>): void => {\n for (const property of record.properties) {\n if (property.type !== AST_NODE_TYPES.Property) continue;\n\n const name = propertyName(property);\n const messageId = name === undefined ? undefined : words.get(name);\n\n if (messageId !== undefined) context.report({ messageId, node: property.key });\n }\n };\n /** D411: the word this property was written with, where that word is a retired value of a known field. */\n const retiredValue = (\n property: TSESTree.Property,\n values: ReadonlyMap<string, ReadonlyMap<string, MessageIds>>,\n ): MessageIds | undefined => {\n const name = propertyName(property);\n const written = name === undefined ? undefined : values.get(name);\n\n if (written === undefined) return undefined;\n\n const value = localValue(source, property.value);\n\n return value.type === AST_NODE_TYPES.Literal && typeof value.value === 'string'\n ? written.get(value.value)\n : undefined;\n };\n /** D411: the value a field of a carried record was written with, where that value is the retired word. */\n const reportValues = (\n record: TSESTree.ObjectExpression,\n values: ReadonlyMap<string, ReadonlyMap<string, MessageIds>>,\n ): void => {\n for (const property of record.properties) {\n if (property.type !== AST_NODE_TYPES.Property) continue;\n\n const messageId = retiredValue(property, values);\n\n if (messageId !== undefined) context.report({ messageId, node: property.value });\n }\n };\n const reportCarried = (record: TSESTree.ObjectExpression, carrier: string, modifiers: Modifiers): void => {\n const property = findProperty(record, carrier);\n const carried = property === undefined ? undefined : localValue(source, property.value);\n\n if (carried?.type !== AST_NODE_TYPES.ObjectExpression) return;\n\n reportRecord(carried, DELIVERY_WORDS);\n\n if (modifiers.carriedValues !== undefined) reportValues(carried, modifiers.carriedValues);\n };\n const reportModifiers = (node: TSESTree.CallExpression, modifiers: Modifiers): void => {\n for (const position of modifiers.at) {\n const record = recordAt(node, position);\n\n if (record === undefined) continue;\n\n reportRecord(record, modifiers.words);\n\n if (modifiers.values !== undefined) reportValues(record, modifiers.values);\n\n for (const carrier of modifiers.carries) reportCarried(record, carrier, modifiers);\n }\n };\n /** Both objects that used to answer `invalidate`: the Resource itself, and the record `useResource` builds. */\n const holdsVerbs = (node: TSESTree.Node): boolean => isResourceValue(source, node) || isResourceHook(source, node);\n /** The object each retired member has to be read on, asked only once the name has already matched. */\n const memberOwner = (node: TSESTree.MemberExpression, messageId: MessageIds): boolean => {\n if (messageId === 'resourceInvalidate') return holdsVerbs(node.object);\n\n if (messageId === 'stateActivity') return isStateActivity(source, node);\n\n if (messageId === 'navigatorPolicy') return isSurfaceValue(source, node.object);\n\n return isCommandOutcome(source, node.object);\n };\n /**\n * The four members this rule reads off a value it can resolve (D415 added `surface.policy`, which the message\n * of `NavigatorPolicy` already named and the rule did not report). The name decides first and the resolution\n * second, so a member this rule has nothing to say about never pays for the object it was read on (D309, D323).\n */\n const retiredMember = (node: TSESTree.MemberExpression, name: string): MessageIds | undefined => {\n const messageId = RETIRED_MEMBERS.get(name);\n\n return messageId !== undefined && memberOwner(node, messageId) ? messageId : undefined;\n };\n\n return {\n CallExpression(node): void {\n const contribution = contributionCall(node);\n\n if (contribution !== undefined) reportModifiers(node, contribution);\n\n const condition = conditionRecord(node);\n\n if (condition !== undefined) reportRecord(condition, CONDITION_WORDS);\n\n const declared = declaredCall(node);\n\n if (declared === undefined) return;\n\n if (declared.word !== undefined) context.report({ messageId: declared.word, node: calleeWord(node.callee) });\n\n if (declared.modifiers !== undefined) reportModifiers(node, declared.modifiers);\n },\n ImportDeclaration(node): void {\n if (!node.source.value.startsWith('@opetope/')) return;\n\n for (const specifier of node.specifiers) {\n if (specifier.type !== AST_NODE_TYPES.ImportSpecifier) continue;\n\n const word = importedName(specifier);\n const retired = RETIRED_IMPORTS.get(word);\n\n if (retired !== undefined && (retired.module === undefined || retired.module === node.source.value)) {\n context.report({\n data: { replacement: retired.replacement, word },\n messageId: retired.messageId,\n node: specifier.imported,\n });\n }\n }\n },\n MemberExpression(node): void {\n if (node.computed || node.property.type !== AST_NODE_TYPES.Identifier) return;\n\n const messageId = retiredMember(node, node.property.name);\n\n if (messageId !== undefined) context.report({ messageId, node: node.property });\n },\n Property(node): void {\n if (propertyName(node) !== 'invalidate' || node.parent.type !== AST_NODE_TYPES.ObjectPattern) return;\n\n const declarator = node.parent.parent;\n\n if (declarator.type !== AST_NODE_TYPES.VariableDeclarator || declarator.init === null) return;\n\n if (holdsVerbs(declarator.init)) context.report({ messageId: 'resourceInvalidate', node: node.key });\n },\n };\n },\n meta: {\n docs: {\n description:\n 'A word the D365–D411 wave or a decision after it retired is named with its replacement, never rewritten.',\n },\n messages: {\n commandLane:\n '`lane` is now a member of `concurrency`: write `concurrency: lane`, `concurrency: { by, lane }` for a keyed queue, or `concurrency: { lane, pending: \"latest\" }` where `policy: \"latest\"` stood beside it. Which of the three this record meant is in what it wrote together, so nothing here is rewritten for you (D387).',\n commandLatest:\n '`concurrency: \"latest\"` is now `concurrency: { pending: \"latest\" }`, and `{ lane, pending: \"latest\" }` where the queue is shared. The word named the input that wins and never named what it wins, so the place is written out: one waiting slot at the end of the lane, taken by a newer input while the body in flight is left to finish. Nothing else about the policy moved (D459).',\n commandName:\n '`{{word}}` is now `{{replacement}}`: one word for a command, everywhere. The primitive was the last place the vocabulary still said `Call`, while the hook was already `useCommand` and the outcome `CommandOutcome`. There is no alias (D385).',\n commandOnce:\n '`once` is now `memoize`: it caches a successful result, it does not stop after one run. `addEventListener(type, handler, { once: true })` is what the platform means by the word, and it is not what this option ever did (D389).',\n commandOutcomeStatus:\n '`status` is now `kind` on a `CommandOutcome`: one word for the discriminant of a settled answer, the one `ResourceState`, `ResourceOperationOutcome`, `ResourceCommitOutcome`, `PaginationOutcome` and a screen result already carry. The three branches are unchanged — `{ kind: \"ok\", value }`, `{ kind: \"failed\", error }`, `{ kind: \"cancelled\", reason }` (D411).',\n commandPolicy:\n '`policy` is now `concurrency`: one word for the order the runs take, written as `queue`, `parallel`, a lane or `{ pending: \"latest\" }`. Where `queueBy` or `lane` stood beside it the three collapse into one value — `{ by }`, `{ by, lane }` or `{ lane, pending: \"latest\" }` — so the shape depends on which of them this record wrote, and that is why this rule names the word instead of rewriting it (D387, D459).',\n commandQueueBy:\n '`queueBy` is now a member of `concurrency`: write `concurrency: { by: input => key }`, or `concurrency: { by, lane }` where a lane stood beside it (D387).',\n conditionFrom:\n \"`from` of `defineCondition` is now `source`: write `defineCondition(id, { select, source })`. One word names the dependency a node reads — `resource.load({ source })` and `attach(source)` already say it, and this node's own refusals said `Condition source` about the field they called `from` (D410, D411).\",\n contextCall:\n '`call` is now `command`: `ctx.command(run, options?)` in a model, `own.command(within, run, options?)` in a feature. The body takes one argument, its context, and reads the declared input off it as `input` — and `Input` is inferred from every position of the call except the body, so it is written in the cheapest that fits: the result type of a model factory names it in the literal it returns, an annotated option names it (`dedupe: (deposit: Deposit) => …`), a constant names it (`const refill: Command<Refill, void> = ctx.command(…)`), and the annotation of that context — `({ input, update }: ModelCommandContext<Deposit>)` in a model, `({ input, source }: FeatureCommandContext<typeof within, Deposit>)` in a feature — is what is left; a feature has the last two only. `command<Deposit>(…)` is not a position: it pins `Output` to its default (D385, D386, D444, D455).',\n contextCalls:\n '`ctx.calls` and `own.calls` are now `ctx.select` and `own.select`: declaring a body and selecting a command a dependency already declares are two mechanisms, so they are two words. `select(source, \"name\")` answers one command and `select(source, [\"a\", \"b\"])` a record of them (D388).',\n contributionWhen:\n '`when` of a contribution is now `enabled`: write `slot(target, value, { enabled })`, and the same at `pipe` and `register`. A truth the runtime reads while the node exists is `enabled`, at a contribution and at a Resource alike; `when` names the other mechanism — the declared `Condition`s of `defineFeature({ when })`, which the application resolves before anything exists. `scope.while` keeps its own `when` (D378, D411).',\n deliveryKey:\n 'Inside a delivery record `key` is now `by`: `{ pending: \"latest\", by }` keeps one waiting place per key instead of one for the whole node (D374).',\n deliveryKind:\n 'Inside a delivery record `kind` is now `pending`: `kind: \"latest\"` is `pending: \"latest\"`, and `kind: \"queue\"` is `pending: \"all\"` — the backlog only an event has. The discriminant moved because with one dimension shared by both nodes, the discriminant is that dimension (D374).',\n deliveryReject:\n '`overflow: \"reject\"` is now `overflow: \"drop\"`: one word at both nodes for «the new one does not enter and `emit` answers `false`». `\"flush-oldest\"` is unchanged and still the default of a keyed delivery (D369, D411).',\n effectOnDispose:\n '`onDispose` is now `finalize`: an effect has two releases — the disposer a run returns, and the one the node itself gets once — and an `on*` prefix did not tell them apart. No word of the authoring vocabulary carries that prefix any more (D379).',\n effectSkipInitial:\n '`skipInitial` is now `initial`, and the polarity is inverted: `skipInitial: true` is `initial: false`, and `initial` defaults to `true`. Both words are booleans, so carrying the value across unchanged compiles and means the opposite — which is why this rule names it and leaves the rewrite to you (D379).',\n effectWhen:\n '`when` at an effect is now `filter` or `initial`, and which one depends on what the predicate asks. A predicate that selects values is `filter: (current, previous) => …`; a predicate whose whole job is to refuse the first run — `(_current, previous) => previous !== undefined` — is `initial: false`. This rule does not guess between them. The word `when` is untouched at a feature and at `scope.while`; at a contribution it is now `enabled` (D379, D411).',\n eventBackpressure:\n '`backpressure` is now `delivery`: one word at both nodes that admit a producer. Write `delivery: \"latest\"` for one waiting place that the newest payload takes, or the record — `{ pending, by }`, `{ pending, capacity, overflow }` — for the rest (D374).',\n fromExternal:\n '`externalReadable` is now `fromExternal`: `from*` names where a `Readable` comes from, beside `fromMaybe`. The old name was built from its result, which every word of that module already answers (D380).',\n navigatorPolicy:\n '`NavigatorPolicy` is now `NavigatorCatalogue`, and `surface.policy` is now `surface.catalogue`: this is four callbacks a navigator asks, and D291 made a policy data — a word when it has no parameters, a record when it has them (D411).',\n resourceActivity:\n '`ResourceActivity` is retired at both entries that spelled it. From `@opetope/devtools` it is `ResourceNodeActivity` (D411). From `@opetope/core` it is gone: a state answers what failed and what is working in two fields of its own, so read `state.failure` and `state.pending` instead of a union that flattened them (D462).',\n resourceDisposer:\n '`ResourceDisposer` is now `Disposer`: one name for `() => Awaitable<void>`, which three of them used to spell — `Disposer`, `ResourceDisposer` and `FeatureDisposer`. It travels on `@opetope/core/internal` beside `Awaitable` (D411).',\n resourceInvalidate:\n '`invalidate()` is now `reset()`: it clears the whole cache, drops the current data, opens a new epoch and restarts every configured channel. Everywhere else `invalidate` means «mark stale, keep the data», so the old name promised the opposite of what the verb does; it now names no operation of a Resource at all (D373).',\n runtimeInternalEntry:\n '`{{word}}` is published by `{{replacement}}`: import it from there. Three names were published by both entries and every consumer took the internal copy, so the copies are gone and the names are not (D411, D415).',\n scopeKeyed:\n '`scope.keyed(source, open, { key })` is now `scope.each(source, key, open)`: `each` says what the node does, one child per element, and the key is required — so it stands between the list it identifies and the child it opens. The trailing record is gone, which makes this a move and not only a rename (D378).',\n stateActivity:\n 'No `ResourceState` carries `activity` any more: the union said what a channel was doing and what had failed in one word. Read `state.failure` — `undefined` is «nothing failed», and otherwise `channel` names the channel that died and `error` carries its failure — and `state.pending` for the channel with work in flight. Both are declared on every member, so neither needs a narrowing by `kind` first (D462).',\n useCommands:\n '`useCommands` is gone: a record of command consumers comes from `useModel(Declaration, select)`, which has an owner and a lifetime. One command is still `useCommand` (D388).',\n },\n schema: [],\n type: 'problem',\n },\n name: 'no-retired-vocabulary',\n});\n\nexport { noRetiredVocabulary };\n"],"names":["COMMAND_WORDS","COMMAND_VALUES","EFFECT_WORDS","EVENT_WORDS","DELIVERY_WORDS","NO_WORDS","DELIVERY","LIVE_DELIVERY_VALUES","CONTRIBUTION_WORDS","CONTRIBUTION_RECORDS","CONDITION_WORDS","OPTION_RECORDS","RETIRED_MEMBERS","RETIRED_METHODS","RETIRED_IMPORTS","calleeWord","callee","AST_NODE_TYPES","importedName","specifier","noRetiredVocabulary","createRule","context","source","declaredCall","node","named","methodPath","declared","isContextFunction","recordAt","position","argument","value","localValue","contributionCall","modifiers","isFeatureSection","conditionRecord","isApi","reportRecord","record","words","property","name","propertyName","messageId","retiredValue","values","written","reportValues","reportCarried","carrier","findProperty","carried","reportModifiers","holdsVerbs","isResourceValue","isResourceHook","memberOwner","isStateActivity","isSurfaceValue","isCommandOutcome","retiredMember","contribution","condition","word","retired","declarator"],"mappings":"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EAAapB,CAAI,IAAM,cAAgBA,EAAK,OAAO,OAASR,EAAe,cAAe,OAE9F,MAAMmD,EAAa3C,EAAK,OAAO,OAE3B2C,EAAW,OAASnD,EAAe,oBAAsBmD,EAAW,OAAS,MAE7EZ,EAAWY,EAAW,IAAI,GAAG9C,EAAQ,OAAO,CAAE,UAAW,qBAAsB,KAAMG,EAAK,IAAK,CACrG,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YACE,+GACH,EACD,SAAU,CACR,YACE,6TACF,cACE,0XACF,YACE,kPACF,YACE,oOACF,qBACE,8WACF,cACE,saACF,eACE,6JACF,cACE,yTACF,YACE,04BACF,aACE,8RACF,iBACE,+aACF,YACE,oJACF,aACE,8RACF,eACE,kOACF,gBACE,kQACF,kBACE,wTACF,WACE,wdACF,kBACE,wQACF,aACE,6MACF,gBACE,kPACF,iBACE,qUACF,iBACE,+OACF,mBACE,yUACF,qBACE,uNACF,WACE,4TACF,cACE,0aACF,YACE,+KACH,EACD,OAAQ,CAAA,EACR,KAAM,SACP,EACD,KAAM,uBACP,CAAA"}
1
+ {"version":3,"file":"no-retired-vocabulary.js","sources":["../../src/rules/no-retired-vocabulary.ts"],"sourcesContent":["import { DefinitionType } from '@typescript-eslint/scope-manager';\nimport { AST_NODE_TYPES } from '@typescript-eslint/types';\nimport type { TSESTree } from '@typescript-eslint/types';\n\nimport { findProperty, propertyName } from '../ast';\nimport { isContextFunction, methodPath } from '../declaration-ingress';\nimport type { EntryMove } from '../entry-moves';\nimport {\n dynamicMove,\n importMove,\n namespaceMemberMove,\n namespaceTypeMove,\n reexportMove,\n starMove,\n staticMemberName,\n typeImportMove,\n} from '../entry-moves';\nimport { hasWritesBeyondDefinition, importName, isApi, isFeatureSection, localValue } from '../model-bindings';\nimport {\n isCommandOutcome,\n isLinkSourceValue,\n isResourceHook,\n isResourceValue,\n isStateActivity,\n isSurfaceValue,\n} from '../retired-vocabulary';\nimport { RETIRED_MESSAGES } from '../retired-vocabulary-messages';\nimport type { MessageIds } from '../retired-vocabulary-messages';\nimport { createResourceVocabulary } from '../resource-vocabulary';\nimport { createRule, findVariable } from '../rule';\nimport type { ReportFixFunction } from '../rule';\n\n/**\n * One name a package no longer exports, and the word that carries its meaning now. D411: `module` is written where\n * the name is retired at one entry and live at another — `ApplicationConditionBinding` is still the name, on the\n * entry an author is meant to take it from. D462 took the scope off `ResourceActivity`: the name is now retired at\n * both entries it was ever written from, so asking the module would only let one of them through.\n */\ntype Retired = { readonly messageId: MessageIds; readonly module?: Modules; readonly replacement: string };\ntype Modules = string | readonly string[];\n/**\n * Where one node keeps its modifiers, and which retired words live there. `at` holds every position the record is\n * written in across the two surfaces — `ctx.command(run, options)` and `own.command(within, run, options)` — and\n * nothing else at those positions is an object literal, so one list answers both. `carries` names the members whose\n * own record is read in turn: a delivery policy is a record inside a record.\n */\ntype Modifiers = {\n readonly at: readonly number[];\n readonly carries: readonly string[];\n /** D411: a word of a carried record whose **value** was retired, not its key: `overflow: 'reject'` is one. */\n readonly carriedValues?: ReadonlyMap<string, ReadonlyMap<string, MessageIds>>;\n /** D459: the same fact one record higher — a word retired as the **value** of a field of this record itself. */\n readonly values?: ReadonlyMap<string, ReadonlyMap<string, MessageIds>>;\n readonly words: ReadonlyMap<string, MessageIds>;\n};\n\n/** D387, D389: the four words the options record of a command declaration and of a selection retired. */\nconst COMMAND_WORDS = new Map<string, MessageIds>([\n ['lane', 'commandLane'],\n ['once', 'commandOnce'],\n ['policy', 'commandPolicy'],\n ['queueBy', 'commandQueueBy'],\n]);\n/** D459: the one value of that record that moved — the waiting place is written as the record that names it. */\nconst COMMAND_VALUES = new Map<string, ReadonlyMap<string, MessageIds>>([\n ['concurrency', new Map<string, MessageIds>([['latest', 'commandLatest']])],\n]);\n/** D379: the three modifiers of an effect run. */\nconst EFFECT_WORDS = new Map<string, MessageIds>([\n ['onDispose', 'effectOnDispose'],\n ['skipInitial', 'effectSkipInitial'],\n ['when', 'effectWhen'],\n]);\nconst WHILE_WORDS = new Map<string, MessageIds>([['when', 'scopeWhileWhen']]);\nconst EVENT_WORDS = new Map<string, MessageIds>([['backpressure', 'eventBackpressure']]);\n/** D374: the two fields inside the record, whichever of the two words the record itself is still written under. */\nconst DELIVERY_WORDS = new Map<string, MessageIds>([\n ['key', 'deliveryKey'],\n ['kind', 'deliveryKind'],\n]);\n/** D486: pagination left the declaration record; it is `resource.paginate(resource, { cursor, load, merge })`. */\nconst DECLARATION_WORDS = new Map<string, MessageIds>([['pagination', 'resourcePagination']]);\n/** D486: the selector of the next cursor is `cursor`, so alphabetical order is the order TypeScript infers in. */\nconst PAGINATE_WORDS = new Map<string, MessageIds>([['nextCursor', 'paginateNextCursor']]);\nconst DELIVERY = ['backpressure', 'delivery'];\n/** D411: the one field of a delivery whose value moved: a full keyed capacity answers `drop`, not `reject`. */\nconst LIVE_DELIVERY_VALUES = new Map<string, ReadonlyMap<string, MessageIds>>([\n ['overflow', new Map<string, MessageIds>([['reject', 'deliveryReject']])],\n]);\n/** D411: the words a contribution writes beside its value, on the `provides` section that declares it. */\nconst CONTRIBUTION_WORDS = new Map<string, MessageIds>([['when', 'contributionWhen']]);\nconst CONTRIBUTION_RECORDS = new Map<string, Modifiers>([\n ['pipe', { at: [2], carries: [], words: CONTRIBUTION_WORDS }],\n ['register', { at: [2], carries: [], words: CONTRIBUTION_WORDS }],\n ['slot', { at: [2], carries: [], words: CONTRIBUTION_WORDS }],\n]);\n/** D411: the record `defineCondition` takes second; the word it named its source by is the one that moved. */\nconst CONDITION_WORDS = new Map<string, MessageIds>([['from', 'conditionFrom']]);\n\nconst OPTION_RECORDS = new Map<string, Modifiers>([\n ['call', { at: [1, 2], carries: [], values: COMMAND_VALUES, words: COMMAND_WORDS }],\n ['calls', { at: [2], carries: [], values: COMMAND_VALUES, words: COMMAND_WORDS }],\n ['command', { at: [1, 2], carries: [], values: COMMAND_VALUES, words: COMMAND_WORDS }],\n ['effect', { at: [2], carries: [], words: EFFECT_WORDS }],\n ['event', { at: [3], carries: DELIVERY, words: EVENT_WORDS }],\n ['resource.live', { at: [0], carriedValues: LIVE_DELIVERY_VALUES, carries: DELIVERY, words: DECLARATION_WORDS }],\n ['resource.load', { at: [0], carries: [], words: DECLARATION_WORDS }],\n ['resource.paginate', { at: [1], carries: [], words: PAGINATE_WORDS }],\n ['select', { at: [2], carries: [], values: COMMAND_VALUES, words: COMMAND_WORDS }],\n ['scope.while', { at: [2], carries: [], words: WHILE_WORDS }],\n]);\n\n/** D411, D415, D462: the members whose name is retired, each with the object it has to have been read on. */\nconst RETIRED_MEMBERS = new Map<string, MessageIds>([\n ['activity', 'stateActivity'],\n ['invalidate', 'resourceInvalidate'],\n ['pending', 'linkSourcePending'],\n ['policy', 'navigatorPolicy'],\n ['status', 'commandOutcomeStatus'],\n ['view', 'surfaceView'],\n]);\n\n/** D378, D385, D388: the methods themselves, named on a declaring context of this library. */\nconst RETIRED_METHODS = new Map<string, MessageIds>([\n ['call', 'contextCall'],\n ['calls', 'contextCalls'],\n ['scope.keyed', 'scopeKeyed'],\n]);\n\n/** D380, D385, D388: the names an `@opetope/*` entry no longer exports. The module itself is the proof. */\nconst FEATURE_OWN_REMOVED = new Map<string, string>([\n ['effect', 'write `ctx.effect(...)`'],\n ['event', 'write `ctx.event(...)`'],\n ['resource', 'write `ctx.resource.load(...)` or `ctx.resource.live(...)`'],\n ['scope', 'write `ctx.scope.switch(...)`, `ctx.scope.while(...)` or `ctx.scope.each(...)`'],\n ['lane', 'declare a lane and use `ctx.command(…, { concurrency: lane })`'],\n]);\n\n/** D517: the entries `CommandInputArgs` left; `@opetope/core/internal` still names it for the library itself. */\nconst TESTING_ENTRIES = ['@opetope/core/testing', '@opetope/react/testing', '@opetope/runtime/testing'];\nconst RETIRED_IMPORTS = new Map<string, Retired>([\n ['useSelector', { messageId: 'reactUseSelector', module: '@opetope/react', replacement: 'useReadable' }],\n /** D542: a body written through `defineFeature.body` is typed from its header and needs no annotation. */\n ['FeatureBodyOf', { messageId: 'featureBodyOf', module: '@opetope/runtime', replacement: 'defineFeature.body' }],\n ...[\n 'FeatureBoundary',\n 'FeatureBoundaryError',\n 'useFeature',\n 'useFeatureRetry',\n 'FeatureBoundaryProps',\n 'FeatureDemandLease',\n 'FeatureDemandResult',\n 'FeatureDemandSource',\n 'FeatureDemandState',\n ].map(\n name =>\n [\n name,\n {\n messageId: 'reactFeatureDemand' as const,\n module: '@opetope/react/integration',\n replacement: 'ContributionBoundary',\n },\n ] as const,\n ),\n [\n 'ApplicationConditionBinding',\n { messageId: 'runtimeInternalEntry', module: '@opetope/runtime/internal', replacement: '@opetope/runtime' },\n ],\n /** D411, D415: the entry retired three copies, and a table that held one left two migrations unnamed. */\n [\n 'ApplicationExecution',\n { messageId: 'runtimeInternalEntry', module: '@opetope/runtime/internal', replacement: '@opetope/runtime' },\n ],\n [\n 'ApplicationImportBinding',\n { messageId: 'runtimeInternalEntry', module: '@opetope/runtime/internal', replacement: '@opetope/runtime' },\n ],\n ['Call', { messageId: 'commandName', replacement: 'Command' }],\n ['CallError', { messageId: 'commandName', replacement: 'CommandError' }],\n /** D517: the input tuple of a command execution left the testing entries; the wrappers it served name others. */\n ['CallInputArgs', { messageId: 'commandInputArgs', replacement: 'RunCommandArgs' }],\n ['CommandInputArgs', { messageId: 'commandInputArgs', module: TESTING_ENTRIES, replacement: 'RunCommandArgs' }],\n ['CallTimeoutError', { messageId: 'commandName', replacement: 'CommandTimeoutError' }],\n ['NavigatorPolicy', { messageId: 'navigatorPolicy', replacement: 'NavigatorCatalogue' }],\n ['ResourceActivity', { messageId: 'resourceActivity', replacement: 'ResourceNodeActivity' }],\n ['ResourceDisposer', { messageId: 'resourceDisposer', replacement: 'Disposer' }],\n ['RunCallOptions', { messageId: 'commandName', replacement: 'RunCommandOptions' }],\n ['externalReadable', { messageId: 'fromExternal', replacement: 'fromExternal' }],\n ['runCall', { messageId: 'commandName', replacement: 'runCommand' }],\n ['useCommands', { messageId: 'useCommands', replacement: 'useModel' }],\n]);\n\n/** The retired entry of a name imported from `from`, when the name is retired at that entry. */\nfunction retiredImport(word: string, from: string): Retired | undefined {\n const retired = RETIRED_IMPORTS.get(word);\n const module = retired?.module;\n\n return module === undefined || module === from || (typeof module !== 'string' && module.includes(from))\n ? retired\n : undefined;\n}\n\n/** What one call of a declaring context is, as far as this rule reads it: a retired word, retired modifiers, both. */\ntype Declared = { readonly modifiers: Modifiers | undefined; readonly word: MessageIds | undefined };\n\n/** The word a callee ends in: `keyed` of `own.scope.keyed`, or the plain name a destructured member is called by. */\nfunction calleeWord(callee: TSESTree.Node): TSESTree.Node {\n return callee.type === AST_NODE_TYPES.MemberExpression ? callee.property : callee;\n}\n\nconst noRetiredVocabulary = createRule<[], MessageIds>({\n create(context) {\n const source = context.sourceCode;\n const resourceVocabulary = createResourceVocabulary(source, (node, messageId, fix) => {\n context.report({ ...(fix === undefined ? {} : { fix }), messageId, node });\n });\n\n /**\n * The shape decides first and the context second: a call whose method this rule has nothing to say about never\n * pays for resolving the parameter it was written on (D309, D323).\n */\n const declaredCall = (node: TSESTree.CallExpression): Declared | undefined => {\n const named = methodPath(source, node.callee);\n\n if (named === undefined) return undefined;\n\n const declared: Declared = {\n modifiers: OPTION_RECORDS.get(named.method),\n word: RETIRED_METHODS.get(named.method),\n };\n\n if (declared.modifiers === undefined && declared.word === undefined) return undefined;\n\n return isContextFunction(source, named.fn) ? declared : undefined;\n };\n /** The record written at one of the positions this node takes its modifiers in, past the name it was given. */\n const recordAt = (node: TSESTree.CallExpression, position: number): TSESTree.ObjectExpression | undefined => {\n const argument = node.arguments[position];\n\n if (argument === undefined || argument.type === AST_NODE_TYPES.SpreadElement) return undefined;\n\n const value = localValue(source, argument);\n\n return value.type === AST_NODE_TYPES.ObjectExpression ? value : undefined;\n };\n /**\n * D411: a contribution is declared on `provides`, not on `own`, so the section that proves it is its own. The\n * shape decides first here too: nothing resolves a section for a method this rule has nothing to say about.\n */\n const contributionCall = (node: TSESTree.CallExpression): Modifiers | undefined => {\n const named = methodPath(source, node.callee);\n const modifiers = named === undefined ? undefined : CONTRIBUTION_RECORDS.get(named.method);\n\n if (named === undefined || modifiers === undefined) return undefined;\n\n return isFeatureSection(source, named.fn, 'provides', true) ? modifiers : undefined;\n };\n /** D411: `defineCondition(id, options)` is a name this package exports, so the import is what proves it. */\n const conditionRecord = (node: TSESTree.CallExpression): TSESTree.ObjectExpression | undefined => {\n if (!isApi(source, node.callee, '@opetope/runtime', 'defineCondition', true)) return undefined;\n\n return recordAt(node, 1);\n };\n const whileFix = (property: TSESTree.Property, direct: boolean): ReportFixFunction | undefined => {\n if (!direct || property.computed) return undefined;\n if (property.shorthand) {\n if (source.getCommentsInside(property).length > 0) return undefined;\n return fixer => fixer.replaceText(property, `filter: ${source.getText(property.value)}`);\n }\n const written = source.getText(property.key);\n const next =\n property.key.type === AST_NODE_TYPES.Literal ? `${written.charAt(0)}filter${written.charAt(0)}` : 'filter';\n return fixer => fixer.replaceText(property.key, next);\n };\n const reportProperty = (\n property: TSESTree.Property,\n words: ReadonlyMap<string, MessageIds>,\n direct: boolean,\n ): void => {\n const name = propertyName(property);\n if (name === undefined) return;\n const messageId = words.get(name);\n if (messageId === undefined) return;\n const fix = messageId === 'scopeWhileWhen' ? whileFix(property, direct) : undefined;\n if (fix === undefined) context.report({ messageId, node: property.key });\n else context.report({ fix, messageId, node: property.key });\n };\n const reportRecord = (\n record: TSESTree.ObjectExpression,\n words: ReadonlyMap<string, MessageIds>,\n direct = false,\n ): void => {\n for (const property of record.properties)\n if (property.type === AST_NODE_TYPES.Property) reportProperty(property, words, direct);\n };\n /** D411: the word this property was written with, where that word is a retired value of a known field. */\n const retiredValue = (\n property: TSESTree.Property,\n values: ReadonlyMap<string, ReadonlyMap<string, MessageIds>>,\n ): MessageIds | undefined => {\n const name = propertyName(property);\n const written = name === undefined ? undefined : values.get(name);\n\n if (written === undefined) return undefined;\n\n const value = localValue(source, property.value);\n\n return value.type === AST_NODE_TYPES.Literal && typeof value.value === 'string'\n ? written.get(value.value)\n : undefined;\n };\n /** D411: the value a field of a carried record was written with, where that value is the retired word. */\n const reportValues = (\n record: TSESTree.ObjectExpression,\n values: ReadonlyMap<string, ReadonlyMap<string, MessageIds>>,\n ): void => {\n for (const property of record.properties) {\n if (property.type !== AST_NODE_TYPES.Property) continue;\n\n const messageId = retiredValue(property, values);\n\n if (messageId !== undefined) context.report({ messageId, node: property.value });\n }\n };\n const reportCarried = (record: TSESTree.ObjectExpression, carrier: string, modifiers: Modifiers): void => {\n const property = findProperty(record, carrier);\n const carried = property === undefined ? undefined : localValue(source, property.value);\n\n if (carried?.type !== AST_NODE_TYPES.ObjectExpression) return;\n\n reportRecord(carried, DELIVERY_WORDS);\n\n if (modifiers.carriedValues !== undefined) reportValues(carried, modifiers.carriedValues);\n };\n const reportModifiers = (node: TSESTree.CallExpression, modifiers: Modifiers): void => {\n for (const position of modifiers.at) {\n const record = recordAt(node, position);\n\n if (record === undefined) continue;\n\n reportRecord(record, modifiers.words, node.arguments[position] === record);\n\n if (modifiers.values !== undefined) reportValues(record, modifiers.values);\n\n for (const carrier of modifiers.carries) reportCarried(record, carrier, modifiers);\n }\n };\n /** Both objects that used to answer `invalidate`: the Resource itself, and the record `useResource` builds. */\n const holdsVerbs = (node: TSESTree.Node): boolean => isResourceValue(source, node) || isResourceHook(source, node);\n /** The object each retired member has to be read on, asked only once the name has already matched. */\n const memberOwner = (node: TSESTree.MemberExpression, messageId: MessageIds): boolean => {\n if (messageId === 'resourceInvalidate') return holdsVerbs(node.object);\n\n if (messageId === 'stateActivity') return isStateActivity(source, node);\n\n if (messageId === 'navigatorPolicy') return isSurfaceValue(source, node.object);\n\n if (messageId === 'surfaceView') return isSurfaceValue(source, node.object);\n\n if (messageId === 'linkSourcePending') return isLinkSourceValue(source, node.object);\n\n return isCommandOutcome(source, node.object);\n };\n /**\n * The four members this rule reads off a value it can resolve (D415 added `surface.policy`, which the message\n * of `NavigatorPolicy` already named and the rule did not report). The name decides first and the resolution\n * second, so a member this rule has nothing to say about never pays for the object it was read on (D309, D323).\n */\n const retiredMember = (node: TSESTree.MemberExpression, name: string): MessageIds | undefined => {\n const messageId = RETIRED_MEMBERS.get(name);\n\n return messageId !== undefined && memberOwner(node, messageId) ? messageId : undefined;\n };\n const retiredMemberFix = (\n node: TSESTree.MemberExpression,\n messageId: MessageIds,\n ): ReportFixFunction | undefined => {\n if (node.computed) return undefined;\n\n const replacement =\n messageId === 'surfaceView' ? 'regions' : messageId === 'linkSourcePending' ? 'intent' : undefined;\n\n return replacement === undefined ? undefined : fixer => fixer.replaceText(node.property, replacement);\n };\n\n /** Each migration report has a local edit; no fix reaches into later references or across another rule's span. */\n const reportMove = (move: EntryMove | undefined): void => {\n if (move === undefined) return;\n const sameEntry = move.data['to'] === `\\`${move.data['from']}\\``;\n context.report({\n data: move.data,\n fix: move.fix,\n messageId: sameEntry ? 'entryRenamed' : 'entryMoved',\n node: move.node,\n });\n };\n\n const featureWord = (callee: TSESTree.Node, root: string): TSESTree.Node => {\n let word = callee;\n while (\n word.type === AST_NODE_TYPES.MemberExpression &&\n word.property.type === AST_NODE_TYPES.Identifier &&\n word.property.name !== root\n )\n word = word.object;\n return word.type === AST_NODE_TYPES.MemberExpression ? word.property : word;\n };\n /** D501: report only a removed method of Opetope Feature own, including destructured aliases. */\n const reportRemovedFeatureOwn = (node: TSESTree.CallExpression): boolean => {\n const named = methodPath(source, node.callee);\n if (named === undefined) return false;\n const root = named.method.split('.')[0];\n if (root === undefined) return false;\n const replacement = FEATURE_OWN_REMOVED.get(root);\n if (replacement === undefined || !isFeatureSection(source, named.fn, 'own', true)) return false;\n context.report({\n data: { replacement, word: `own.${root}` },\n messageId: 'featureOwnMember',\n node: featureWord(node.callee, root),\n });\n return true;\n };\n\n /** Resolve one lexical variable definition before considering its creator. */\n const kitVariable = (node: TSESTree.Identifier) => {\n const variable = findVariable(source.getScope(node), node);\n if (variable === null) return undefined;\n const [definition] = variable.defs;\n if (variable.defs.length !== 1 || definition?.type !== DefinitionType.Variable) return undefined;\n if (definition.node.id.type !== AST_NODE_TYPES.Identifier) return undefined;\n return { definition, variable };\n };\n\n /** A later write makes even a diagnostic speculative: the receiver may no longer be a Kit source. */\n const kitBinding = (node: TSESTree.Identifier) => {\n const resolved = kitVariable(node);\n if (resolved === undefined) return undefined;\n const { definition, variable } = resolved;\n if (hasWritesBeyondDefinition(variable, definition)) return undefined;\n return {\n binding: definition.parent.kind === 'const' ? 'fix' : 'report',\n candidate: definition.node.init ?? node,\n } as const;\n };\n\n /** Same-file creator provenance determines whether `publish` is safe to rewrite or only worth reporting. */\n const kitSource = (node: TSESTree.Node): 'fix' | 'report' | undefined => {\n const resolved =\n node.type === AST_NODE_TYPES.Identifier ? kitBinding(node) : { binding: 'report', candidate: node };\n if (resolved === undefined) return undefined;\n const creator = localValue(source, resolved.candidate);\n return creator.type === AST_NODE_TYPES.CallExpression &&\n isApi(source, creator.callee, '@opetope/kit', 'createExternalSource', true)\n ? resolved.binding === 'fix' && creator === resolved.candidate\n ? 'fix'\n : 'report'\n : undefined;\n };\n\n const isKitWrite = (node: TSESTree.MemberExpression): boolean =>\n (node.parent.type === AST_NODE_TYPES.AssignmentExpression && node.parent.left === node) ||\n (node.parent.type === AST_NODE_TYPES.UpdateExpression && node.parent.argument === node) ||\n (node.parent.type === AST_NODE_TYPES.UnaryExpression && node.parent.operator === 'delete');\n\n const reportKitMember = (node: TSESTree.MemberExpression, name: string): boolean => {\n if (name !== 'publish') return false;\n const kit = kitSource(node.object);\n if (kit === undefined) return false;\n context.report({\n ...(kit === 'fix' && !node.computed && !isKitWrite(node)\n ? { fix: (fixer: Parameters<ReportFixFunction>[0]) => fixer.replaceText(node.property, 'set') }\n : {}),\n messageId: 'externalPublish',\n node: node.property,\n });\n return true;\n };\n\n const patternKey = (node: TSESTree.Property): string | undefined =>\n node.computed && node.key.type === AST_NODE_TYPES.Literal && typeof node.key.value === 'string'\n ? node.key.value\n : propertyName(node);\n\n const reportKitDestructure = (node: TSESTree.Property): void => {\n if (patternKey(node) !== 'publish' || node.parent.type !== AST_NODE_TYPES.ObjectPattern) return;\n const declarator = node.parent.parent;\n if (declarator.type !== AST_NODE_TYPES.VariableDeclarator || declarator.init === null) return;\n if (kitSource(declarator.init) !== undefined) context.report({ messageId: 'externalPublish', node: node.key });\n };\n\n const reportResourceDestructure = (node: TSESTree.Property): void => {\n if (propertyName(node) !== 'invalidate' || node.parent.type !== AST_NODE_TYPES.ObjectPattern) return;\n const declarator = node.parent.parent;\n if (declarator.type !== AST_NODE_TYPES.VariableDeclarator || declarator.init === null) return;\n if (holdsVerbs(declarator.init)) context.report({ messageId: 'resourceInvalidate', node: node.key });\n };\n\n return {\n CallExpression(node): void {\n resourceVocabulary.visitCall(node);\n if (reportRemovedFeatureOwn(node)) return;\n const contribution = contributionCall(node);\n\n if (contribution !== undefined) reportModifiers(node, contribution);\n\n const condition = conditionRecord(node);\n\n if (condition !== undefined) reportRecord(condition, CONDITION_WORDS);\n\n const declared = declaredCall(node);\n\n if (declared === undefined) return;\n\n if (declared.word !== undefined) context.report({ messageId: declared.word, node: calleeWord(node.callee) });\n\n if (declared.modifiers !== undefined) reportModifiers(node, declared.modifiers);\n },\n ImportDeclaration(node): void {\n if (!node.source.value.startsWith('@opetope/')) return;\n\n reportMove(importMove(source, node));\n\n for (const specifier of node.specifiers) {\n if (specifier.type !== AST_NODE_TYPES.ImportSpecifier) continue;\n\n const word = importName(specifier);\n const retired = retiredImport(word, node.source.value);\n\n if (retired !== undefined) {\n context.report({\n data: { replacement: retired.replacement, word },\n messageId: retired.messageId,\n node: specifier.imported,\n });\n }\n }\n },\n ExportAllDeclaration(node): void {\n reportMove(starMove(node));\n },\n ExportNamedDeclaration(node): void {\n reportMove(reexportMove(source, node));\n },\n ImportExpression(node): void {\n reportMove(dynamicMove(source, node));\n },\n MemberExpression(node): void {\n reportMove(namespaceMemberMove(source, node));\n const name = staticMemberName(node);\n if (name === undefined || reportKitMember(node, name)) return;\n const messageId = retiredMember(node, name);\n\n if (messageId !== undefined) {\n const fix = retiredMemberFix(node, messageId);\n context.report({\n ...(fix === undefined ? {} : { fix }),\n messageId,\n node: node.property,\n });\n }\n },\n Property(node): void {\n reportKitDestructure(node);\n reportResourceDestructure(node);\n },\n TSImportType(node): void {\n reportMove(typeImportMove(node));\n },\n TSQualifiedName(node): void {\n reportMove(namespaceTypeMove(source, node));\n },\n TSTypeReference(node): void {\n resourceVocabulary.visitType(node);\n },\n };\n },\n meta: {\n docs: {\n description:\n 'A retired word is named with its replacement; entry moves and locally proven Resource spellings are rewritten.',\n },\n fixable: 'code',\n messages: RETIRED_MESSAGES,\n schema: [],\n type: 'problem',\n },\n name: 'no-retired-vocabulary',\n});\n\nexport { noRetiredVocabulary };\n"],"names":["COMMAND_WORDS","COMMAND_VALUES","EFFECT_WORDS","WHILE_WORDS","EVENT_WORDS","DELIVERY_WORDS","DECLARATION_WORDS","PAGINATE_WORDS","DELIVERY","LIVE_DELIVERY_VALUES","CONTRIBUTION_WORDS","CONTRIBUTION_RECORDS","CONDITION_WORDS","OPTION_RECORDS","RETIRED_MEMBERS","RETIRED_METHODS","FEATURE_OWN_REMOVED","TESTING_ENTRIES","RETIRED_IMPORTS","name","retiredImport","word","from","retired","module","calleeWord","callee","AST_NODE_TYPES","noRetiredVocabulary","createRule","context","source","resourceVocabulary","createResourceVocabulary","node","messageId","fix","declaredCall","named","methodPath","declared","isContextFunction","recordAt","position","argument","value","localValue","contributionCall","modifiers","isFeatureSection","conditionRecord","isApi","whileFix","property","direct","fixer","written","next","reportProperty","words","propertyName","reportRecord","record","retiredValue","values","reportValues","reportCarried","carrier","findProperty","carried","reportModifiers","holdsVerbs","isResourceValue","isResourceHook","memberOwner","isStateActivity","isSurfaceValue","isLinkSourceValue","isCommandOutcome","retiredMember","retiredMemberFix","replacement","reportMove","move","sameEntry","featureWord","root","reportRemovedFeatureOwn","kitVariable","variable","findVariable","definition","DefinitionType","kitBinding","resolved","hasWritesBeyondDefinition","kitSource","creator","isKitWrite","reportKitMember","kit","patternKey","reportKitDestructure","declarator","reportResourceDestructure","contribution","condition","importMove","specifier","importName","starMove","reexportMove","dynamicMove","namespaceMemberMove","staticMemberName","typeImportMove","namespaceTypeMove","RETIRED_MESSAGES"],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ type MessageIds = 'singleCommandLane' | 'singleSelectionLane';
2
+ /**
3
+ * D494: a lane is the word for a queue several commands share, so a lane only one site takes says nothing its own
4
+ * `concurrency` does not. A command declared by `ctx.command` already runs its calls one at a time in a queue of its
5
+ * own — `'queue'` is its default, and `{ pending: 'latest' }` takes a private lane as well (D387, D459). A selection
6
+ * schedules only what is written on it: without `concurrency` every request starts at once, and a written one gives it
7
+ * a queue of its own (D336), so there the advice is to write `'queue'`, not to drop the word.
8
+ */
9
+ declare const noSingleCommandLane: import("../rule.js").RuleModule<MessageIds, []>;
10
+ export { noSingleCommandLane };
@@ -0,0 +1,2 @@
1
+ import{AST_NODE_TYPES as a}from"@typescript-eslint/types";import{propertyName as d,within as f}from"../ast.js";import{methodPath as o,isModelContextFunction as u}from"../declaration-ingress.js";import{variableOf as m,isFunction as p,unwrap as y}from"../model-bindings.js";import{createRule as h}from"../rule.js";const g=new Map([["command",1],["select",2]]);function S(t,e){const n=e.parent;if(n?.type!==a.CallExpression)return;const r=o(t,n.callee);if(!(r===void 0||n.arguments[g.get(r.method)??-1]!==e))return u(t,r.fn)?n:void 0}function c(t,e){const n=e.parent;if(!(n?.type!==a.Property||n.value!==e))return d(n)==="concurrency"?S(t,n.parent):void 0}function w(t){let e=t;for(;e.parent!==void 0&&y(e.parent)!==e.parent;)e=e.parent;return e}function l(t,e){const n=w(e),r=c(t,n);if(r!==void 0)return{command:r,latest:!1};const i=n.parent;if(i?.type!==a.Property||d(i)!=="lane")return;const s=c(t,i.parent);return s===void 0?void 0:{command:s,latest:!0}}function O(t){const e=t.parent;return e.type===a.VariableDeclarator&&e.id.type===a.Identifier?e.id:void 0}const D=new Set([a.AccessorProperty,a.DoWhileStatement,a.ForInStatement,a.ForOfStatement,a.ForStatement,a.PropertyDefinition,a.StaticBlock,a.WhileStatement]);function q(t,e){for(let n=e.parent;n!==void 0&&!f(t,n);n=n.parent)if(p(n)||D.has(n.type))return!1;return!0}function C(t,e){const n=(m(t,e)?.references??[]).filter(i=>i.identifier!==e),[r]=n;return n.length===1&&r?.identifier.type===a.Identifier?r.identifier:void 0}function E(t,e){const n=O(e);if(n===void 0)return l(t,e);const r=C(t,n);return r===void 0||!q(e,r)?void 0:l(t,r)}function I(t,e){return o(t,e.command.callee)?.method==="select"?{data:{instead:e.latest?"`concurrency: { pending: 'latest' }`":"`concurrency: 'queue'`"},messageId:"singleSelectionLane"}:{data:{instead:e.latest?"`{ pending: 'latest' }`":"`'queue'`, the default,"},messageId:"singleCommandLane"}}function P(t,e){if(e.arguments.length>0)return!1;const n=o(t,e.callee);return n?.method==="lane"&&u(t,n.fn)}const v=h({create(t){const e=t.sourceCode;return{CallExpression(n){if(!P(e,n))return;const r=E(e,n);r!==void 0&&t.report({...I(e,r),node:n})}}},meta:{docs:{description:"A lane is a queue several commands share; a lane only one command or selection takes says nothing."},messages:{singleCommandLane:"Only one command takes this lane, and a command already runs its calls one at a time in a queue of its own. Write {{instead}} and drop the lane; a lane is how several commands share one queue (D387, D494).",singleSelectionLane:"Only this selection takes this lane. Write {{instead}} and drop the lane: a selection without `concurrency` starts every request at once, and a written one gives it a queue of its own (D336, D387, D494)."},schema:[],type:"suggestion"},name:"no-single-command-lane"});export{v as noSingleCommandLane};
2
+ //# sourceMappingURL=no-single-command-lane.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-single-command-lane.js","sources":["../../src/rules/no-single-command-lane.ts"],"sourcesContent":["import { AST_NODE_TYPES } from '@typescript-eslint/types';\nimport type { TSESTree } from '@typescript-eslint/types';\n\nimport { propertyName, within } from '../ast';\nimport { isModelContextFunction, methodPath } from '../declaration-ingress';\nimport { isFunction, unwrap, variableOf } from '../model-bindings';\nimport type { SourceCode } from '../rule';\nimport { createRule } from '../rule';\n\ntype MessageIds = 'singleCommandLane' | 'singleSelectionLane';\n\n/** Where a lane stands in a record of modifiers: the whole `concurrency`, or the `lane` of `{ lane, pending }`. */\ntype LaneSite = { readonly command: TSESTree.CallExpression; readonly latest: boolean };\n\n/** The position of the modifiers record in the two model calls that take a lane: `command(run, options)` and `select`. */\nconst MODIFIERS_AT = new Map([\n ['command', 1],\n ['select', 2],\n]);\n\n/** The call whose modifiers record this is, when it is the record of a model's `command` or `select`. */\nfunction modifiersOf(source: SourceCode, record: TSESTree.Node): TSESTree.CallExpression | undefined {\n const call = record.parent;\n\n if (call?.type !== AST_NODE_TYPES.CallExpression) return undefined;\n\n const named = methodPath(source, call.callee);\n\n if (named === undefined || call.arguments[MODIFIERS_AT.get(named.method) ?? -1] !== record) return undefined;\n\n return isModelContextFunction(source, named.fn) ? call : undefined;\n}\n\n/** `concurrency: <value>` directly inside a modifiers record: the record's call, where there is one. */\nfunction concurrencyOf(source: SourceCode, value: TSESTree.Node): TSESTree.CallExpression | undefined {\n const property = value.parent;\n\n if (property?.type !== AST_NODE_TYPES.Property || property.value !== value) return undefined;\n\n return propertyName(property) === 'concurrency' ? modifiersOf(source, property.parent) : undefined;\n}\n\n/** The expression a type-only wrapper — `as`, `satisfies`, `!` — stands for where it is written, wrappers included. */\nfunction outermost(node: TSESTree.Node): TSESTree.Node {\n let current = node;\n\n while (current.parent !== undefined && unwrap(current.parent) !== current.parent) current = current.parent;\n\n return current;\n}\n\n/**\n * The command a lane written at `node` orders, and in which form: `concurrency: lane`, or the `lane` of\n * `concurrency: { lane, pending: 'latest' }`. Anything else — a record assembled elsewhere, a lane handed to a helper —\n * is somewhere this rule cannot follow, and it says nothing about it.\n */\nfunction laneSite(source: SourceCode, node: TSESTree.Node): LaneSite | undefined {\n const written = outermost(node);\n const whole = concurrencyOf(source, written);\n\n if (whole !== undefined) return { command: whole, latest: false };\n\n const property = written.parent;\n\n if (property?.type !== AST_NODE_TYPES.Property || propertyName(property) !== 'lane') return undefined;\n\n const latest = concurrencyOf(source, property.parent);\n\n return latest === undefined ? undefined : { command: latest, latest: true };\n}\n\n/** The name a lane is bound to where it is taken: `const lane = ctx.lane()`. */\nfunction laneName(call: TSESTree.CallExpression): TSESTree.Identifier | undefined {\n const declarator = call.parent;\n\n return declarator.type === AST_NODE_TYPES.VariableDeclarator && declarator.id.type === AST_NODE_TYPES.Identifier\n ? declarator.id\n : undefined;\n}\n\n/**\n * What runs its body more than once, or at another time than the code around it: a loop, and the members of a class —\n * a field and an `accessor` evaluate for every instance, a `static` block for every evaluation of the class.\n */\nconst REPEATS: ReadonlySet<string> = new Set([\n AST_NODE_TYPES.AccessorProperty,\n AST_NODE_TYPES.DoWhileStatement,\n AST_NODE_TYPES.ForInStatement,\n AST_NODE_TYPES.ForOfStatement,\n AST_NODE_TYPES.ForStatement,\n AST_NODE_TYPES.PropertyDefinition,\n AST_NODE_TYPES.StaticBlock,\n AST_NODE_TYPES.WhileStatement,\n]);\n\n/**\n * Whether `read` runs once for every lane `call` takes: no function, no loop and no member of a class stands between\n * the read and the code that holds the declaration. A helper `run => ctx.command(run, { concurrency: lane })`, a `map`,\n * a `for` or a class field makes one read into many commands, and that lane is shared.\n */\nfunction readOnce(call: TSESTree.CallExpression, read: TSESTree.Node): boolean {\n for (let current = read.parent; current !== undefined && !within(call, current); current = current.parent) {\n if (isFunction(current) || REPEATS.has(current.type)) return false;\n }\n\n return true;\n}\n\n/** The one place a lane bound to a name is read, or `undefined` when it is read more than once or never. */\nfunction onlyRead(source: SourceCode, name: TSESTree.Identifier): TSESTree.Identifier | undefined {\n const reads = (variableOf(source, name)?.references ?? []).filter(reference => reference.identifier !== name);\n const [only] = reads;\n\n return reads.length === 1 && only?.identifier.type === AST_NODE_TYPES.Identifier ? only.identifier : undefined;\n}\n\n/**\n * Where the lane `call` takes is written into a modifiers record: right there, or at the one read of the name it is\n * bound to, where that read declares one command.\n */\nfunction siteOf(source: SourceCode, call: TSESTree.CallExpression): LaneSite | undefined {\n const name = laneName(call);\n\n if (name === undefined) return laneSite(source, call);\n\n const read = onlyRead(source, name);\n\n return read === undefined || !readOnce(call, read) ? undefined : laneSite(source, read);\n}\n\ntype Advice = { readonly data: { readonly instead: string }; readonly messageId: MessageIds };\n\n/** What the site writes instead of the lane: a command's own queue is its default, a selection's is written. */\nfunction adviceOf(source: SourceCode, site: LaneSite): Advice {\n if (methodPath(source, site.command.callee)?.method === 'select') {\n const instead = site.latest ? \"`concurrency: { pending: 'latest' }`\" : \"`concurrency: 'queue'`\";\n\n return { data: { instead }, messageId: 'singleSelectionLane' };\n }\n\n return {\n data: { instead: site.latest ? \"`{ pending: 'latest' }`\" : \"`'queue'`, the default,\" },\n messageId: 'singleCommandLane',\n };\n}\n\n/** `ctx.lane()` on a model's context. */\nfunction isModelLane(source: SourceCode, call: TSESTree.CallExpression): boolean {\n if (call.arguments.length > 0) return false;\n\n const named = methodPath(source, call.callee);\n\n return named?.method === 'lane' && isModelContextFunction(source, named.fn);\n}\n\n/**\n * D494: a lane is the word for a queue several commands share, so a lane only one site takes says nothing its own\n * `concurrency` does not. A command declared by `ctx.command` already runs its calls one at a time in a queue of its\n * own — `'queue'` is its default, and `{ pending: 'latest' }` takes a private lane as well (D387, D459). A selection\n * schedules only what is written on it: without `concurrency` every request starts at once, and a written one gives it\n * a queue of its own (D336), so there the advice is to write `'queue'`, not to drop the word.\n */\nconst noSingleCommandLane = createRule<[], MessageIds>({\n create(context) {\n const source = context.sourceCode;\n\n return {\n CallExpression(node): void {\n if (!isModelLane(source, node)) return;\n\n const site = siteOf(source, node);\n\n if (site !== undefined) context.report({ ...adviceOf(source, site), node });\n },\n };\n },\n meta: {\n docs: {\n description: 'A lane is a queue several commands share; a lane only one command or selection takes says nothing.',\n },\n messages: {\n singleCommandLane:\n 'Only one command takes this lane, and a command already runs its calls one at a time in a queue of its own. Write {{instead}} and drop the lane; a lane is how several commands share one queue (D387, D494).',\n singleSelectionLane:\n 'Only this selection takes this lane. Write {{instead}} and drop the lane: a selection without `concurrency` starts every request at once, and a written one gives it a queue of its own (D336, D387, D494).',\n },\n schema: [],\n type: 'suggestion',\n },\n name: 'no-single-command-lane',\n});\n\nexport { noSingleCommandLane };\n"],"names":["MODIFIERS_AT","modifiersOf","source","record","call","AST_NODE_TYPES","named","methodPath","isModelContextFunction","concurrencyOf","value","property","propertyName","outermost","node","current","unwrap","laneSite","written","whole","latest","laneName","declarator","REPEATS","readOnce","read","within","isFunction","onlyRead","name","reads","variableOf","reference","only","siteOf","adviceOf","site","isModelLane","noSingleCommandLane","createRule","context"],"mappings":"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"}
@@ -1,6 +1,3 @@
1
- import type { TSESLint } from '@typescript-eslint/utils';
2
1
  type MessageIds = 'snapshotInUpdate' | 'writeFromPrevious';
3
- declare const noSnapshotInUpdate: TSESLint.RuleModule<MessageIds, [], unknown, TSESLint.RuleListener> & {
4
- name: string;
5
- };
2
+ declare const noSnapshotInUpdate: import("../rule.js").RuleModule<MessageIds, []>;
6
3
  export { noSnapshotInUpdate };
@@ -1 +1 @@
1
- {"version":3,"file":"no-snapshot-in-update.js","sources":["../../src/rules/no-snapshot-in-update.ts"],"sourcesContent":["import type { TSESLint, TSESTree } from '@typescript-eslint/utils';\n\nimport { createRule } from '../rule';\nimport type { Site, Written } from '../snapshot-updates';\nimport { editsOf, siteAt } from '../snapshot-updates';\n\ntype MessageIds = 'snapshotInUpdate' | 'writeFromPrevious';\n\nconst noSnapshotInUpdate = createRule<[], MessageIds>({\n create(context) {\n const source = context.sourceCode;\n const written: Written = { barriers: [], calls: [], declarators: [], functions: [] };\n\n const rewrite =\n (site: Site, name: string): TSESLint.ReportFixFunction =>\n fixer =>\n editsOf(source, site, name).map(edit => fixer.replaceTextRange(edit.range, edit.text));\n\n /**\n * Oxlint applies the first suggestion unattended, so a value this rule cannot move into an updater carries\n * none: the write is still wrong, and how to compute it from the previous value is the author's to write.\n */\n const report = (site: Site): void => {\n const [read] = site.reads;\n\n if (read === undefined) return;\n\n const { node } = read;\n const { name } = site;\n\n if (name === undefined || !site.rewritable) {\n context.report({ messageId: 'snapshotInUpdate', node });\n\n return;\n }\n\n const fix = rewrite(site, name);\n\n // A name of its own and no reader left behind: only then does the rewrite need nobody to look at it.\n if (site.free && site.aliases.every(alias => alias.removable)) {\n context.report({ fix, messageId: 'snapshotInUpdate', node });\n\n return;\n }\n\n context.report({\n messageId: 'snapshotInUpdate',\n node,\n suggest: [{ data: { name }, fix, messageId: 'writeFromPrevious' }],\n });\n };\n\n return {\n ':function'(node: TSESTree.Node): void {\n written.functions.push(node);\n },\n 'AssignmentExpression, AwaitExpression, UpdateExpression, YieldExpression'(node: TSESTree.Node): void {\n written.barriers.push(node);\n },\n // `delete` is the one unary operator that writes; the rest compute, and computing travels with the value.\n UnaryExpression(node): void {\n if (node.operator === 'delete') written.barriers.push(node);\n },\n CallExpression(node): void {\n written.calls.push(node);\n },\n VariableDeclarator(node): void {\n written.declarators.push(node);\n },\n 'Program:exit'(): void {\n for (const call of written.calls) {\n const site = siteAt(source, call, written);\n\n if (site !== undefined) report(site);\n }\n },\n };\n },\n meta: {\n docs: {\n description: 'A write computes its value from the previous one, not from a snapshot of the state it replaces.',\n },\n fixable: 'code',\n hasSuggestions: true,\n messages: {\n snapshotInUpdate:\n 'This value reads the state it is about to replace: `getSnapshot()` runs before the write, on a state that may already be closed, and the write then lands on a value read earlier. Compute it from the previous value — `update(state, previous => ({ ...previous, ... }))` — which is read at write time and is not computed at all for a write the runtime drops (D282, D288).',\n writeFromPrevious: 'Compute the value from `{{name}}`, the value this write replaces.',\n },\n schema: [],\n type: 'problem',\n },\n name: 'no-snapshot-in-update',\n});\n\nexport { noSnapshotInUpdate };\n"],"names":["noSnapshotInUpdate","createRule","context","source","written","rewrite","site","name","fixer","editsOf","edit","report","read","node","fix","alias","call","siteAt"],"mappings":"qGAQA,MAAMA,EAAqBC,EAA2B,CACpD,OAAOC,EAAO,CACZ,MAAMC,EAASD,EAAQ,WACjBE,EAAmB,CAAE,SAAU,GAAI,MAAO,CAAA,EAAI,YAAa,CAAA,EAAI,UAAW,EAAE,EAE5EC,EACJ,CAACC,EAAYC,IACbC,GACEC,EAAQN,EAAQG,EAAMC,CAAI,EAAE,IAAIG,GAAQF,EAAM,iBAAiBE,EAAK,MAAOA,EAAK,IAAI,CAAC,EAMnFC,EAAUL,GAAoB,CAClC,KAAM,CAACM,CAAI,EAAIN,EAAK,MAEpB,GAAIM,IAAS,OAAW,OAExB,KAAM,CAAE,KAAAC,CAAI,EAAKD,EACX,CAAE,KAAAL,CAAI,EAAKD,EAEjB,GAAIC,IAAS,QAAa,CAACD,EAAK,WAAY,CAC1CJ,EAAQ,OAAO,CAAE,UAAW,mBAAoB,KAAAW,CAAI,CAAE,EAEtD,MACF,CAEA,MAAMC,EAAMT,EAAQC,EAAMC,CAAI,EAG9B,GAAID,EAAK,MAAQA,EAAK,QAAQ,MAAMS,GAASA,EAAM,SAAS,EAAG,CAC7Db,EAAQ,OAAO,CAAE,IAAAY,EAAK,UAAW,mBAAoB,KAAAD,EAAM,EAE3D,MACF,CAEAX,EAAQ,OAAO,CACb,UAAW,mBACX,KAAAW,EACA,QAAS,CAAC,CAAE,KAAM,CAAE,KAAAN,CAAI,EAAI,IAAAO,EAAK,UAAW,oBAAqB,CAClE,CAAA,CACH,EAEA,MAAO,CACL,YAAYD,EAAmB,CAC7BT,EAAQ,UAAU,KAAKS,CAAI,CAC7B,EACA,2EAA2EA,EAAmB,CAC5FT,EAAQ,SAAS,KAAKS,CAAI,CAC5B,EAEA,gBAAgBA,EAAI,CACdA,EAAK,WAAa,UAAUT,EAAQ,SAAS,KAAKS,CAAI,CAC5D,EACA,eAAeA,EAAI,CACjBT,EAAQ,MAAM,KAAKS,CAAI,CACzB,EACA,mBAAmBA,EAAI,CACrBT,EAAQ,YAAY,KAAKS,CAAI,CAC/B,EACA,gBAAc,CACZ,UAAWG,KAAQZ,EAAQ,MAAO,CAChC,MAAME,EAAOW,EAAOd,EAAQa,EAAMZ,CAAO,EAErCE,IAAS,QAAWK,EAAOL,CAAI,CACrC,CACF,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YAAa,iGACd,EACD,QAAS,OACT,eAAgB,GAChB,SAAU,CACR,iBACE,6XACF,kBAAmB,mEACpB,EACD,OAAQ,CAAA,EACR,KAAM,SACP,EACD,KAAM,uBACP,CAAA"}
1
+ {"version":3,"file":"no-snapshot-in-update.js","sources":["../../src/rules/no-snapshot-in-update.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/types';\n\nimport type { ReportFixFunction } from '../rule';\nimport { createRule } from '../rule';\nimport type { Site, Written } from '../snapshot-updates';\nimport { editsOf, siteAt } from '../snapshot-updates';\n\ntype MessageIds = 'snapshotInUpdate' | 'writeFromPrevious';\n\nconst noSnapshotInUpdate = createRule<[], MessageIds>({\n create(context) {\n const source = context.sourceCode;\n const written: Written = { barriers: [], calls: [], declarators: [], functions: [] };\n\n const rewrite =\n (site: Site, name: string): ReportFixFunction =>\n fixer =>\n editsOf(source, site, name).map(edit => fixer.replaceTextRange(edit.range, edit.text));\n\n /**\n * Oxlint applies the first suggestion unattended, so a value this rule cannot move into an updater carries\n * none: the write is still wrong, and how to compute it from the previous value is the author's to write.\n */\n const report = (site: Site): void => {\n const [read] = site.reads;\n\n if (read === undefined) return;\n\n const { node } = read;\n const { name } = site;\n\n if (name === undefined || !site.rewritable) {\n context.report({ messageId: 'snapshotInUpdate', node });\n\n return;\n }\n\n const fix = rewrite(site, name);\n\n // A name of its own and no reader left behind: only then does the rewrite need nobody to look at it.\n if (site.free && site.aliases.every(alias => alias.removable)) {\n context.report({ fix, messageId: 'snapshotInUpdate', node });\n\n return;\n }\n\n context.report({\n messageId: 'snapshotInUpdate',\n node,\n suggest: [{ data: { name }, fix, messageId: 'writeFromPrevious' }],\n });\n };\n\n return {\n ':function'(node: TSESTree.Node): void {\n written.functions.push(node);\n },\n 'AssignmentExpression, AwaitExpression, UpdateExpression, YieldExpression'(node: TSESTree.Node): void {\n written.barriers.push(node);\n },\n // `delete` is the one unary operator that writes; the rest compute, and computing travels with the value.\n UnaryExpression(node): void {\n if (node.operator === 'delete') written.barriers.push(node);\n },\n CallExpression(node): void {\n written.calls.push(node);\n },\n VariableDeclarator(node): void {\n written.declarators.push(node);\n },\n 'Program:exit'(): void {\n for (const call of written.calls) {\n const site = siteAt(source, call, written);\n\n if (site !== undefined) report(site);\n }\n },\n };\n },\n meta: {\n docs: {\n description: 'A write computes its value from the previous one, not from a snapshot of the state it replaces.',\n },\n fixable: 'code',\n hasSuggestions: true,\n messages: {\n snapshotInUpdate:\n 'This value reads the state it is about to replace: `getSnapshot()` runs before the write, on a state that may already be closed, and the write then lands on a value read earlier. Compute it from the previous value — `update(state, previous => ({ ...previous, ... }))` — which is read at write time and is not computed at all for a write the runtime drops (D282, D288).',\n writeFromPrevious: 'Compute the value from `{{name}}`, the value this write replaces.',\n },\n schema: [],\n type: 'problem',\n },\n name: 'no-snapshot-in-update',\n});\n\nexport { noSnapshotInUpdate };\n"],"names":["noSnapshotInUpdate","createRule","context","source","written","rewrite","site","name","fixer","editsOf","edit","report","read","node","fix","alias","call","siteAt"],"mappings":"qGASA,MAAMA,EAAqBC,EAA2B,CACpD,OAAOC,EAAO,CACZ,MAAMC,EAASD,EAAQ,WACjBE,EAAmB,CAAE,SAAU,GAAI,MAAO,CAAA,EAAI,YAAa,CAAA,EAAI,UAAW,EAAE,EAE5EC,EACJ,CAACC,EAAYC,IACbC,GACEC,EAAQN,EAAQG,EAAMC,CAAI,EAAE,IAAIG,GAAQF,EAAM,iBAAiBE,EAAK,MAAOA,EAAK,IAAI,CAAC,EAMnFC,EAAUL,GAAoB,CAClC,KAAM,CAACM,CAAI,EAAIN,EAAK,MAEpB,GAAIM,IAAS,OAAW,OAExB,KAAM,CAAE,KAAAC,CAAI,EAAKD,EACX,CAAE,KAAAL,CAAI,EAAKD,EAEjB,GAAIC,IAAS,QAAa,CAACD,EAAK,WAAY,CAC1CJ,EAAQ,OAAO,CAAE,UAAW,mBAAoB,KAAAW,CAAI,CAAE,EAEtD,MACF,CAEA,MAAMC,EAAMT,EAAQC,EAAMC,CAAI,EAG9B,GAAID,EAAK,MAAQA,EAAK,QAAQ,MAAMS,GAASA,EAAM,SAAS,EAAG,CAC7Db,EAAQ,OAAO,CAAE,IAAAY,EAAK,UAAW,mBAAoB,KAAAD,EAAM,EAE3D,MACF,CAEAX,EAAQ,OAAO,CACb,UAAW,mBACX,KAAAW,EACA,QAAS,CAAC,CAAE,KAAM,CAAE,KAAAN,CAAI,EAAI,IAAAO,EAAK,UAAW,oBAAqB,CAClE,CAAA,CACH,EAEA,MAAO,CACL,YAAYD,EAAmB,CAC7BT,EAAQ,UAAU,KAAKS,CAAI,CAC7B,EACA,2EAA2EA,EAAmB,CAC5FT,EAAQ,SAAS,KAAKS,CAAI,CAC5B,EAEA,gBAAgBA,EAAI,CACdA,EAAK,WAAa,UAAUT,EAAQ,SAAS,KAAKS,CAAI,CAC5D,EACA,eAAeA,EAAI,CACjBT,EAAQ,MAAM,KAAKS,CAAI,CACzB,EACA,mBAAmBA,EAAI,CACrBT,EAAQ,YAAY,KAAKS,CAAI,CAC/B,EACA,gBAAc,CACZ,UAAWG,KAAQZ,EAAQ,MAAO,CAChC,MAAME,EAAOW,EAAOd,EAAQa,EAAMZ,CAAO,EAErCE,IAAS,QAAWK,EAAOL,CAAI,CACrC,CACF,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YAAa,iGACd,EACD,QAAS,OACT,eAAgB,GAChB,SAAU,CACR,iBACE,6XACF,kBAAmB,mEACpB,EACD,OAAQ,CAAA,EACR,KAAM,SACP,EACD,KAAM,uBACP,CAAA"}
@@ -1,4 +1,3 @@
1
- declare const noSnapshotReadInRender: import("@typescript-eslint/utils/ts-eslint").RuleModule<"snapshotInRender", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
2
- name: string;
3
- };
1
+ type MessageIds = 'selectorIdentity' | 'snapshotInRender' | 'snapshotInSelector';
2
+ declare const noSnapshotReadInRender: import("../rule.js").RuleModule<MessageIds, []>;
4
3
  export { noSnapshotReadInRender };
@@ -1,2 +1,2 @@
1
- import{AST_NODE_TYPES as o}from"@typescript-eslint/utils";import{functionName as a}from"../ast.js";import{createRule as i}from"../rule.js";const p=/^use[A-Z]/,c=/^[A-Z]/;function d(t){const{callee:n}=t;return n.type!==o.MemberExpression||n.computed?!1:n.property.type===o.Identifier&&n.property.name==="getSnapshot"}function m(t){return t.name===void 0?!1:p.test(t.name)?!0:t.hasJsx&&c.test(t.name)}const f=i({create(t){const n=[],r=[];return{":function"(e){const s={hasJsx:!1,name:a(e),reads:[]};n.push(s),r.push(s)},":function:exit"(){r.pop()},CallExpression(e){d(e)&&r.at(-1)?.reads.push(e)},"JSXElement, JSXFragment"(){for(const e of r)e.hasJsx=!0},"Program:exit"(){for(const e of n)if(m(e))for(const s of e.reads)t.report({messageId:"snapshotInRender",node:s})}}},meta:{docs:{description:"A component reads observed data reactively, not by taking a snapshot while it renders."},messages:{snapshotInRender:"A snapshot taken while rendering is not reactive: the component keeps the value it read and never hears the next one. Read it with `useReadable`, or select it in `useModel(Declaration, (model, { read }) => ...)` (D205, D214)."},schema:[],type:"problem"},name:"no-snapshot-read-in-render"});export{f as noSnapshotReadInRender};
1
+ import{AST_NODE_TYPES as s}from"@typescript-eslint/types";import{functionName as u,isFunctionLike as i,calleeName as f}from"../ast.js";import{createRule as p}from"../rule.js";const l=/^use[A-Z]/,m=/^[A-Z]/;function h(e){const{callee:t}=e;return t.type!==s.MemberExpression||t.computed?!1:t.property.type===s.Identifier&&t.property.name==="getSnapshot"}function y(e){return e.name===void 0?!1:l.test(e.name)?!0:e.hasJsx&&m.test(e.name)}function I(e){return e.type!==s.Property||e.computed?void 0:e.key.type===s.Identifier&&e.key.name==="read"&&e.value.type===s.Identifier?e.value.name:void 0}function S(e){const t=e.params[1];if(t?.type===s.Identifier)return{context:t.name,reads:new Set};const n=t?.type===s.ObjectPattern?t.properties.map(I):[];return{context:void 0,reads:new Set(n.filter(r=>r!==void 0))}}function b(e,t){return!e.computed&&e.object.type===s.Identifier&&e.object.name===t.context&&e.property.type===s.Identifier&&e.property.name==="read"}function g(e,t){const{callee:n}=e;return n.type===s.Identifier?t.reads.has(n.name):n.type===s.MemberExpression&&b(n,t)}function c(e){if(!(!i(e)||e.parent.type!==s.CallExpression))return e.parent.arguments[1]===e?e.parent:void 0}function d(e){const t=c(e);return t!==void 0&&f(t)?.split(".").at(-1)==="useModel"}function x(e,t){if(i(e)&&d(e))return S(e);const n=t?.selector,r=c(e);return n!==void 0&&r!==void 0&&g(r,n)?n:void 0}function v(e){const{body:t}=e;if(t.type!==s.BlockStatement)return t;const[n]=t.body;return t.body.length===1&&n?.type===s.ReturnStatement?n.argument??void 0:void 0}function R(e){const[t]=e.params,n=v(e);return t?.type===s.Identifier&&n?.type===s.Identifier&&n.name===t.name}const w=p({create(e){const t=[],n=[];return{":function"(r){const a=x(r,n.at(-1)),o={hasJsx:!1,name:u(r),reads:[],selector:a};i(r)&&d(r)&&R(r)&&e.report({messageId:"selectorIdentity",node:r}),t.push(o),n.push(o)},":function:exit"(){n.pop()},CallExpression(r){h(r)&&n.at(-1)?.reads.push(r)},"JSXElement, JSXFragment"(){for(const r of n)r.hasJsx=!0},"Program:exit"(){for(const r of t){const a=r.selector!==void 0?"snapshotInSelector":"snapshotInRender";if(!(r.selector===void 0&&!y(r)))for(const o of r.reads)e.report({messageId:a,node:o})}}}},meta:{docs:{description:"A component reads observed data reactively, not by taking a snapshot while it renders."},messages:{selectorIdentity:"A selector that answers the model it was handed leaves every source in the selection, and the types refuse each one: select the fields and read(...) every source, or call useModel(Model) without a selector (D476).",snapshotInSelector:"getSnapshot() in a selector never updates: the selection keeps the value it read, because only read(source) subscribes the component to it. Use read(source), or read(source, project) (D476).",snapshotInRender:"A snapshot taken while rendering is not reactive: the component keeps the value it read and never hears the next one. Read it with `useReadable`, or select it in `useModel(Declaration, (model, { read }) => ...)` (D205, D214)."},schema:[],type:"problem"},name:"no-snapshot-read-in-render"});export{w as noSnapshotReadInRender};
2
2
  //# sourceMappingURL=no-snapshot-read-in-render.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-snapshot-read-in-render.js","sources":["../../src/rules/no-snapshot-read-in-render.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nimport { functionName } from '../ast';\nimport { createRule } from '../rule';\n\ntype MessageIds = 'snapshotInRender';\n\ntype Frame = {\n hasJsx: boolean;\n readonly name: string | undefined;\n readonly reads: TSESTree.CallExpression[];\n};\n\nconst HOOK_NAME = /^use[A-Z]/;\nconst COMPONENT_NAME = /^[A-Z]/;\n\nfunction isSnapshotRead(node: TSESTree.CallExpression): boolean {\n const { callee } = node;\n\n if (callee.type !== AST_NODE_TYPES.MemberExpression || callee.computed) return false;\n\n return callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === 'getSnapshot';\n}\n\n/**\n * A hook by its name, a component by its name and the elements it returns. A function that returns no element is\n * not a render scope even when its name is capitalized, so a factory keeps its snapshot reads.\n */\nfunction isRenderScope(frame: Frame): boolean {\n if (frame.name === undefined) return false;\n\n if (HOOK_NAME.test(frame.name)) return true;\n\n return frame.hasJsx && COMPONENT_NAME.test(frame.name);\n}\n\nconst noSnapshotReadInRender = createRule<[], MessageIds>({\n create(context) {\n const frames: Frame[] = [];\n const stack: Frame[] = [];\n\n return {\n ':function'(node: TSESTree.Node): void {\n const frame: Frame = { hasJsx: false, name: functionName(node), reads: [] };\n\n frames.push(frame);\n stack.push(frame);\n },\n ':function:exit'(): void {\n stack.pop();\n },\n CallExpression(node): void {\n if (isSnapshotRead(node)) stack.at(-1)?.reads.push(node);\n },\n 'JSXElement, JSXFragment'(): void {\n // The elements of a nested callback are still the elements this component renders.\n for (const frame of stack) frame.hasJsx = true;\n },\n 'Program:exit'(): void {\n for (const frame of frames) {\n if (!isRenderScope(frame)) continue;\n\n for (const read of frame.reads) context.report({ messageId: 'snapshotInRender', node: read });\n }\n },\n };\n },\n meta: {\n docs: {\n description: 'A component reads observed data reactively, not by taking a snapshot while it renders.',\n },\n messages: {\n snapshotInRender:\n 'A snapshot taken while rendering is not reactive: the component keeps the value it read and never hears the next one. Read it with `useReadable`, or select it in `useModel(Declaration, (model, { read }) => ...)` (D205, D214).',\n },\n schema: [],\n type: 'problem',\n },\n name: 'no-snapshot-read-in-render',\n});\n\nexport { noSnapshotReadInRender };\n"],"names":["HOOK_NAME","COMPONENT_NAME","isSnapshotRead","node","callee","AST_NODE_TYPES","isRenderScope","frame","noSnapshotReadInRender","createRule","context","frames","stack","functionName","read"],"mappings":"2IAcA,MAAMA,EAAY,YACZC,EAAiB,SAEvB,SAASC,EAAeC,EAA6B,CACnD,KAAM,CAAE,OAAAC,CAAM,EAAKD,EAEnB,OAAIC,EAAO,OAASC,EAAe,kBAAoBD,EAAO,SAAiB,GAExEA,EAAO,SAAS,OAASC,EAAe,YAAcD,EAAO,SAAS,OAAS,aACxF,CAMA,SAASE,EAAcC,EAAY,CACjC,OAAIA,EAAM,OAAS,OAAkB,GAEjCP,EAAU,KAAKO,EAAM,IAAI,EAAU,GAEhCA,EAAM,QAAUN,EAAe,KAAKM,EAAM,IAAI,CACvD,CAEA,MAAMC,EAAyBC,EAA2B,CACxD,OAAOC,EAAO,CACZ,MAAMC,EAAkB,CAAA,EAClBC,EAAiB,CAAA,EAEvB,MAAO,CACL,YAAYT,EAAmB,CAC7B,MAAMI,EAAe,CAAE,OAAQ,GAAO,KAAMM,EAAaV,CAAI,EAAG,MAAO,EAAE,EAEzEQ,EAAO,KAAKJ,CAAK,EACjBK,EAAM,KAAKL,CAAK,CAClB,EACA,kBAAgB,CACdK,EAAM,IAAG,CACX,EACA,eAAeT,EAAI,CACbD,EAAeC,CAAI,GAAGS,EAAM,GAAG,EAAE,GAAG,MAAM,KAAKT,CAAI,CACzD,EACA,2BAAyB,CAEvB,UAAWI,KAASK,EAAOL,EAAM,OAAS,EAC5C,EACA,gBAAc,CACZ,UAAWA,KAASI,EAClB,GAAKL,EAAcC,CAAK,EAExB,UAAWO,KAAQP,EAAM,MAAOG,EAAQ,OAAO,CAAE,UAAW,mBAAoB,KAAMI,EAAM,CAEhG,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YAAa,wFACd,EACD,SAAU,CACR,iBACE,mOACH,EACD,OAAQ,CAAA,EACR,KAAM,SACP,EACD,KAAM,4BACP,CAAA"}
1
+ {"version":3,"file":"no-snapshot-read-in-render.js","sources":["../../src/rules/no-snapshot-read-in-render.ts"],"sourcesContent":["import { AST_NODE_TYPES } from '@typescript-eslint/types';\nimport type { TSESTree } from '@typescript-eslint/types';\n\nimport { calleeName, functionName, isFunctionLike } from '../ast';\nimport { createRule } from '../rule';\n\ntype MessageIds = 'selectorIdentity' | 'snapshotInRender' | 'snapshotInSelector';\n\n/**\n * D476: an inline `useModel` selector runs while the component renders, and so does a projection it hands to `read`;\n * a function the selector only creates — a callback in its result — runs later and keeps its reads.\n */\ntype SelectorScope = {\n readonly context: string | undefined;\n readonly reads: ReadonlySet<string>;\n};\n\ntype Frame = {\n hasJsx: boolean;\n readonly name: string | undefined;\n readonly reads: TSESTree.CallExpression[];\n readonly selector: SelectorScope | undefined;\n};\n\nconst HOOK_NAME = /^use[A-Z]/;\nconst COMPONENT_NAME = /^[A-Z]/;\n\nfunction isSnapshotRead(node: TSESTree.CallExpression): boolean {\n const { callee } = node;\n\n if (callee.type !== AST_NODE_TYPES.MemberExpression || callee.computed) return false;\n\n return callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === 'getSnapshot';\n}\n\n/**\n * A hook by its name, a component by its name and the elements it returns. A function that returns no element is\n * not a render scope even when its name is capitalized, so a factory keeps its snapshot reads.\n */\nfunction isRenderScope(frame: Frame): boolean {\n if (frame.name === undefined) return false;\n\n if (HOOK_NAME.test(frame.name)) return true;\n\n return frame.hasJsx && COMPONENT_NAME.test(frame.name);\n}\n\n/** `read` destructured from the selection context, under its own name or another: `{ read }`, `{ read: take }`. */\nfunction readBinding(property: TSESTree.ObjectPattern['properties'][number]): string | undefined {\n if (property.type !== AST_NODE_TYPES.Property || property.computed) return undefined;\n\n const named = property.key.type === AST_NODE_TYPES.Identifier && property.key.name === 'read';\n\n return named && property.value.type === AST_NODE_TYPES.Identifier ? property.value.name : undefined;\n}\n\n/** The names `read` is reachable under in a selector: `{ read }`, `{ read: readSource }` or `context.read`. */\nfunction selectorScope(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression): SelectorScope {\n const context = node.params[1];\n\n if (context?.type === AST_NODE_TYPES.Identifier) return { context: context.name, reads: new Set() };\n\n const bindings = context?.type === AST_NODE_TYPES.ObjectPattern ? context.properties.map(readBinding) : [];\n\n return { context: undefined, reads: new Set(bindings.filter(name => name !== undefined)) };\n}\n\nfunction isContextRead(callee: TSESTree.MemberExpression, scope: SelectorScope): boolean {\n return (\n !callee.computed &&\n callee.object.type === AST_NODE_TYPES.Identifier &&\n callee.object.name === scope.context &&\n callee.property.type === AST_NODE_TYPES.Identifier &&\n callee.property.name === 'read'\n );\n}\n\nfunction isReadCall(call: TSESTree.CallExpression, scope: SelectorScope): boolean {\n const { callee } = call;\n\n if (callee.type === AST_NODE_TYPES.Identifier) return scope.reads.has(callee.name);\n\n return callee.type === AST_NODE_TYPES.MemberExpression && isContextRead(callee, scope);\n}\n\n/** The call a function expression is the second argument of, where both `useModel` and `read` take a function. */\nfunction secondArgumentOf(node: TSESTree.Node): TSESTree.CallExpression | undefined {\n if (!isFunctionLike(node) || node.parent.type !== AST_NODE_TYPES.CallExpression) return undefined;\n\n return node.parent.arguments[1] === node ? node.parent : undefined;\n}\n\nfunction isInlineSelector(node: TSESTree.Node): boolean {\n const call = secondArgumentOf(node);\n\n return call !== undefined && calleeName(call)?.split('.').at(-1) === 'useModel';\n}\n\n/** The selector this function is, or the selector whose `read` runs it as a projection; nothing for any other. */\nfunction selectorOf(node: TSESTree.Node, enclosing: Frame | undefined): SelectorScope | undefined {\n if (isFunctionLike(node) && isInlineSelector(node)) return selectorScope(node);\n\n const scope = enclosing?.selector;\n const call = secondArgumentOf(node);\n\n return scope !== undefined && call !== undefined && isReadCall(call, scope) ? scope : undefined;\n}\n\n/** What a function answers when its body is one expression or one `return`. */\nfunction answerOf(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression): TSESTree.Node | undefined {\n const { body } = node;\n\n if (body.type !== AST_NODE_TYPES.BlockStatement) return body;\n\n const [statement] = body.body;\n\n return body.body.length === 1 && statement?.type === AST_NODE_TYPES.ReturnStatement\n ? (statement.argument ?? undefined)\n : undefined;\n}\n\n/** `model => model`: the selector answers the model it was handed, sources and all. */\nfunction isIdentitySelector(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression): boolean {\n const [model] = node.params;\n const answer = answerOf(node);\n\n return (\n model?.type === AST_NODE_TYPES.Identifier &&\n answer?.type === AST_NODE_TYPES.Identifier &&\n answer.name === model.name\n );\n}\n\nconst noSnapshotReadInRender = createRule<[], MessageIds>({\n create(context) {\n const frames: Frame[] = [];\n const stack: Frame[] = [];\n\n return {\n ':function'(node: TSESTree.Node): void {\n const selector = selectorOf(node, stack.at(-1));\n const frame: Frame = { hasJsx: false, name: functionName(node), reads: [], selector };\n\n if (isFunctionLike(node) && isInlineSelector(node) && isIdentitySelector(node)) {\n context.report({ messageId: 'selectorIdentity', node });\n }\n\n frames.push(frame);\n stack.push(frame);\n },\n ':function:exit'(): void {\n stack.pop();\n },\n CallExpression(node): void {\n if (isSnapshotRead(node)) stack.at(-1)?.reads.push(node);\n },\n 'JSXElement, JSXFragment'(): void {\n // The elements of a nested callback are still the elements this component renders.\n for (const frame of stack) frame.hasJsx = true;\n },\n 'Program:exit'(): void {\n for (const frame of frames) {\n const messageId = frame.selector !== undefined ? 'snapshotInSelector' : 'snapshotInRender';\n\n if (frame.selector === undefined && !isRenderScope(frame)) continue;\n\n for (const read of frame.reads) context.report({ messageId, node: read });\n }\n },\n };\n },\n meta: {\n docs: {\n description: 'A component reads observed data reactively, not by taking a snapshot while it renders.',\n },\n messages: {\n selectorIdentity:\n 'A selector that answers the model it was handed leaves every source in the selection, and the types refuse each one: select the fields and read(...) every source, or call useModel(Model) without a selector (D476).',\n snapshotInSelector:\n 'getSnapshot() in a selector never updates: the selection keeps the value it read, because only read(source) subscribes the component to it. Use read(source), or read(source, project) (D476).',\n snapshotInRender:\n 'A snapshot taken while rendering is not reactive: the component keeps the value it read and never hears the next one. Read it with `useReadable`, or select it in `useModel(Declaration, (model, { read }) => ...)` (D205, D214).',\n },\n schema: [],\n type: 'problem',\n },\n name: 'no-snapshot-read-in-render',\n});\n\nexport { noSnapshotReadInRender };\n"],"names":["HOOK_NAME","COMPONENT_NAME","isSnapshotRead","node","callee","AST_NODE_TYPES","isRenderScope","frame","readBinding","property","selectorScope","context","bindings","name","isContextRead","scope","isReadCall","call","secondArgumentOf","isFunctionLike","isInlineSelector","calleeName","selectorOf","enclosing","answerOf","body","statement","isIdentitySelector","model","answer","noSnapshotReadInRender","createRule","frames","stack","selector","functionName","messageId","read"],"mappings":"+KAwBA,MAAMA,EAAY,YACZC,EAAiB,SAEvB,SAASC,EAAeC,EAA6B,CACnD,KAAM,CAAE,OAAAC,CAAM,EAAKD,EAEnB,OAAIC,EAAO,OAASC,EAAe,kBAAoBD,EAAO,SAAiB,GAExEA,EAAO,SAAS,OAASC,EAAe,YAAcD,EAAO,SAAS,OAAS,aACxF,CAMA,SAASE,EAAcC,EAAY,CACjC,OAAIA,EAAM,OAAS,OAAkB,GAEjCP,EAAU,KAAKO,EAAM,IAAI,EAAU,GAEhCA,EAAM,QAAUN,EAAe,KAAKM,EAAM,IAAI,CACvD,CAGA,SAASC,EAAYC,EAAsD,CACzE,OAAIA,EAAS,OAASJ,EAAe,UAAYI,EAAS,SAAU,OAEtDA,EAAS,IAAI,OAASJ,EAAe,YAAcI,EAAS,IAAI,OAAS,QAEvEA,EAAS,MAAM,OAASJ,EAAe,WAAaI,EAAS,MAAM,KAAO,MAC5F,CAGA,SAASC,EAAcP,EAAoE,CACzF,MAAMQ,EAAUR,EAAK,OAAO,CAAC,EAE7B,GAAIQ,GAAS,OAASN,EAAe,WAAY,MAAO,CAAE,QAASM,EAAQ,KAAM,MAAO,IAAI,GAAK,EAEjG,MAAMC,EAAWD,GAAS,OAASN,EAAe,cAAgBM,EAAQ,WAAW,IAAIH,CAAW,EAAI,CAAA,EAExG,MAAO,CAAE,QAAS,OAAW,MAAO,IAAI,IAAII,EAAS,OAAOC,GAAQA,IAAS,MAAS,CAAC,CAAC,CAC1F,CAEA,SAASC,EAAcV,EAAmCW,EAAoB,CAC5E,MACE,CAACX,EAAO,UACRA,EAAO,OAAO,OAASC,EAAe,YACtCD,EAAO,OAAO,OAASW,EAAM,SAC7BX,EAAO,SAAS,OAASC,EAAe,YACxCD,EAAO,SAAS,OAAS,MAE7B,CAEA,SAASY,EAAWC,EAA+BF,EAAoB,CACrE,KAAM,CAAE,OAAAX,CAAM,EAAKa,EAEnB,OAAIb,EAAO,OAASC,EAAe,WAAmBU,EAAM,MAAM,IAAIX,EAAO,IAAI,EAE1EA,EAAO,OAASC,EAAe,kBAAoBS,EAAcV,EAAQW,CAAK,CACvF,CAGA,SAASG,EAAiBf,EAAmB,CAC3C,GAAI,GAACgB,EAAehB,CAAI,GAAKA,EAAK,OAAO,OAASE,EAAe,gBAEjE,OAAOF,EAAK,OAAO,UAAU,CAAC,IAAMA,EAAOA,EAAK,OAAS,MAC3D,CAEA,SAASiB,EAAiBjB,EAAmB,CAC3C,MAAMc,EAAOC,EAAiBf,CAAI,EAElC,OAAOc,IAAS,QAAaI,EAAWJ,CAAI,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,IAAM,UACvE,CAGA,SAASK,EAAWnB,EAAqBoB,EAA4B,CACnE,GAAIJ,EAAehB,CAAI,GAAKiB,EAAiBjB,CAAI,EAAG,OAAOO,EAAcP,CAAI,EAE7E,MAAMY,EAAQQ,GAAW,SACnBN,EAAOC,EAAiBf,CAAI,EAElC,OAAOY,IAAU,QAAaE,IAAS,QAAaD,EAAWC,EAAMF,CAAK,EAAIA,EAAQ,MACxF,CAGA,SAASS,EAASrB,EAAoE,CACpF,KAAM,CAAE,KAAAsB,CAAI,EAAKtB,EAEjB,GAAIsB,EAAK,OAASpB,EAAe,eAAgB,OAAOoB,EAExD,KAAM,CAACC,CAAS,EAAID,EAAK,KAEzB,OAAOA,EAAK,KAAK,SAAW,GAAKC,GAAW,OAASrB,EAAe,gBAC/DqB,EAAU,UAAY,OACvB,MACN,CAGA,SAASC,EAAmBxB,EAAoE,CAC9F,KAAM,CAACyB,CAAK,EAAIzB,EAAK,OACf0B,EAASL,EAASrB,CAAI,EAE5B,OACEyB,GAAO,OAASvB,EAAe,YAC/BwB,GAAQ,OAASxB,EAAe,YAChCwB,EAAO,OAASD,EAAM,IAE1B,CAEA,MAAME,EAAyBC,EAA2B,CACxD,OAAOpB,EAAO,CACZ,MAAMqB,EAAkB,CAAA,EAClBC,EAAiB,CAAA,EAEvB,MAAO,CACL,YAAY9B,EAAmB,CAC7B,MAAM+B,EAAWZ,EAAWnB,EAAM8B,EAAM,GAAG,EAAE,CAAC,EACxC1B,EAAe,CAAE,OAAQ,GAAO,KAAM4B,EAAahC,CAAI,EAAG,MAAO,CAAA,EAAI,SAAA+B,CAAQ,EAE/Ef,EAAehB,CAAI,GAAKiB,EAAiBjB,CAAI,GAAKwB,EAAmBxB,CAAI,GAC3EQ,EAAQ,OAAO,CAAE,UAAW,mBAAoB,KAAAR,CAAI,CAAE,EAGxD6B,EAAO,KAAKzB,CAAK,EACjB0B,EAAM,KAAK1B,CAAK,CAClB,EACA,kBAAgB,CACd0B,EAAM,IAAG,CACX,EACA,eAAe9B,EAAI,CACbD,EAAeC,CAAI,GAAG8B,EAAM,GAAG,EAAE,GAAG,MAAM,KAAK9B,CAAI,CACzD,EACA,2BAAyB,CAEvB,UAAWI,KAAS0B,EAAO1B,EAAM,OAAS,EAC5C,EACA,gBAAc,CACZ,UAAWA,KAASyB,EAAQ,CAC1B,MAAMI,EAAY7B,EAAM,WAAa,OAAY,qBAAuB,mBAExE,GAAI,EAAAA,EAAM,WAAa,QAAa,CAACD,EAAcC,CAAK,GAExD,UAAW8B,KAAQ9B,EAAM,MAAOI,EAAQ,OAAO,CAAE,UAAAyB,EAAW,KAAMC,CAAI,CAAE,CAC1E,CACF,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YAAa,wFACd,EACD,SAAU,CACR,iBACE,wNACF,mBACE,iMACF,iBACE,mOACH,EACD,OAAQ,CAAA,EACR,KAAM,SACP,EACD,KAAM,4BACP,CAAA"}
@@ -1,4 +1,2 @@
1
- declare const noSubscribeOutsideModels: import("@typescript-eslint/utils/ts-eslint").RuleModule<"handWrittenSubscription", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
2
- name: string;
3
- };
1
+ declare const noSubscribeOutsideModels: import("../rule.js").RuleModule<"handWrittenSubscription", []>;
4
2
  export { noSubscribeOutsideModels };
@@ -1,2 +1,2 @@
1
- import{AST_NODE_TYPES as t}from"@typescript-eslint/utils";import{isDeclaredIngress as s}from"../declaration-ingress.js";import{createRule as o}from"../rule.js";function n(r){const{callee:e}=r;return e.type!==t.MemberExpression||e.computed||r.arguments.length===0?!1:e.property.type===t.Identifier&&e.property.name==="subscribe"}const i=o({create(r){return{CallExpression(e){!n(e)||s(r.sourceCode,e)||r.report({messageId:"handWrittenSubscription",node:e.callee})}}},meta:{docs:{description:"A hand-written subscription stays in the layer that owns the state it observes."},messages:{handWrittenSubscription:"A subscription written by hand owns a cleanup nobody here can see. In a component read with `useReadable` or a model selection; in a feature or a model declare `effect`, `event` or the `connect` of `resource.live`."},schema:[],type:"problem"},name:"no-subscribe-outside-models"});export{i as noSubscribeOutsideModels};
1
+ import{isSubscribeCall as r,isDeclaredIngress as t,enclosingBuilder as o}from"../declaration-ingress.js";import{createRule as n}from"../rule.js";const i=n({create(s){return{CallExpression(e){!r(e)||t(s.sourceCode,e)||o(s.sourceCode,e)!==void 0||s.report({messageId:"handWrittenSubscription",node:e.callee})}}},meta:{docs:{description:"A hand-written subscription stays in the layer that owns the state it observes."},messages:{handWrittenSubscription:"A subscription written by hand owns a cleanup nobody here can see. In a component read with `useReadable` or a model selection; declare `effect`, `event` or the `connect` of `resource.live` in a model."},schema:[],type:"problem"},name:"no-subscribe-outside-models"});export{i as noSubscribeOutsideModels};
2
2
  //# sourceMappingURL=no-subscribe-outside-models.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"no-subscribe-outside-models.js","sources":["../../src/rules/no-subscribe-outside-models.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nimport { isDeclaredIngress } from '../declaration-ingress';\nimport { createRule } from '../rule';\n\ntype MessageIds = 'handWrittenSubscription';\n\n/** A call, not a reference: `useSyncExternalStore(source.subscribe, …)` hands the function over without calling it. */\nfunction isSubscribeCall(node: TSESTree.CallExpression): boolean {\n const { callee } = node;\n\n if (callee.type !== AST_NODE_TYPES.MemberExpression || callee.computed || node.arguments.length === 0) return false;\n\n return callee.property.type === AST_NODE_TYPES.Identifier && callee.property.name === 'subscribe';\n}\n\nconst noSubscribeOutsideModels = createRule<[], MessageIds>({\n create(context) {\n return {\n CallExpression(node): void {\n if (!isSubscribeCall(node) || isDeclaredIngress(context.sourceCode, node)) return;\n\n context.report({ messageId: 'handWrittenSubscription', node: node.callee });\n },\n };\n },\n meta: {\n docs: {\n description: 'A hand-written subscription stays in the layer that owns the state it observes.',\n },\n messages: {\n handWrittenSubscription:\n 'A subscription written by hand owns a cleanup nobody here can see. In a component read with `useReadable` or a model selection; in a feature or a model declare `effect`, `event` or the `connect` of `resource.live`.',\n },\n schema: [],\n type: 'problem',\n },\n name: 'no-subscribe-outside-models',\n});\n\nexport { noSubscribeOutsideModels };\n"],"names":["isSubscribeCall","node","callee","AST_NODE_TYPES","noSubscribeOutsideModels","createRule","context","isDeclaredIngress"],"mappings":"gKASA,SAASA,EAAgBC,EAA6B,CACpD,KAAM,CAAE,OAAAC,CAAM,EAAKD,EAEnB,OAAIC,EAAO,OAASC,EAAe,kBAAoBD,EAAO,UAAYD,EAAK,UAAU,SAAW,EAAU,GAEvGC,EAAO,SAAS,OAASC,EAAe,YAAcD,EAAO,SAAS,OAAS,WACxF,CAEA,MAAME,EAA2BC,EAA2B,CAC1D,OAAOC,EAAO,CACZ,MAAO,CACL,eAAeL,EAAI,CACb,CAACD,EAAgBC,CAAI,GAAKM,EAAkBD,EAAQ,WAAYL,CAAI,GAExEK,EAAQ,OAAO,CAAE,UAAW,0BAA2B,KAAML,EAAK,OAAQ,CAC5E,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YAAa,iFACd,EACD,SAAU,CACR,wBACE,wNACH,EACD,OAAQ,CAAA,EACR,KAAM,SACP,EACD,KAAM,6BACP,CAAA"}
1
+ {"version":3,"file":"no-subscribe-outside-models.js","sources":["../../src/rules/no-subscribe-outside-models.ts"],"sourcesContent":["import { enclosingBuilder, isDeclaredIngress, isSubscribeCall } from '../declaration-ingress';\nimport { createRule } from '../rule';\n\ntype MessageIds = 'handWrittenSubscription';\n\nconst noSubscribeOutsideModels = createRule<[], MessageIds>({\n create(context) {\n return {\n CallExpression(node): void {\n if (\n !isSubscribeCall(node) ||\n isDeclaredIngress(context.sourceCode, node) ||\n // D470: the body of a model scope builder answers to `scope-builder-releases-subscriptions`, in every layer.\n enclosingBuilder(context.sourceCode, node) !== undefined\n ) {\n return;\n }\n\n context.report({ messageId: 'handWrittenSubscription', node: node.callee });\n },\n };\n },\n meta: {\n docs: {\n description: 'A hand-written subscription stays in the layer that owns the state it observes.',\n },\n messages: {\n handWrittenSubscription:\n 'A subscription written by hand owns a cleanup nobody here can see. In a component read with `useReadable` or a model selection; declare `effect`, `event` or the `connect` of `resource.live` in a model.',\n },\n schema: [],\n type: 'problem',\n },\n name: 'no-subscribe-outside-models',\n});\n\nexport { noSubscribeOutsideModels };\n"],"names":["noSubscribeOutsideModels","createRule","context","node","isSubscribeCall","isDeclaredIngress","enclosingBuilder"],"mappings":"iJAKA,MAAMA,EAA2BC,EAA2B,CAC1D,OAAOC,EAAO,CACZ,MAAO,CACL,eAAeC,EAAI,CAEf,CAACC,EAAgBD,CAAI,GACrBE,EAAkBH,EAAQ,WAAYC,CAAI,GAE1CG,EAAiBJ,EAAQ,WAAYC,CAAI,IAAM,QAKjDD,EAAQ,OAAO,CAAE,UAAW,0BAA2B,KAAMC,EAAK,OAAQ,CAC5E,EAEJ,EACA,KAAM,CACJ,KAAM,CACJ,YAAa,iFACd,EACD,SAAU,CACR,wBACE,2MACH,EACD,OAAQ,CAAA,EACR,KAAM,SACP,EACD,KAAM,6BACP,CAAA"}
@@ -1,6 +1,3 @@
1
- import type { TSESLint } from '@typescript-eslint/utils';
2
1
  type MessageIds = 'writeAfterInvokedSourceWrite' | 'writeAfterSourceWrite';
3
- declare const noWriteAfterSourceWrite: TSESLint.RuleModule<MessageIds, [], unknown, TSESLint.RuleListener> & {
4
- name: string;
5
- };
2
+ declare const noWriteAfterSourceWrite: import("../rule.js").RuleModule<MessageIds, []>;
6
3
  export { noWriteAfterSourceWrite };
@@ -1,2 +1,2 @@
1
- import{AST_NODE_TYPES as a}from"@typescript-eslint/utils";import{within as E}from"../ast.js";import{contextMembers as C,fromContext as k}from"../context-members.js";import{methodPath as h,isContextFunction as x,isModelContextFunction as A,commandBody as D}from"../declaration-ingress.js";import{declaredEffect as T}from"../effect-declarations.js";import{localValue as u,unwrap as f,variableOf as d,isApi as O,enclosingFunction as W,isFunction as M}from"../model-bindings.js";import{createRule as N}from"../rule.js";const m=["update"],P=["invoke"],w=1,R=0,B=new Set(["!=","!==","<","<=","==","===",">",">=","in","instanceof"]),F=new Set(["!","typeof"]),g=new Set([a.ReturnStatement,a.ThrowStatement]);function _(t,e){const n=u(t,e);if(n.type!==a.CallExpression)return!1;const r=h(t,n.callee);return r?.method==="state"&&x(t,r.fn)}function q(t,e){if(e.type!==a.CallExpression||!O(t,e.callee,"@opetope/core","derive",!0))return;const[n,r]=e.arguments;if(n===void 0)return;const i=f(n);return i.type!==a.ArrayExpression?{dependencies:[i],selector:r}:{dependencies:i.elements.flatMap(o=>o===null?[]:[o]),selector:r}}function K(t){const{parent:e}=t;return e.type===a.BinaryExpression?B.has(e.operator):e.type===a.UnaryExpression?F.has(e.operator):(e.type===a.ConditionalExpression||e.type===a.IfStatement)&&e.test===t}function L(t,e,n){const r=e===void 0?void 0:u(t,e);if(r===void 0||!M(r))return;const i=r.params[n];return i?.type===a.Identifier?i:void 0}function V(t,e,n){const r=L(t,e,n);return(r===void 0?null:d(t,r))?.references.some(({identifier:o})=>o.type===a.Identifier&&!K(o))??!1}function S(t,e,n){const r=f(n);if(r.type!==a.Identifier)return;const i=d(t,r);i!==null&&_(t,r)&&e.add(i)}function Y(t,e){const n=new Set;S(t,n,e);const r=q(t,u(t,e));if(r===void 0)return n;for(const[i,o]of r.dependencies.entries())V(t,r.selector,i)&&S(t,n,o);return n}function p(t,e,n,r,i){const o=C(t,e,r,[i],n.declarators);return n.calls.filter(s=>E(s,e)&&W(t,s)===e).filter(s=>k(t,s.callee,o,i)).sort((s,c)=>s.range[0]-c.range[0])}function X(t,e,n){return p(t,e,n,w,m[0])}function v(t,e,n){const[r]=e.arguments;if(r===void 0)return!1;const i=f(r);if(i.type!==a.Identifier)return!1;const o=d(t,i);return o!==null&&n.has(o)}function z(t,e){const n=u(t,f(e));if(n.type!==a.CallExpression)return;const r=h(t,n.callee);if(r?.method==="command")return A(t,r.fn)?D(t,n):void 0}function U(t,e,n,r){const[i]=e.arguments,o=i===void 0?void 0:z(t,i);return o===void 0?!1:p(t,o,n,R,m[0]).some(s=>v(t,s,r))}function y(t){let e=t;for(;e.type===a.BlockStatement;){const n=e.body.at(-1);if(n===void 0)return;e=n}return e}function b(t){const e=y(t);return e!==void 0&&g.has(e.type)}function j(t){const e=y(t);return e===void 0?!1:g.has(e.type)?!0:e.type!==a.IfStatement||e.alternate===null?!1:b(e.consequent)&&b(e.alternate)}function G(t,e,n){const r=e.range[1],i=n.range[0],o=s=>s.range[0]>=r&&s.range[1]<=i&&j(s);return t.getAncestors(e).some(s=>s.type===a.BlockStatement&&s.body.some(o))}function H(t,e){const n=Math.min(t.length,e.length);let r=0;for(;r<n&&t[r]===e[r];)r+=1;return r}function I(t,e,n){const r=[...t.getAncestors(e),e],i=[...t.getAncestors(n),n],o=H(r,i),s=o===0?void 0:r[o-1],c=r[o],l=i[o];return s?.type!==a.BlockStatement||c===void 0||l===void 0?!1:c.range[1]<=l.range[0]&&!G(t,e,n)}const J=N({create(t){const e=t.sourceCode,n={calls:[],declarators:[]},r=(i,o)=>{const s=X(e,i,n);for(const c of s)v(e,c,o)&&s.some(l=>I(e,c,l))&&t.report({messageId:"writeAfterSourceWrite",node:c});for(const c of p(e,i,n,w,P[0]))U(e,c,n,o)&&s.some(l=>I(e,c,l))&&t.report({messageId:"writeAfterInvokedSourceWrite",node:c})};return{CallExpression(i){n.calls.push(i)},"Program:exit"(){for(const i of n.calls){const o=T(e,i);if(o===void 0)continue;const s=Y(e,o.from);s.size>0&&r(o.run,s)}},VariableDeclarator(i){n.declarators.push(i)}}},meta:{docs:{description:"A write into the own source of an effect, its own or a command it invokes, is that run last."},messages:{writeAfterInvokedSourceWrite:"The command this call starts writes into a cell this run's own source reads, so unless that write leaves the published value equal it ends this run inside the command: `invoke` gives the command the cancellation of the run, and one abort ends them both. Everything of the run after this call is then lost \u2014 a write it reaches is dropped and reaches the reporter as `LostWrite`, and a body still awaiting this call is cut short with a cancellation and reaches no write at all. Make the write into the source the last write of the run, or keep what the run accumulates out of its source and read it with `getSnapshot()`, or take `execution.capture(state)` before the moving write \u2014 a commit outlives the run and answers `applied` or `cancelled` (D288, D319, D365, D432, D447).",writeAfterSourceWrite:"This write goes into a cell this run's own source reads, so unless it leaves the published value equal it ends this run inside the write itself, and every write of the run after it is dropped. The first of those dropped writes reaches the reporter as `LostWrite`, once per run, saying the rest went with it. Make the write into the source the last write of the run, or keep what the run accumulates out of its source and read it with `getSnapshot()`, or take `execution.capture(state)` before the moving write \u2014 a commit outlives the run and answers `applied` or `cancelled` (D288, D319, D365, D432, D447)."},schema:[],type:"problem"},name:"no-write-after-source-write"});export{J as noWriteAfterSourceWrite};
1
+ import{AST_NODE_TYPES as a}from"@typescript-eslint/types";import{within as E}from"../ast.js";import{contextMembers as C,fromContext as k}from"../context-members.js";import{methodPath as h,isModelContextFunction as x,commandBody as A,isContextFunction as D}from"../declaration-ingress.js";import{declaredEffect as T}from"../effect-declarations.js";import{localValue as u,unwrap as d,variableOf as f,enclosingFunction as O,isApi as W,isFunction as M}from"../model-bindings.js";import{createRule as N}from"../rule.js";const m=["update"],P=["invoke"],w=1,R=0,B=new Set(["!=","!==","<","<=","==","===",">",">=","in","instanceof"]),F=new Set(["!","typeof"]),g=new Set([a.ReturnStatement,a.ThrowStatement]);function _(t,e){const n=u(t,e);if(n.type!==a.CallExpression)return!1;const r=h(t,n.callee);return r?.method==="state"&&D(t,r.fn)}function q(t,e){if(e.type!==a.CallExpression||!W(t,e.callee,"@opetope/core","derive",!0))return;const[n,r]=e.arguments;if(n===void 0)return;const i=d(n);return i.type!==a.ArrayExpression?{dependencies:[i],selector:r}:{dependencies:i.elements.flatMap(o=>o===null?[]:[o]),selector:r}}function K(t){const{parent:e}=t;return e.type===a.BinaryExpression?B.has(e.operator):e.type===a.UnaryExpression?F.has(e.operator):(e.type===a.ConditionalExpression||e.type===a.IfStatement)&&e.test===t}function L(t,e,n){const r=e===void 0?void 0:u(t,e);if(r===void 0||!M(r))return;const i=r.params[n];return i?.type===a.Identifier?i:void 0}function V(t,e,n){const r=L(t,e,n);return(r===void 0?null:f(t,r))?.references.some(({identifier:o})=>o.type===a.Identifier&&!K(o))??!1}function v(t,e,n){const r=d(n);if(r.type!==a.Identifier)return;const i=f(t,r);i!==null&&_(t,r)&&e.add(i)}function Y(t,e){const n=new Set;v(t,n,e);const r=q(t,u(t,e));if(r===void 0)return n;for(const[i,o]of r.dependencies.entries())V(t,r.selector,i)&&v(t,n,o);return n}function p(t,e,n,r,i){const o=C(t,e,r,[i],n.declarators);return n.calls.filter(s=>E(s,e)&&O(t,s)===e).filter(s=>k(t,s.callee,o,i)).sort((s,c)=>s.range[0]-c.range[0])}function X(t,e,n){return p(t,e,n,w,m[0])}function S(t,e,n){const[r]=e.arguments;if(r===void 0)return!1;const i=d(r);if(i.type!==a.Identifier)return!1;const o=f(t,i);return o!==null&&n.has(o)}function z(t,e){const n=u(t,d(e));if(n.type!==a.CallExpression)return;const r=h(t,n.callee);if(r?.method==="command")return x(t,r.fn)?A(t,n):void 0}function U(t,e,n,r){const[i]=e.arguments,o=i===void 0?void 0:z(t,i);return o===void 0?!1:p(t,o,n,R,m[0]).some(s=>S(t,s,r))}function y(t){let e=t;for(;e.type===a.BlockStatement;){const n=e.body.at(-1);if(n===void 0)return;e=n}return e}function b(t){const e=y(t);return e!==void 0&&g.has(e.type)}function j(t){const e=y(t);return e===void 0?!1:g.has(e.type)?!0:e.type!==a.IfStatement||e.alternate===null?!1:b(e.consequent)&&b(e.alternate)}function G(t,e,n){const r=e.range[1],i=n.range[0],o=s=>s.range[0]>=r&&s.range[1]<=i&&j(s);return t.getAncestors(e).some(s=>s.type===a.BlockStatement&&s.body.some(o))}function H(t,e){const n=Math.min(t.length,e.length);let r=0;for(;r<n&&t[r]===e[r];)r+=1;return r}function I(t,e,n){const r=[...t.getAncestors(e),e],i=[...t.getAncestors(n),n],o=H(r,i),s=o===0?void 0:r[o-1],c=r[o],l=i[o];return s?.type!==a.BlockStatement||c===void 0||l===void 0?!1:c.range[1]<=l.range[0]&&!G(t,e,n)}const J=N({create(t){const e=t.sourceCode,n={calls:[],declarators:[]},r=(i,o)=>{const s=X(e,i,n);for(const c of s)S(e,c,o)&&s.some(l=>I(e,c,l))&&t.report({messageId:"writeAfterSourceWrite",node:c});for(const c of p(e,i,n,w,P[0]))U(e,c,n,o)&&s.some(l=>I(e,c,l))&&t.report({messageId:"writeAfterInvokedSourceWrite",node:c})};return{CallExpression(i){n.calls.push(i)},"Program:exit"(){for(const i of n.calls){const o=T(e,i);if(o===void 0)continue;const s=Y(e,o.from);s.size>0&&r(o.run,s)}},VariableDeclarator(i){n.declarators.push(i)}}},meta:{docs:{description:"A write into the own source of an effect, its own or a command it invokes, is that run last."},messages:{writeAfterInvokedSourceWrite:"The command this call starts writes into a cell this run's own source reads, so unless that write leaves the published value equal it ends this run inside the command: `invoke` gives the command the cancellation of the run, and one abort ends them both. Everything of the run after this call is then lost \u2014 a write it reaches is dropped and reaches the reporter as `LostWrite`, and a body still awaiting this call is cut short with a cancellation and reaches no write at all. Make the write into the source the last write of the run, or keep what the run accumulates out of its source and read it with `read`, or take `execution.capture(state)` before the moving write \u2014 a commit outlives the run and answers `applied` or `cancelled` (D288, D319, D365, D432, D447).",writeAfterSourceWrite:"This write goes into a cell this run's own source reads, so unless it leaves the published value equal it ends this run inside the write itself, and every write of the run after it is dropped. The first of those dropped writes reaches the reporter as `LostWrite`, once per run, saying the rest went with it. Make the write into the source the last write of the run, or keep what the run accumulates out of its source and read it with `read`, or take `execution.capture(state)` before the moving write \u2014 a commit outlives the run and answers `applied` or `cancelled` (D288, D319, D365, D432, D447)."},schema:[],type:"problem"},name:"no-write-after-source-write"});export{J as noWriteAfterSourceWrite};
2
2
  //# sourceMappingURL=no-write-after-source-write.js.map