@opetope/lint 0.14.0 → 0.15.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.
- package/CHANGELOG.md +62 -0
- package/README.md +39 -2
- package/dist/ast.d.ts +14 -2
- package/dist/ast.js +1 -1
- package/dist/ast.js.map +1 -1
- package/dist/command-hooks.d.ts +7 -6
- package/dist/command-hooks.js +1 -1
- package/dist/command-hooks.js.map +1 -1
- package/dist/context-members.d.ts +4 -4
- package/dist/context-members.js +1 -1
- package/dist/context-members.js.map +1 -1
- package/dist/declaration-ingress.d.ts +43 -11
- package/dist/declaration-ingress.js +1 -1
- package/dist/declaration-ingress.js.map +1 -1
- package/dist/declarations.d.ts +1 -1
- package/dist/declarations.js +1 -1
- package/dist/declarations.js.map +1 -1
- package/dist/effect-declarations.d.ts +3 -2
- package/dist/effect-declarations.js +1 -1
- package/dist/effect-declarations.js.map +1 -1
- package/dist/entry-move-rows.d.ts +21 -0
- package/dist/entry-move-rows.js +2 -0
- package/dist/entry-move-rows.js.map +1 -0
- package/dist/entry-moves.d.ts +25 -0
- package/dist/entry-moves.js +10 -0
- package/dist/entry-moves.js.map +1 -0
- package/dist/feature-body-records.d.ts +5 -3
- package/dist/feature-body-records.js +1 -1
- package/dist/feature-body-records.js.map +1 -1
- package/dist/index.d.ts +65 -58
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lazy-body-migration.d.ts +5 -5
- package/dist/lazy-body-migration.js +1 -1
- package/dist/lazy-body-migration.js.map +1 -1
- package/dist/model-bindings.d.ts +21 -13
- package/dist/model-bindings.js +1 -1
- package/dist/model-bindings.js.map +1 -1
- package/dist/resource-vocabulary.d.ts +17 -0
- package/dist/resource-vocabulary.js +2 -0
- package/dist/resource-vocabulary.js.map +1 -0
- package/dist/retired-vocabulary-messages.d.ts +6 -0
- package/dist/retired-vocabulary-messages.js +2 -0
- package/dist/retired-vocabulary-messages.js.map +1 -0
- package/dist/retired-vocabulary.d.ts +10 -8
- package/dist/retired-vocabulary.js +1 -1
- package/dist/retired-vocabulary.js.map +1 -1
- package/dist/rule.d.ts +94 -5
- package/dist/rule.js +1 -1
- package/dist/rule.js.map +1 -1
- package/dist/rules/capture-command-cleanup.d.ts +1 -4
- package/dist/rules/capture-command-cleanup.js +1 -1
- package/dist/rules/capture-command-cleanup.js.map +1 -1
- package/dist/rules/define-feature-property-order.d.ts +1 -4
- package/dist/rules/define-feature-property-order.js +1 -1
- package/dist/rules/define-feature-property-order.js.map +1 -1
- package/dist/rules/enabled-predicate.d.ts +1 -4
- package/dist/rules/enabled-predicate.js +1 -1
- package/dist/rules/enabled-predicate.js.map +1 -1
- package/dist/rules/id-naming.d.ts +1 -3
- package/dist/rules/layer-placement.d.ts +1 -3
- package/dist/rules/no-behavior-in-integration.d.ts +8 -0
- package/dist/rules/no-behavior-in-integration.js +2 -0
- package/dist/rules/no-behavior-in-integration.js.map +1 -0
- package/dist/rules/no-command-in-deps.d.ts +1 -4
- package/dist/rules/no-command-in-deps.js +1 -1
- package/dist/rules/no-command-in-deps.js.map +1 -1
- package/dist/rules/no-dead-abort-check.d.ts +8 -0
- package/dist/rules/no-dead-abort-check.js +2 -0
- package/dist/rules/no-dead-abort-check.js.map +1 -0
- package/dist/rules/no-event-without-emit.d.ts +10 -0
- package/dist/rules/no-event-without-emit.js +2 -0
- package/dist/rules/no-event-without-emit.js.map +1 -0
- package/dist/rules/no-inline-requires-models.d.ts +8 -0
- package/dist/rules/no-inline-requires-models.js +5 -0
- package/dist/rules/no-inline-requires-models.js.map +1 -0
- package/dist/rules/no-internal-imports.d.ts +1 -3
- package/dist/rules/no-internal-imports.js +1 -1
- package/dist/rules/no-internal-imports.js.map +1 -1
- package/dist/rules/no-redundant-const-tuple.d.ts +1 -4
- package/dist/rules/no-redundant-const-tuple.js +1 -1
- package/dist/rules/no-redundant-const-tuple.js.map +1 -1
- package/dist/rules/no-retired-vocabulary.d.ts +2 -4
- package/dist/rules/no-retired-vocabulary.js +1 -1
- package/dist/rules/no-retired-vocabulary.js.map +1 -1
- package/dist/rules/no-single-command-lane.d.ts +10 -0
- package/dist/rules/no-single-command-lane.js +2 -0
- package/dist/rules/no-single-command-lane.js.map +1 -0
- package/dist/rules/no-snapshot-in-update.d.ts +1 -4
- package/dist/rules/no-snapshot-in-update.js.map +1 -1
- package/dist/rules/no-snapshot-read-in-render.d.ts +2 -3
- package/dist/rules/no-snapshot-read-in-render.js +1 -1
- package/dist/rules/no-snapshot-read-in-render.js.map +1 -1
- package/dist/rules/no-subscribe-outside-models.d.ts +1 -3
- package/dist/rules/no-subscribe-outside-models.js +1 -1
- package/dist/rules/no-subscribe-outside-models.js.map +1 -1
- package/dist/rules/no-write-after-source-write.d.ts +1 -4
- package/dist/rules/no-write-after-source-write.js +1 -1
- package/dist/rules/no-write-after-source-write.js.map +1 -1
- package/dist/rules/prefer-derive.d.ts +7 -0
- package/dist/rules/prefer-derive.js +2 -0
- package/dist/rules/prefer-derive.js.map +1 -0
- package/dist/rules/prefer-effect-current.d.ts +1 -4
- package/dist/rules/prefer-effect-current.js +1 -1
- package/dist/rules/prefer-effect-current.js.map +1 -1
- package/dist/rules/prefer-lazy-body-record.d.ts +1 -4
- package/dist/rules/prefer-lazy-body-record.js +1 -1
- package/dist/rules/prefer-lazy-body-record.js.map +1 -1
- package/dist/rules/prefer-model-selection.d.ts +1 -3
- package/dist/rules/prefer-model-selection.js +1 -1
- package/dist/rules/prefer-model-selection.js.map +1 -1
- package/dist/rules/prefer-read.d.ts +2 -0
- package/dist/rules/prefer-read.js +2 -0
- package/dist/rules/prefer-read.js.map +1 -0
- package/dist/rules/prefer-when-over-enabled.d.ts +7 -0
- package/dist/rules/prefer-when-over-enabled.js +2 -0
- package/dist/rules/prefer-when-over-enabled.js.map +1 -0
- package/dist/rules/require-declared-models.d.ts +1 -3
- package/dist/rules/require-declared-models.js +1 -1
- package/dist/rules/require-declared-models.js.map +1 -1
- package/dist/rules/require-literal-id.d.ts +2 -3
- package/dist/rules/require-literal-id.js +1 -1
- package/dist/rules/require-literal-id.js.map +1 -1
- package/dist/rules/require-static-feature.d.ts +9 -0
- package/dist/rules/require-static-feature.js +2 -0
- package/dist/rules/require-static-feature.js.map +1 -0
- package/dist/rules/scope-builder-releases-subscriptions.d.ts +10 -0
- package/dist/rules/scope-builder-releases-subscriptions.js +2 -0
- package/dist/rules/scope-builder-releases-subscriptions.js.map +1 -0
- package/dist/snapshot-updates.d.ts +4 -3
- package/dist/snapshot-updates.js +1 -1
- package/dist/snapshot-updates.js.map +1 -1
- package/dist/static-value.d.ts +3 -2
- package/dist/static-value.js +1 -1
- package/dist/static-value.js.map +1 -1
- package/oxlintrc.json +10 -0
- package/package.json +13 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"declaration-ingress.js","sources":["../src/declaration-ingress.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES, TSESLint } from '@typescript-eslint/utils';\n\nimport { propertyName } from './ast';\nimport type { FunctionNode } from './model-bindings';\nimport { definitionOf, isApi, isFeatureSection, isFunction, localValue, unwrap } from './model-bindings';\n\n/**\n * The callbacks a declared node opens its work in and owns the release of: the disposer they return is run by the\n * node, in the drain of the generation that opened it. The argument index is part of the contract — `run`, `load`,\n * `filter` and `key` sit in the same calls and are not ingress.\n *\n * D458: the subscription of an event is the third argument, because `run` moved in front of it.\n */\nconst positionalIngress = new Map([\n ['event', 2],\n // D378: the key of `each` stands between the source and the child, so the callback that opens is the third argument.\n ['scope.each', 2],\n ['scope.switch', 1],\n ['scope.while', 1],\n]);\n\n/**\n * The callbacks written as a record member. `attach`'s `close` is a release, not an opening; D349 puts the connection\n * of a live Resource under `connect` in the one options record, so that is where the ingress of a subscription is.\n */\nconst recordIngress = new Map([\n ['attach', { argument: 1, property: 'open' }],\n ['resource.live', { argument: 0, property: 'connect' }],\n]);\n\ntype Annotated = TSESTree.Identifier | TSESTree.ObjectPattern;\ntype NamedMethod = { readonly fn: FunctionNode; readonly method: string };\ntype ParameterOf = { readonly fn: FunctionNode; readonly name: TSESTree.BindingName };\n\nfunction annotatedParameter(fn: FunctionNode): Annotated | undefined {\n const [parameter] = fn.params;\n\n if (parameter?.type === AST_NODE_TYPES.Identifier || parameter?.type === AST_NODE_TYPES.ObjectPattern) {\n return parameter;\n }\n\n return undefined;\n}\n\n/** The factory of a model says so in the parameter it takes: the name `ModelContext` carries where it is exported. */\nfunction declaresModelContext(source: TSESLint.SourceCode, fn: FunctionNode): boolean {\n const annotation = annotatedParameter(fn)?.typeAnnotation?.typeAnnotation;\n\n if (annotation?.type !== AST_NODE_TYPES.TSTypeReference) return false;\n\n const { typeName } = annotation;\n\n return typeName.type === AST_NODE_TYPES.Identifier && isApi(source, typeName, '@opetope/core', 'ModelContext', true);\n}\n\n/** The function this name is a parameter of, and the pattern node that bound it there. */\nfunction parameterOf(source: TSESLint.SourceCode, node: TSESTree.Identifier): ParameterOf | undefined {\n const definition = definitionOf(source, node);\n\n if (definition?.type !== TSESLint.Scope.DefinitionType.Parameter || !isFunction(definition.node)) return undefined;\n\n return { fn: definition.node, name: definition.name };\n}\n\n/** `own` itself: the plain name a context parameter was given, whichever function that parameter belongs to. */\nfunction contextName(source: TSESLint.SourceCode, node: TSESTree.Identifier): FunctionNode | undefined {\n const parameter = parameterOf(source, node);\n\n return parameter !== undefined && parameter.name === parameter.fn.params[0] ? parameter.fn : undefined;\n}\n\n/** `({ resource }) => resource.live(…)`: the method under the key the destructuring took it from, alias included. */\nfunction destructuredMethod(source: TSESLint.SourceCode, node: TSESTree.Identifier): NamedMethod | undefined {\n const parameter = parameterOf(source, node);\n const property = parameter?.name.parent;\n\n if (parameter === undefined || property?.type !== AST_NODE_TYPES.Property) return undefined;\n\n const method = property.parent === parameter.fn.params[0] ? propertyName(property) : undefined;\n\n return method === undefined ? undefined : { fn: parameter.fn, method };\n}\n\n/** The dotted steps of a member chain and the name it starts from: `own.scope.while` is `own` and `scope.while`. */\nfunction memberSteps(callee: TSESTree.Node): { root: TSESTree.Node; steps: readonly string[] } | undefined {\n const steps: string[] = [];\n let current: TSESTree.Node = callee;\n\n while (current.type === AST_NODE_TYPES.MemberExpression) {\n if (current.computed || current.property.type !== AST_NODE_TYPES.Identifier) return undefined;\n\n steps.unshift(current.property.name);\n current = current.object;\n }\n\n return { root: current, steps };\n}\n\n/**\n * The method this callee names on the first parameter of some function, and that function. Whether the parameter\n * really is a declaring context is a separate question: answering it here would make the two questions circular.\n */\nfunction methodPath(source: TSESLint.SourceCode, callee: TSESTree.Node): NamedMethod | undefined {\n const chain = memberSteps(callee);\n\n if (chain?.root.type !== AST_NODE_TYPES.Identifier) return undefined;\n\n const named = chain.steps.length === 0 ? undefined : contextName(source, chain.root);\n\n if (named !== undefined) return { fn: named, method: chain.steps.join('.') };\n\n const destructured = destructuredMethod(source, chain.root);\n\n return destructured === undefined\n ? undefined\n : { fn: destructured.fn, method: [destructured.method, ...chain.steps].join('.') };\n}\n\n/** One step outward: the context whose `model(…)` call declares this factory, where that is how it was written. */\nfunction declaringContext(source: TSESLint.SourceCode, fn: FunctionNode): FunctionNode | undefined {\n const call = fn.parent;\n\n if (call.type !== AST_NODE_TYPES.CallExpression || call.arguments[1] !== fn) return undefined;\n\n const declaring = methodPath(source, call.callee);\n\n return declaring?.method === 'model' ? declaring.fn : undefined;\n}\n\n/**\n * The two functions that hand an author a declaring context: the `own` section written right where `defineFeature`\n * takes it, and the factory of a model — which is either annotated as one or written where a feature declares it,\n * as the second argument of `model(Declaration, factory)`. That second form is proved by walking outward one\n * `model(…)` at a time, and the set of functions already visited ends a chain that would come back to its start.\n */\nfunction isContextFunction(source: TSESLint.SourceCode, fn: FunctionNode): boolean {\n const seen = new Set<FunctionNode>();\n let current: FunctionNode | undefined = fn;\n\n while (current !== undefined && !seen.has(current)) {\n seen.add(current);\n\n if (isFeatureSection(source, current, 'own', true) || declaresModelContext(source, current)) return true;\n\n current = declaringContext(source, current);\n }\n\n return false;\n}\n\n/**\n * D330: the context of a model and nothing else. The `own` section of a feature is a declaring context too, but its\n * `command` takes the body second and hands it no writer (D139, D385), so a rule about the writer of a command asks\n * this.\n */\nfunction isModelContextFunction(source: TSESLint.SourceCode, fn: FunctionNode): boolean {\n if (declaresModelContext(source, fn)) return true;\n\n const declaring = declaringContext(source, fn);\n\n return declaring !== undefined && isContextFunction(source, declaring);\n}\n\nfunction admitsIngress(method: string, position: number, property: string | undefined): boolean {\n if (positionalIngress.get(method) === position) return true;\n\n const record = recordIngress.get(method);\n\n return record?.argument === position && record.property === property;\n}\n\n/** The shape decides first and the import second: a call that cannot be ingress never pays for the resolution. */\nfunction isIngressArgument(\n source: TSESLint.SourceCode,\n call: TSESTree.CallExpression,\n position: number,\n property: string | undefined,\n): boolean {\n const named = methodPath(source, call.callee);\n\n return named !== undefined && admitsIngress(named.method, position, property) && isContextFunction(source, named.fn);\n}\n\n/** The record member the walk came through since the last call boundary: the `{ open }` of an `attach`. */\nfunction memberProperty(parent: TSESTree.Node, child: TSESTree.Node, current: string | undefined): string | undefined {\n if (parent.type !== AST_NODE_TYPES.ObjectExpression || child.type !== AST_NODE_TYPES.Property) return current;\n\n return propertyName(child);\n}\n\n/**\n * Whether this node stands lexically inside a callback whose opened work the declared node releases. The walk goes\n * all the way out, so a nested function body counts; only the resolved context and the position decide.\n */\nfunction isDeclaredIngress(source: TSESLint.SourceCode, node: TSESTree.Node): boolean {\n let child: TSESTree.Node = node;\n let property: string | undefined;\n\n for (const parent of source.getAncestors(node).reverse()) {\n if (parent.type === AST_NODE_TYPES.CallExpression) {\n const position = parent.arguments.indexOf(child as TSESTree.CallExpressionArgument);\n\n if (position !== -1 && isIngressArgument(source, parent, position, property)) return true;\n\n property = undefined;\n } else {\n property = memberProperty(parent, child, property);\n }\n\n child = parent;\n }\n\n return false;\n}\n\n/**\n * `context.command(run, options?)`: the body a model command is declared with, inline or bound to a local name.\n * D447: two rules read the writes of one command body — `capture-command-cleanup` where the declaration stands, and\n * `no-write-after-source-write` where a run invokes the name that holds it — so the resolution is one function here\n * rather than the same six lines twice.\n */\nfunction commandBody(source: TSESLint.SourceCode, call: TSESTree.CallExpression): FunctionNode | undefined {\n const [body] = call.arguments;\n\n if (body === undefined || body.type === AST_NODE_TYPES.SpreadElement) return undefined;\n\n const value = localValue(source, unwrap(body));\n\n return isFunction(value) ? value : undefined;\n}\n\n/**\n * D323: a rule that rewrites code has to resolve its package exactly (D309), and this pair is that resolution: the\n * method a callee names on a declaring context, and whether that parameter really is one.\n */\nexport { commandBody, isContextFunction, isDeclaredIngress, isModelContextFunction, methodPath };\n"],"names":["positionalIngress","recordIngress","annotatedParameter","fn","parameter","AST_NODE_TYPES","declaresModelContext","source","annotation","typeName","isApi","parameterOf","node","definition","definitionOf","TSESLint","isFunction","contextName","destructuredMethod","property","method","propertyName","memberSteps","callee","steps","current","methodPath","chain","named","destructured","declaringContext","call","declaring","isContextFunction","seen","isFeatureSection","isModelContextFunction","admitsIngress","position","record","isIngressArgument","memberProperty","parent","child","isDeclaredIngress","commandBody","body","value","localValue","unwrap"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"declaration-ingress.js","sources":["../src/declaration-ingress.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 { propertyName } from './ast';\nimport type { FunctionNode } from './model-bindings';\nimport {\n definitionOf,\n enclosingFunction,\n isApi,\n isFeatureSection,\n isFunction,\n isSlot,\n localValue,\n unwrap,\n variableOf,\n} from './model-bindings';\nimport type { SourceCode } from './rule';\n\n/**\n * The callbacks a declared node opens its work in and owns the release of: the disposer they return is run by the\n * node, in the drain of the generation that opened it. The argument index is part of the contract — `run`, `load`,\n * `filter` and `key` sit in the same calls and are not ingress.\n *\n * D458: the subscription of an event is the third argument, because `run` moved in front of it.\n */\nconst positionalIngress = new Map([['event', 2]]);\n\n/**\n * D470: the builder of a model scope — and of a Resource view, the same child machine — hands its child context in the\n * second parameter. It is no ingress: what it returns is a fields record, never a disposer the node would run, so\n * work it opens by hand is released only through `child.cleanup`. Its child context declares ingress like any other.\n */\nconst modelBuilders = new Map([\n ['resource.view', 1],\n ['scope.each', 2],\n ['scope.switch', 1],\n ['scope.while', 1],\n]);\n\n/**\n * The callbacks written as a record member. `attach`'s `close` is a release, not an opening; D349 puts the connection\n * of a live Resource under `connect` in the one options record, so that is where the ingress of a subscription is.\n */\nconst recordIngress = new Map([\n ['attach', { argument: 1, property: 'open' }],\n ['resource.live', { argument: 0, property: 'connect' }],\n]);\n\ntype NamedMethod = { readonly fn: FunctionNode; readonly method: string };\ntype ParameterOf = { readonly fn: FunctionNode; readonly name: TSESTree.BindingName };\n\nfunction isModelContextParameter(source: SourceCode, parameter: TSESTree.Parameter): boolean {\n if (parameter.type !== AST_NODE_TYPES.Identifier && parameter.type !== AST_NODE_TYPES.ObjectPattern) return false;\n\n const annotation = parameter.typeAnnotation?.typeAnnotation;\n\n if (annotation?.type !== AST_NODE_TYPES.TSTypeReference) return false;\n\n const { typeName } = annotation;\n\n return typeName.type === AST_NODE_TYPES.Identifier && isApi(source, typeName, '@opetope/core', 'ModelContext', true);\n}\n\n/**\n * A function says it takes a model's context in the parameter annotated with the name `ModelContext` carries where it\n * is exported, in whichever position: the factory of a model takes it first, a builder written in a file of its own\n * second.\n */\nfunction annotatedContext(source: SourceCode, fn: FunctionNode): TSESTree.Parameter | undefined {\n return fn.params.find(parameter => isModelContextParameter(source, parameter));\n}\n\nfunction declaresModelContext(source: SourceCode, fn: FunctionNode): boolean {\n return annotatedContext(source, fn) !== undefined;\n}\n\n/** The function this name is a parameter of, and the pattern node that bound it there. */\nfunction parameterOf(source: SourceCode, node: TSESTree.Identifier): ParameterOf | undefined {\n const definition = definitionOf(source, node);\n\n if (definition?.type !== DefinitionType.Parameter || !isFunction(definition.node)) return undefined;\n\n return { fn: definition.node, name: definition.name };\n}\n\n/** The name a function is bound to where it is written: `const open = (…) => …` or `function open(…) {}`. */\nfunction boundName(fn: FunctionNode): TSESTree.Identifier | undefined {\n if (fn.type === AST_NODE_TYPES.FunctionDeclaration) return fn.id ?? undefined;\n\n const { parent } = fn;\n\n return parent.type === AST_NODE_TYPES.VariableDeclarator &&\n parent.init === fn &&\n parent.id.type === AST_NODE_TYPES.Identifier\n ? parent.id\n : undefined;\n}\n\n/** The builders being asked about right now: a builder that names itself inside its own body is not its own proof. */\nconst askedBuilders = new Set<FunctionNode>();\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\ntype BuilderSite = { readonly method: string; readonly wrapped: boolean };\n\n/**\n * The model builder method `argument` stands at the builder's position of, on a context that is a model's, and\n * whether a wrapper stands between.\n */\nfunction builderSite(source: SourceCode, argument: TSESTree.Node): BuilderSite | undefined {\n const written = outermost(argument);\n const call = written.parent;\n\n if (call?.type !== AST_NODE_TYPES.CallExpression) return undefined;\n\n const position = call.arguments.indexOf(written as TSESTree.CallExpressionArgument);\n\n if (position === -1) return undefined;\n\n // eslint-disable-next-line no-use-before-define -- a builder is found through the call whose context it serves\n const named = methodPath(source, call.callee);\n\n // eslint-disable-next-line no-use-before-define -- a wrapper call is followed to the call that receives it\n if (named === undefined) return wrapperSite(source, call, position);\n\n // eslint-disable-next-line no-use-before-define -- that context is a model's, which may itself be a builder's child\n return modelBuilders.get(named.method) === position && isModelContextFunction(source, named.fn)\n ? { method: named.method, wrapped: false }\n : undefined;\n}\n\n/** `scope.each(rows, key, track(open))` hands the scope the function its wrapper wraps: the wrapper's first argument. */\nfunction wrapperSite(source: SourceCode, call: TSESTree.CallExpression, position: number): BuilderSite | undefined {\n const site = position === 0 ? builderSite(source, call) : undefined;\n\n return site === undefined ? undefined : { method: site.method, wrapped: true };\n}\n\n/**\n * The method `fn` is the builder of where `argument` — the function itself or a name bound to it — is handed over.\n * Through a wrapper only a function that takes the child's context, its second parameter, is the builder: the\n * `listener` of `makeOpen(listener)` is not.\n */\nfunction builderCall(source: SourceCode, fn: FunctionNode, argument: TSESTree.Node): string | undefined {\n const site = builderSite(source, argument);\n\n return site !== undefined && (!site.wrapped || fn.params.length >= 2) ? site.method : undefined;\n}\n\n/**\n * D470: the method this function is the builder of — `scope.switch`, `scope.while`, `scope.each` or `resource.view` —\n * where it stands at the builder's position of that call on a model's context, inline or through a name bound to it\n * in the same file. Its second parameter is then the child's context. A function that is only annotated like one is\n * no builder: a helper `(source, ctx: ModelContext) => …` hands its release to its caller.\n */\nfunction builderMethod(source: SourceCode, fn: FunctionNode): string | undefined {\n const inline = builderCall(source, fn, fn);\n\n if (inline !== undefined || askedBuilders.has(fn)) return inline;\n\n const name = boundName(fn);\n const variable = name === undefined ? null : variableOf(source, name);\n\n if (variable === null) return undefined;\n\n askedBuilders.add(fn);\n try {\n for (const reference of variable.references) {\n const method = builderCall(source, fn, reference.identifier);\n\n if (method !== undefined) return method;\n }\n\n return undefined;\n } finally {\n askedBuilders.delete(fn);\n }\n}\n\nfunction isModelBuilder(source: SourceCode, fn: FunctionNode): boolean {\n return builderMethod(source, fn) !== undefined;\n}\n\n/**\n * The parameter a function receives its declaring context in: the second of a model builder, else the one annotated\n * `ModelContext`, else the first.\n */\nfunction contextParameter(source: SourceCode, fn: FunctionNode): TSESTree.Parameter | undefined {\n if (isModelBuilder(source, fn)) return fn.params[1];\n\n return annotatedContext(source, fn) ?? fn.params[0];\n}\n\n/** `own` itself: the plain name a context parameter was given, whichever function that parameter belongs to. */\nfunction contextName(source: SourceCode, node: TSESTree.Identifier): FunctionNode | undefined {\n const parameter = parameterOf(source, node);\n\n return parameter !== undefined && parameter.name === contextParameter(source, parameter.fn)\n ? parameter.fn\n : undefined;\n}\n\n/** `({ resource }) => resource.live(…)`: the method under the key the destructuring took it from, alias included. */\nfunction destructuredMethod(source: SourceCode, node: TSESTree.Identifier): NamedMethod | undefined {\n const parameter = parameterOf(source, node);\n const property = parameter?.name.parent;\n\n if (parameter === undefined || property?.type !== AST_NODE_TYPES.Property) return undefined;\n\n const method = property.parent === contextParameter(source, parameter.fn) ? propertyName(property) : undefined;\n\n return method === undefined ? undefined : { fn: parameter.fn, method };\n}\n\n/** The dotted steps of a member chain and the name it starts from: `context.scope.while` is `context` and `scope.while`. */\nfunction memberSteps(callee: TSESTree.Node): { root: TSESTree.Node; steps: readonly string[] } | undefined {\n const steps: string[] = [];\n let current: TSESTree.Node = callee;\n\n while (current.type === AST_NODE_TYPES.MemberExpression) {\n if (current.computed || current.property.type !== AST_NODE_TYPES.Identifier) return undefined;\n\n steps.unshift(current.property.name);\n current = current.object;\n }\n\n return { root: current, steps };\n}\n\n/**\n * The method this callee names on the context parameter of some function, and that function. Whether the parameter\n * really is a declaring context is a separate question: answering it here would make the two questions circular.\n */\nfunction methodPath(source: SourceCode, callee: TSESTree.Node): NamedMethod | undefined {\n const chain = memberSteps(callee);\n\n if (chain?.root.type !== AST_NODE_TYPES.Identifier) return undefined;\n\n const named = chain.steps.length === 0 ? undefined : contextName(source, chain.root);\n\n if (named !== undefined) return { fn: named, method: chain.steps.join('.') };\n\n const destructured = destructuredMethod(source, chain.root);\n\n return destructured === undefined\n ? undefined\n : { fn: destructured.fn, method: [destructured.method, ...chain.steps].join('.') };\n}\n\n/** One step outward: the context whose `model(…)` call declares this factory, where that is how it was written. */\nfunction declaringContext(source: SourceCode, fn: FunctionNode): FunctionNode | undefined {\n const call = fn.parent;\n\n // `model(Declaration, factory)` and `model(Declaration, deps, factory)` both hand the callback a ModelContext.\n if (call.type !== AST_NODE_TYPES.CallExpression || (call.arguments[1] !== fn && call.arguments[2] !== fn))\n return undefined;\n\n const declaring = methodPath(source, call.callee);\n\n return declaring?.method === 'model' ? declaring.fn : undefined;\n}\n\n/**\n * The two functions that hand an author a declaring context: the `own` section written right where `defineFeature`\n * takes it, and the factory of a model — which is either annotated as one or written where a feature declares it,\n * as the factory argument of `model(Declaration, factory)` or `model(Declaration, deps, factory)`. That form is\n * proved by walking outward one\n * `model(…)` at a time, and the set of functions already visited ends a chain that would come back to its start.\n */\nfunction isContextFunction(source: SourceCode, fn: FunctionNode): boolean {\n const seen = new Set<FunctionNode>();\n let current: FunctionNode | undefined = fn;\n\n while (current !== undefined && !seen.has(current)) {\n seen.add(current);\n\n if (isFeatureSection(source, current, 'own', true) || declaresModelContext(source, current)) return true;\n\n if (isModelBuilder(source, current)) return true;\n\n current = declaringContext(source, current);\n }\n\n return false;\n}\n\n/** The factory position of a model call: `(Declaration, factory)` or `(Declaration, deps, factory)`. */\nfunction isFactoryArgument(call: TSESTree.CallExpression, fn: FunctionNode): boolean {\n return call.arguments.length >= 2 && call.arguments.at(-1) === fn && call.arguments.length <= 3;\n}\n\n/**\n * D514: the builder a slot contribution declares its models in — `slot(target, ({ model }) => …)` in a `provides`\n * section — hands `model` exactly as `own` does, so the factory of that `model(…)` is a model's context too.\n */\nfunction isSlotBuilder(source: SourceCode, fn: FunctionNode): boolean {\n const call = fn.parent;\n\n return call.type === AST_NODE_TYPES.CallExpression && call.arguments[1] === fn && isSlot(source, call.callee);\n}\n\n/** D514: the factory `openModel(Declaration, factory)` of Runtime testing hands a model's context. */\nfunction isOpenModelFactory(source: SourceCode, fn: FunctionNode): boolean {\n const call = fn.parent;\n\n return (\n call.type === AST_NODE_TYPES.CallExpression &&\n isFactoryArgument(call, fn) &&\n isApi(source, call.callee, '@opetope/runtime/testing', 'openModel', true)\n );\n}\n\n/**\n * D330: the context of a model and nothing else. The `own` section of a feature is a declaring context too, but its\n * `command` takes the body second and hands it no writer (D139, D385), so a rule about the writer of a command asks\n * this. D514: the factory of `openModel`, and of a `model(…)` a slot contribution declares, are models' contexts.\n */\nfunction isModelContextFunction(source: SourceCode, fn: FunctionNode): boolean {\n if (declaresModelContext(source, fn) || isModelBuilder(source, fn) || isOpenModelFactory(source, fn)) return true;\n\n const declaring = declaringContext(source, fn);\n\n return declaring !== undefined && (isContextFunction(source, declaring) || isSlotBuilder(source, declaring));\n}\n\n/**\n * D514: the shape of a model factory without the proof of it — the function at the factory position of a call named\n * `model` or `openModel` whose origin this file does not prove. A rule may name a retired word there, never rewrite it.\n */\nfunction isModelFactoryShape(fn: FunctionNode): boolean {\n const call = fn.parent;\n\n if (call.type !== AST_NODE_TYPES.CallExpression || !isFactoryArgument(call, fn)) return false;\n\n const callee = call.callee.type === AST_NODE_TYPES.MemberExpression ? call.callee.property : call.callee;\n\n return callee.type === AST_NODE_TYPES.Identifier && (callee.name === 'model' || callee.name === 'openModel');\n}\n\n/** D514: where a method of a model context takes the callback that receives an execution context. */\nconst EXECUTION_CALLBACKS = new Map([\n ['command', 0],\n ['event', 2],\n]);\n\n/**\n * D514: the callbacks of a model context whose context is their first parameter and carried `acquire(view)` until\n * `hold` replaced it — a command body and the subscription of an event. An effect run and an event run take their\n * context second, behind the value, and are not followed: their `acquire` is the compiler's to refuse.\n */\nfunction isExecutionCallback(source: SourceCode, fn: FunctionNode): boolean {\n const call = fn.parent;\n\n if (call.type !== AST_NODE_TYPES.CallExpression) return false;\n\n const named = methodPath(source, call.callee);\n\n if (named === undefined) return false;\n\n const position = EXECUTION_CALLBACKS.get(named.method);\n\n return position !== undefined && call.arguments[position] === fn && isModelContextFunction(source, named.fn);\n}\n\nfunction admitsIngress(method: string, position: number, property: string | undefined): boolean {\n if (positionalIngress.get(method) === position) return true;\n\n const record = recordIngress.get(method);\n\n return record?.argument === position && record.property === property;\n}\n\n/** The shape decides first and the import second: a call that cannot be ingress never pays for the resolution. */\nfunction isIngressArgument(\n source: SourceCode,\n call: TSESTree.CallExpression,\n position: number,\n property: string | undefined,\n): boolean {\n const named = methodPath(source, call.callee);\n\n if (named === undefined || !admitsIngress(named.method, position, property)) return false;\n\n return isContextFunction(source, named.fn);\n}\n\n/** The record member the walk came through since the last call boundary: the `{ open }` of an `attach`. */\nfunction memberProperty(parent: TSESTree.Node, child: TSESTree.Node, current: string | undefined): string | undefined {\n if (parent.type !== AST_NODE_TYPES.ObjectExpression || child.type !== AST_NODE_TYPES.Property) return current;\n\n return propertyName(child);\n}\n\n/**\n * Whether this node stands lexically inside a callback whose opened work the declared node releases. The walk goes\n * all the way out, so a nested function body counts; only the resolved context and the position decide.\n */\nfunction isDeclaredIngress(source: SourceCode, node: TSESTree.Node): boolean {\n let child: TSESTree.Node = node;\n let property: string | undefined;\n\n for (const parent of source.getAncestors(node).reverse()) {\n if (parent.type === AST_NODE_TYPES.CallExpression) {\n const position = parent.arguments.indexOf(child as TSESTree.CallExpressionArgument);\n\n if (position !== -1 && isIngressArgument(source, parent, position, property)) return true;\n\n property = undefined;\n } else {\n property = memberProperty(parent, child, property);\n }\n\n child = parent;\n }\n\n return false;\n}\n\n/** `child.cleanup(release)` on the child context of this builder — its second parameter, `scope` for a view. */\nfunction isChildCleanup(\n source: SourceCode,\n call: TSESTree.Node,\n builder: FunctionNode,\n): call is TSESTree.CallExpression {\n if (call.type !== AST_NODE_TYPES.CallExpression) return false;\n\n const named = methodPath(source, call.callee);\n\n return named?.method === 'cleanup' && named.fn === builder;\n}\n\n/**\n * The name a subscription's release is bound to where it is written: `const stop = source.subscribe(l)`, the same\n * with `let`, or `stop = source.subscribe(l)` into a name declared before — the shape of a cleanup registered first.\n */\nfunction heldRelease(parent: TSESTree.Node, node: TSESTree.CallExpression): TSESTree.Node | undefined {\n if (parent.type === AST_NODE_TYPES.VariableDeclarator && parent.init === node) return parent.id;\n\n if (parent.type === AST_NODE_TYPES.AssignmentExpression && parent.operator === '=' && parent.right === node) {\n return parent.left;\n }\n\n return undefined;\n}\n\n/** Whether this reference stands in the function the child's `cleanup` receives: `cleanup(() => { stop(); … })`. */\nfunction inCleanupCallback(source: SourceCode, node: TSESTree.Node, builder: FunctionNode): boolean {\n return source.getAncestors(node).some(ancestor => {\n if (!isFunction(ancestor)) return false;\n\n const call = ancestor.parent;\n\n return isChildCleanup(source, call, builder) && call.arguments[0] === ancestor;\n });\n}\n\n/**\n * D470: a subscription whose release the builder's child context owns — handed to its `cleanup` where it is written,\n * or held by a name that `cleanup` receives or that the function handed to `cleanup` reads, whichever was registered\n * first. The `cleanup` of the parent or of an outer builder's child is not it: that owner outlives this child.\n */\nfunction isReleasedByCleanup(source: SourceCode, node: TSESTree.CallExpression, builder: FunctionNode): boolean {\n const { parent } = node;\n\n if (isChildCleanup(source, parent, builder) && parent.arguments[0] === node) return true;\n\n const held = heldRelease(parent, node);\n const variable = held?.type === AST_NODE_TYPES.Identifier ? variableOf(source, held) : null;\n\n return (\n variable?.references.some(reference => {\n const call = reference.identifier.parent;\n\n if (isChildCleanup(source, call, builder) && call.arguments[0] === reference.identifier) return true;\n\n return inCleanupCallback(source, reference.identifier, builder);\n }) === true\n );\n}\n\n/** Array methods that call their callback before they return, so the callback runs inside the caller's own run. */\nconst synchronousCallbacks = new Set(['every', 'filter', 'find', 'findIndex', 'flatMap', 'forEach', 'map', 'some']);\n\nfunction isSynchronousCallback(fn: FunctionNode): boolean {\n const call = fn.parent;\n\n if (call.type !== AST_NODE_TYPES.CallExpression || call.arguments[0] !== fn) return false;\n\n const { callee } = call;\n\n return (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.property.type === AST_NODE_TYPES.Identifier &&\n synchronousCallbacks.has(callee.property.name)\n );\n}\n\n/**\n * The builder whose own body a subscription is written in, and the method it builds for: the nearest function around\n * it, where that function is a model scope or view builder. The callback of `parts.forEach(…)` and its kin runs in\n * the builder's own run, so it is looked through; a subscription in any other nested callback belongs to the node\n * that runs that callback.\n */\nfunction enclosingBuilder(\n source: SourceCode,\n node: TSESTree.Node,\n): { readonly fn: FunctionNode; readonly method: string } | undefined {\n let fn = enclosingFunction(source, node);\n\n while (fn !== undefined && isSynchronousCallback(fn)) fn = enclosingFunction(source, fn);\n\n if (fn === undefined) return undefined;\n\n const method = builderMethod(source, fn);\n\n return method === undefined ? undefined : { fn, method };\n}\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\n/**\n * `context.command(run, options?)`: the body a model command is declared with, inline or bound to a local name.\n * D447: two rules read the writes of one command body — `capture-command-cleanup` where the declaration stands, and\n * `no-write-after-source-write` where a run invokes the name that holds it — so the resolution is one function here\n * rather than the same six lines twice.\n */\nfunction commandBody(source: SourceCode, call: TSESTree.CallExpression): FunctionNode | undefined {\n const [body] = call.arguments;\n\n if (body === undefined || body.type === AST_NODE_TYPES.SpreadElement) return undefined;\n\n const value = localValue(source, unwrap(body));\n\n return isFunction(value) ? value : undefined;\n}\n\n/**\n * D323: a rule that rewrites code has to resolve its package exactly (D309), and this pair is that resolution: the\n * method a callee names on a declaring context, and whether that parameter really is one.\n */\nexport {\n commandBody,\n contextName,\n enclosingBuilder,\n isContextFunction,\n isDeclaredIngress,\n isExecutionCallback,\n isModelContextFunction,\n isModelFactoryShape,\n isReleasedByCleanup,\n isSubscribeCall,\n methodPath,\n};\n"],"names":["positionalIngress","modelBuilders","recordIngress","isModelContextParameter","source","parameter","AST_NODE_TYPES","annotation","typeName","isApi","annotatedContext","fn","declaresModelContext","parameterOf","node","definition","definitionOf","DefinitionType","isFunction","boundName","parent","askedBuilders","outermost","current","unwrap","builderSite","argument","written","call","position","named","methodPath","wrapperSite","isModelContextFunction","site","builderCall","builderMethod","inline","name","variable","variableOf","reference","method","isModelBuilder","contextParameter","contextName","destructuredMethod","property","propertyName","memberSteps","callee","steps","chain","destructured","declaringContext","declaring","isContextFunction","seen","isFeatureSection","isFactoryArgument","isSlotBuilder","isSlot","isOpenModelFactory","isModelFactoryShape","EXECUTION_CALLBACKS","isExecutionCallback","admitsIngress","record","isIngressArgument","memberProperty","child","isDeclaredIngress","isChildCleanup","builder","heldRelease","inCleanupCallback","ancestor","isReleasedByCleanup","held","synchronousCallbacks","isSynchronousCallback","enclosingBuilder","enclosingFunction","isSubscribeCall","commandBody","body","value","localValue"],"mappings":"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"}
|
package/dist/declarations.d.ts
CHANGED
package/dist/declarations.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{AST_NODE_TYPES as r}from"@typescript-eslint/
|
|
1
|
+
import{AST_NODE_TYPES as r}from"@typescript-eslint/types";import{calleeName as o}from"./ast.js";const d=new Set(["defineApplication","defineCondition","defineFeature","defineHostContract","defineLinkCatalog","defineLinkHandlers","defineModel","definePipe","definePort","defineRegistry","defineScreen","defineSlot","defineSurface","defineSwitchSlot"]),a=new Set([...d,"defineLink"]);function u(e){const[n]=e.arguments;if(!(n===void 0||n.type===r.SpreadElement))return n}function f(e,n){const i=o(e);if(i===void 0||!n.has(i))return;const t=u(e);return t===void 0?void 0:{id:t,name:i}}function c(e){return f(e,d)}function l(e){return f(e,a)}export{c as declarationOf,l as namedDeclarationOf};
|
|
2
2
|
//# sourceMappingURL=declarations.js.map
|
package/dist/declarations.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"declarations.js","sources":["../src/declarations.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"declarations.js","sources":["../src/declarations.ts"],"sourcesContent":["import { AST_NODE_TYPES } from '@typescript-eslint/types';\nimport type { TSESTree } from '@typescript-eslint/types';\n\nimport { calleeName } from './ast';\n\n/**\n * Every declaration of the public vocabulary whose id is a Core declaration id, taken from the three safe entries\n * and from the optional Navigation package, whose screen, surface, link catalog and handler registry pass their id through\n * `declarationId` (D310, D311, D313). D280 gives them one form: the id is the first argument, whatever else the\n * declaration carries. The kernel's own `defineModule`, `defineCallTarget` and `defineCallLane` are absent because\n * an author never writes them.\n */\nconst DECLARATIONS = new Set([\n 'defineApplication',\n 'defineCondition',\n 'defineFeature',\n 'defineHostContract',\n 'defineLinkCatalog',\n 'defineLinkHandlers',\n 'defineModel',\n 'definePipe',\n 'definePort',\n 'defineRegistry',\n 'defineScreen',\n 'defineSlot',\n 'defineSurface',\n 'defineSwitchSlot',\n]);\n\n/**\n * The same declarations plus the one with a grammar of its own: a link id is a canonical lower-case path segment,\n * not a Core declaration id, so `id-naming` must not measure it — and a reserved prefix would refuse it outright.\n * Naming itself first is nonetheless its law too, so a computed link id is as unfindable as any other (D312, D313).\n */\nconst NAMED_DECLARATIONS = new Set([...DECLARATIONS, 'defineLink']);\n\ntype Declaration = {\n readonly id: TSESTree.Node;\n readonly name: string;\n};\n\nfunction idOfArgument(node: TSESTree.CallExpression): TSESTree.Node | undefined {\n const [first] = node.arguments;\n\n if (first === undefined || first.type === AST_NODE_TYPES.SpreadElement) return undefined;\n\n return first;\n}\n\nfunction declarationIn(node: TSESTree.CallExpression, names: ReadonlySet<string>): Declaration | undefined {\n const name = calleeName(node);\n\n if (name === undefined || !names.has(name)) return undefined;\n\n const id = idOfArgument(node);\n\n return id === undefined ? undefined : { id, name };\n}\n\n/** The name and the id expression of a call whose id follows the Core grammar, or `undefined` for anything else. */\nfunction declarationOf(node: TSESTree.CallExpression): Declaration | undefined {\n return declarationIn(node, DECLARATIONS);\n}\n\n/** The same, for every declaration that names itself first, whatever grammar its own id follows. */\nfunction namedDeclarationOf(node: TSESTree.CallExpression): Declaration | undefined {\n return declarationIn(node, NAMED_DECLARATIONS);\n}\n\nexport { declarationOf, namedDeclarationOf };\n"],"names":["DECLARATIONS","NAMED_DECLARATIONS","idOfArgument","node","first","AST_NODE_TYPES","declarationIn","names","name","calleeName","id","declarationOf","namedDeclarationOf"],"mappings":"gGAYA,MAAMA,EAAe,IAAI,IAAI,CAC3B,oBACA,kBACA,gBACA,qBACA,oBACA,qBACA,cACA,aACA,aACA,iBACA,eACA,aACA,gBACA,kBACD,CAAA,EAOKC,EAAqB,IAAI,IAAI,CAAC,GAAGD,EAAc,YAAY,CAAC,EAOlE,SAASE,EAAaC,EAA6B,CACjD,KAAM,CAACC,CAAK,EAAID,EAAK,UAErB,GAAI,EAAAC,IAAU,QAAaA,EAAM,OAASC,EAAe,eAEzD,OAAOD,CACT,CAEA,SAASE,EAAcH,EAA+BI,EAA0B,CAC9E,MAAMC,EAAOC,EAAWN,CAAI,EAE5B,GAAIK,IAAS,QAAa,CAACD,EAAM,IAAIC,CAAI,EAAG,OAE5C,MAAME,EAAKR,EAAaC,CAAI,EAE5B,OAAOO,IAAO,OAAY,OAAY,CAAE,GAAAA,EAAI,KAAAF,CAAI,CAClD,CAGA,SAASG,EAAcR,EAA6B,CAClD,OAAOG,EAAcH,EAAMH,CAAY,CACzC,CAGA,SAASY,EAAmBT,EAA6B,CACvD,OAAOG,EAAcH,EAAMF,CAAkB,CAC/C"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/types';
|
|
2
2
|
import type { FunctionNode } from './model-bindings.js';
|
|
3
|
+
import type { SourceCode } from './rule.js';
|
|
3
4
|
/**
|
|
4
5
|
* One `effect(source, run, options?)` declared on a declaring context of this library. The source is the expression
|
|
5
6
|
* as written, past an `as`; a rule that needs a name of its own asks for one. `inline` says the run is the function
|
|
@@ -16,5 +17,5 @@ type DeclaredEffect = {
|
|
|
16
17
|
* context, and whether that parameter really is one. The shape decides first, so a call that cannot be an effect
|
|
17
18
|
* never pays for the resolution.
|
|
18
19
|
*/
|
|
19
|
-
declare function declaredEffect(source:
|
|
20
|
+
declare function declaredEffect(source: SourceCode, call: TSESTree.CallExpression): DeclaredEffect | undefined;
|
|
20
21
|
export { declaredEffect };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{AST_NODE_TYPES as f}from"@typescript-eslint/
|
|
1
|
+
import{AST_NODE_TYPES as f}from"@typescript-eslint/types";import{methodPath as m,isContextFunction as c}from"./declaration-ingress.js";import{localValue as a,isFunction as i,unwrap as u}from"./model-bindings.js";function p(t,r){const[n,e,o]=r.arguments;if(n===void 0||n.type===f.SpreadElement||e===void 0||e.type===f.SpreadElement)return;const d=a(t,e);if(i(d))return{from:u(n),inline:i(u(e)),options:o,run:d}}function l(t,r){const n=m(t,r.callee);if(n?.method!=="effect")return;const e=p(t,r);if(e!==void 0)return c(t,n.fn)?e:void 0}export{l as declaredEffect};
|
|
2
2
|
//# sourceMappingURL=effect-declarations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"effect-declarations.js","sources":["../src/effect-declarations.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"effect-declarations.js","sources":["../src/effect-declarations.ts"],"sourcesContent":["import { AST_NODE_TYPES } from '@typescript-eslint/types';\nimport type { TSESTree } from '@typescript-eslint/types';\n\nimport { isContextFunction, methodPath } from './declaration-ingress';\nimport type { FunctionNode } from './model-bindings';\nimport { isFunction, localValue, unwrap } from './model-bindings';\nimport type { SourceCode } from './rule';\n\n/**\n * One `effect(source, run, options?)` declared on a declaring context of this library. The source is the expression\n * as written, past an `as`; a rule that needs a name of its own asks for one. `inline` says the run is the function\n * literal the declaration takes, which is what a rule that rewrites inside it needs to know.\n */\ntype DeclaredEffect = {\n readonly from: TSESTree.Node;\n readonly inline: boolean;\n readonly options: TSESTree.CallExpressionArgument | undefined;\n readonly run: FunctionNode;\n};\n\n/** The source, the run and the modifiers of an `effect`, where the run resolves to a function of this module. */\nfunction declaredArguments(source: SourceCode, call: TSESTree.CallExpression): DeclaredEffect | undefined {\n const [from, run, options] = call.arguments;\n\n if (from === undefined || from.type === AST_NODE_TYPES.SpreadElement) return undefined;\n\n if (run === undefined || run.type === AST_NODE_TYPES.SpreadElement) return undefined;\n\n const body = localValue(source, run);\n\n if (!isFunction(body)) return undefined;\n\n return { from: unwrap(from), inline: isFunction(unwrap(run)), options, run: body };\n}\n\n/**\n * D309: a rule that speaks about an effect resolves its package exactly — the method a callee names on a declaring\n * context, and whether that parameter really is one. The shape decides first, so a call that cannot be an effect\n * never pays for the resolution.\n */\nfunction declaredEffect(source: SourceCode, call: TSESTree.CallExpression): DeclaredEffect | undefined {\n const named = methodPath(source, call.callee);\n\n if (named?.method !== 'effect') return undefined;\n\n const declared = declaredArguments(source, call);\n\n if (declared === undefined) return undefined;\n\n return isContextFunction(source, named.fn) ? declared : undefined;\n}\n\nexport { declaredEffect };\n"],"names":["declaredArguments","source","call","from","run","options","AST_NODE_TYPES","body","localValue","isFunction","unwrap","declaredEffect","named","methodPath","declared","isContextFunction"],"mappings":"oNAqBA,SAASA,EAAkBC,EAAoBC,EAA6B,CAC1E,KAAM,CAACC,EAAMC,EAAKC,CAAO,EAAIH,EAAK,UAIlC,GAFIC,IAAS,QAAaA,EAAK,OAASG,EAAe,eAEnDF,IAAQ,QAAaA,EAAI,OAASE,EAAe,cAAe,OAEpE,MAAMC,EAAOC,EAAWP,EAAQG,CAAG,EAEnC,GAAKK,EAAWF,CAAI,EAEpB,MAAO,CAAE,KAAMG,EAAOP,CAAI,EAAG,OAAQM,EAAWC,EAAON,CAAG,CAAC,EAAG,QAAAC,EAAS,IAAKE,CAAI,CAClF,CAOA,SAASI,EAAeV,EAAoBC,EAA6B,CACvE,MAAMU,EAAQC,EAAWZ,EAAQC,EAAK,MAAM,EAE5C,GAAIU,GAAO,SAAW,SAAU,OAEhC,MAAME,EAAWd,EAAkBC,EAAQC,CAAI,EAE/C,GAAIY,IAAa,OAEjB,OAAOC,EAAkBd,EAAQW,EAAM,EAAE,EAAIE,EAAW,MAC1D"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One row of an entry move: the names of `from` that another entry publishes now, the entry that publishes them and the
|
|
3
|
+
* decision that moved them. `names` is a closed list — only a name that left `from` moves, so a name `from` never
|
|
4
|
+
* published, or one it publishes now, stays where it is written and is the compiler's — or `'all'` for an entry that
|
|
5
|
+
* is gone. `rename` maps a moved name to the one it is published under at `to`; its rewrite changes the import and
|
|
6
|
+
* every local reference only when the binding can be resolved safely. An unsupported form is left to the compiler
|
|
7
|
+
* or a later manual pass; a row does not imply that every use of the old spelling receives a lint report.
|
|
8
|
+
*/
|
|
9
|
+
type EntryMoveRow = {
|
|
10
|
+
readonly decision: string;
|
|
11
|
+
/** Names of an entry gone whole that the new entry does not publish: they are withdrawn, not moved. */
|
|
12
|
+
readonly except?: ReadonlySet<string>;
|
|
13
|
+
readonly from: string;
|
|
14
|
+
readonly names: ReadonlySet<string> | 'all';
|
|
15
|
+
readonly reason: string;
|
|
16
|
+
readonly rename?: ReadonlyMap<string, string>;
|
|
17
|
+
readonly to: string;
|
|
18
|
+
};
|
|
19
|
+
declare const ENTRY_MOVES: readonly EntryMoveRow[];
|
|
20
|
+
export type { EntryMoveRow };
|
|
21
|
+
export { ENTRY_MOVES };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const o=new Set(["AbsentProviderPlanNode","ActivityOwner","ApplicationPlanNode","ApplicationPlanSnapshot","AttachmentNode","AttachmentState","CallActivity","ConditionGroupPlanNode","ConditionGroupRuntimeNode","ConditionGroupState","ConditionPlanNode","ConditionRuntimeNode","ConditionState","ContributionPlanNode","ContributionRuntimeNode","ContributionState","ContributionTargetPlanNode","ControlAuditEntry","ControlCommand","ControlOutcome","ControlRejection","Corpus","CorpusShape","DecodeLimits","DesiredAxis","DevtoolsDecodeError","DevtoolsExport","DevtoolsGraphStore","DevtoolsProtocolError","DevtoolsSession","DevtoolsSessionFailure","DevtoolsSessionOptions","DevtoolsStoreStatus","DevtoolsTimeline","DiagnosticAxes","DiagnosticCausalStep","DiagnosticCauseKind","DiagnosticCauseRef","DiagnosticClosedReason","DiagnosticConditionId","DiagnosticDesiredState","DiagnosticEdge","DiagnosticEdgeId","DiagnosticEdgeKind","DiagnosticFailure","DiagnosticFailureCode","DiagnosticGraphIndex","DiagnosticLabel","DiagnosticNode","DiagnosticNodeId","DiagnosticNodeKind","DiagnosticNodeState","DiagnosticOperation","DiagnosticOverride","DiagnosticPhase","DiagnosticPlanFingerprint","DiagnosticPlanNode","DiagnosticProvenance","DiagnosticRuntimeNode","DiagnosticSequence","DiagnosticSessionId","DiagnosticStateRevision","DiagnosticTimestamp","DiagnosticTopologyRevision","DiagnosticValue","DiagnosticWaitReason","ExportLimits","ExtensionPointsProjection","ExtensionRow","FeatureActivity","FeatureInstanceNode","FeatureInstanceState","FeaturePlanNode","FrameOutcome","FrameRejection","HardEdgeKind","HealthAxis","HostContractDemand","HostContractPlanNode","HostContractRuntimeNode","HostContractState","InspectorBlocker","InspectorBreadcrumb","InspectorOwned","InspectorProjection","InspectorWhy","LifecycleAxis","ModelStateReader","ModelStateRequest","ModelStateResult","NodeDisplayState","PortPlanNode","PortRuntimeNode","PortState","ReadLimits","ReadResult","ResourceLoadActivity","ResourceNodeActivity","RuntimeActivitySnapshot","RuntimeControlSession","RuntimeGraphFrame","RuntimeGraphSnapshot","RuntimeInspectionSession","RuntimeStateSnapshot","SearchField","SearchHit","StructuralEdgeKind","TimelineChange","TimelineChangeDetail","TimelineEntry","TimelineFrameEntry","TimelineGapEntry","TimelineLimits","TreeFeatureRow","TreeGroupRow","WeakEdgeKind","WeakEdgeState","canonicalJson","connectDevtoolsSession","countEdges","countNodes","decodeFrame","decodeSnapshot","defaultDecodeLimits","defaultTimelineLimits","diagnosticConditionId","diagnosticEdgeId","diagnosticNodeId","diagnosticPlanFingerprint","diagnosticSequence","diagnosticSessionId","diagnosticStateRevision","diagnosticTopologyRevision","digestOf","exportSnapshot","failureOf","foldFrames","frameSchemaRevision","generateCorpus","generationOf","graphSchemaRevision","isDependencyEdge","isHardEdge","isWeakEdge","largeCorpusShape","nodeAxes","nodeDisplayState","nodePosition","parseProtocolText","progressOf","projectExtensionPoints","projectInspector","sameProtocolValue","searchGraph","smallCorpusShape"]),e="The Devtools root is what an application attaches the panel with \u2014 `installDevtools`, its mode and its theme.",t=new Set(["skipChange","EventDelivery","LiveDelivery","ConsumerResource","OwnedPaginatedResource","OwnedResource","PaginatedResource","PaginationOutcome","PaginationState","Resource","ResourceCommit","ResourceCommitOutcome","ResourceData","ResourceEpoch","ResourceFailure","ResourceIdleReason","ResourceKey","ResourceOperationOutcome","ResourcePagination","ResourceSkip","ResourceState"]),n=[{decision:"D517",from:"@opetope/core",names:new Set(["State"]),reason:"A writable test readable is published by Runtime/testing; Core keeps its state cell type internal.",rename:new Map([["State","TestReadable"]]),to:"@opetope/runtime/testing"},{decision:"D502",except:new Set(["CommandInputArgs"]),from:"@opetope/core/testing",names:"all",reason:"Runtime/testing is the sole home of non-React test words.",rename:new Map([["command","testCommand"]]),to:"@opetope/runtime/testing"},{decision:"D502",from:"@opetope/react/testing",names:new Set(["CommandTimeoutError","EventuallyOptions","ModelInstance","OpenModelOptions","RunCommandOptions","SettleTarget","TestPagination","TestPaginationOptions","TestPaginationRequest","TestResource","TestResourceOptions","WaitOptions","WaitTimeoutError","command","eventually","openModel","runCommand","settled","testPagination","testReadable","testResource","testResourceEpoch","waitFor","yieldTurn"]),reason:"React/testing publishes only renderer and scenario words; Runtime/testing publishes shared test words.",rename:new Map([["command","testCommand"]]),to:"@opetope/runtime/testing"},{decision:"D502",from:"@opetope/runtime/testing",names:new Set(["command"]),reason:"The sole command fixture is named testCommand.",rename:new Map([["command","testCommand"]]),to:"@opetope/runtime/testing"},{decision:"D502",from:"@opetope/navigation/testing",names:new Set(["fakeLinkSource","fakeLinkCodec","FakeLinkSource","FakeLinkCodecOptions"]),reason:"Testing fixtures use the test prefix for values and their named types.",rename:new Map([["fakeLinkSource","testLinkSource"],["fakeLinkCodec","testLinkCodec"],["FakeLinkSource","TestLinkSource"],["FakeLinkCodecOptions","TestLinkCodecOptions"]]),to:"@opetope/navigation/testing"},{decision:"D511",from:"@opetope/navigation",names:new Set(["OpenScreenResult","ReplaceScreenResult","DismissScreenResult"]),reason:"Navigation commands answer discriminated outcome records.",rename:new Map([["OpenScreenResult","OpenScreenOutcome"],["ReplaceScreenResult","ReplaceScreenOutcome"],["DismissScreenResult","DismissScreenOutcome"]]),to:"@opetope/navigation"},{decision:"D511",from:"@opetope/navigation/links",names:new Set(["LinkResult"]),reason:"A link handler answers a discriminated outcome record.",rename:new Map([["LinkResult","LinkOutcome"]]),to:"@opetope/navigation/links"},{decision:"D501",from:"@opetope/runtime",names:t,reason:"Feature own declares composition; ModelContext.resource and its Resource types are published by Core.",to:"@opetope/core"},{decision:"D495",from:"@opetope/devtools",names:o,reason:"`@opetope/devtools/protocol` holds the protocol, the store and the projections a headless reader takes; the root attaches the panel.",to:"@opetope/devtools/protocol"},{decision:"D495",from:"@opetope/devtools/integration",names:"all",reason:`\`@opetope/devtools/integration\` is gone. ${e}`,to:"@opetope/devtools"},{decision:"D495",from:"@opetope/devtools/react",names:new Set(["DevtoolsMode","DevtoolsTheme","defaultTheme"]),reason:`${e} \`/react\` keeps the components of the panel for a host that composes it itself.`,to:"@opetope/devtools"}];export{n as ENTRY_MOVES};
|
|
2
|
+
//# sourceMappingURL=entry-move-rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-move-rows.js","sources":["../src/entry-move-rows.ts"],"sourcesContent":["/**\n * One row of an entry move: the names of `from` that another entry publishes now, the entry that publishes them and the\n * decision that moved them. `names` is a closed list — only a name that left `from` moves, so a name `from` never\n * published, or one it publishes now, stays where it is written and is the compiler's — or `'all'` for an entry that\n * is gone. `rename` maps a moved name to the one it is published under at `to`; its rewrite changes the import and\n * every local reference only when the binding can be resolved safely. An unsupported form is left to the compiler\n * or a later manual pass; a row does not imply that every use of the old spelling receives a lint report.\n */\ntype EntryMoveRow = {\n readonly decision: string;\n /** Names of an entry gone whole that the new entry does not publish: they are withdrawn, not moved. */\n readonly except?: ReadonlySet<string>;\n readonly from: string;\n readonly names: ReadonlySet<string> | 'all';\n readonly reason: string;\n readonly rename?: ReadonlyMap<string, string>;\n readonly to: string;\n};\n\n/** D495: the protocol, the store and the projections, which the Devtools root published before it attached the panel. */\nconst DEVTOOLS_PROTOCOL = new Set([\n 'AbsentProviderPlanNode',\n 'ActivityOwner',\n 'ApplicationPlanNode',\n 'ApplicationPlanSnapshot',\n 'AttachmentNode',\n 'AttachmentState',\n 'CallActivity',\n 'ConditionGroupPlanNode',\n 'ConditionGroupRuntimeNode',\n 'ConditionGroupState',\n 'ConditionPlanNode',\n 'ConditionRuntimeNode',\n 'ConditionState',\n 'ContributionPlanNode',\n 'ContributionRuntimeNode',\n 'ContributionState',\n 'ContributionTargetPlanNode',\n 'ControlAuditEntry',\n 'ControlCommand',\n 'ControlOutcome',\n 'ControlRejection',\n 'Corpus',\n 'CorpusShape',\n 'DecodeLimits',\n 'DesiredAxis',\n 'DevtoolsDecodeError',\n 'DevtoolsExport',\n 'DevtoolsGraphStore',\n 'DevtoolsProtocolError',\n 'DevtoolsSession',\n 'DevtoolsSessionFailure',\n 'DevtoolsSessionOptions',\n 'DevtoolsStoreStatus',\n 'DevtoolsTimeline',\n 'DiagnosticAxes',\n 'DiagnosticCausalStep',\n 'DiagnosticCauseKind',\n 'DiagnosticCauseRef',\n 'DiagnosticClosedReason',\n 'DiagnosticConditionId',\n 'DiagnosticDesiredState',\n 'DiagnosticEdge',\n 'DiagnosticEdgeId',\n 'DiagnosticEdgeKind',\n 'DiagnosticFailure',\n 'DiagnosticFailureCode',\n 'DiagnosticGraphIndex',\n 'DiagnosticLabel',\n 'DiagnosticNode',\n 'DiagnosticNodeId',\n 'DiagnosticNodeKind',\n 'DiagnosticNodeState',\n 'DiagnosticOperation',\n 'DiagnosticOverride',\n 'DiagnosticPhase',\n 'DiagnosticPlanFingerprint',\n 'DiagnosticPlanNode',\n 'DiagnosticProvenance',\n 'DiagnosticRuntimeNode',\n 'DiagnosticSequence',\n 'DiagnosticSessionId',\n 'DiagnosticStateRevision',\n 'DiagnosticTimestamp',\n 'DiagnosticTopologyRevision',\n 'DiagnosticValue',\n 'DiagnosticWaitReason',\n 'ExportLimits',\n 'ExtensionPointsProjection',\n 'ExtensionRow',\n 'FeatureActivity',\n 'FeatureInstanceNode',\n 'FeatureInstanceState',\n 'FeaturePlanNode',\n 'FrameOutcome',\n 'FrameRejection',\n 'HardEdgeKind',\n 'HealthAxis',\n 'HostContractDemand',\n 'HostContractPlanNode',\n 'HostContractRuntimeNode',\n 'HostContractState',\n 'InspectorBlocker',\n 'InspectorBreadcrumb',\n 'InspectorOwned',\n 'InspectorProjection',\n 'InspectorWhy',\n 'LifecycleAxis',\n 'ModelStateReader',\n 'ModelStateRequest',\n 'ModelStateResult',\n 'NodeDisplayState',\n 'PortPlanNode',\n 'PortRuntimeNode',\n 'PortState',\n 'ReadLimits',\n 'ReadResult',\n 'ResourceLoadActivity',\n 'ResourceNodeActivity',\n 'RuntimeActivitySnapshot',\n 'RuntimeControlSession',\n 'RuntimeGraphFrame',\n 'RuntimeGraphSnapshot',\n 'RuntimeInspectionSession',\n 'RuntimeStateSnapshot',\n 'SearchField',\n 'SearchHit',\n 'StructuralEdgeKind',\n 'TimelineChange',\n 'TimelineChangeDetail',\n 'TimelineEntry',\n 'TimelineFrameEntry',\n 'TimelineGapEntry',\n 'TimelineLimits',\n 'TreeFeatureRow',\n 'TreeGroupRow',\n 'WeakEdgeKind',\n 'WeakEdgeState',\n 'canonicalJson',\n 'connectDevtoolsSession',\n 'countEdges',\n 'countNodes',\n 'decodeFrame',\n 'decodeSnapshot',\n 'defaultDecodeLimits',\n 'defaultTimelineLimits',\n 'diagnosticConditionId',\n 'diagnosticEdgeId',\n 'diagnosticNodeId',\n 'diagnosticPlanFingerprint',\n 'diagnosticSequence',\n 'diagnosticSessionId',\n 'diagnosticStateRevision',\n 'diagnosticTopologyRevision',\n 'digestOf',\n 'exportSnapshot',\n 'failureOf',\n 'foldFrames',\n 'frameSchemaRevision',\n 'generateCorpus',\n 'generationOf',\n 'graphSchemaRevision',\n 'isDependencyEdge',\n 'isHardEdge',\n 'isWeakEdge',\n 'largeCorpusShape',\n 'nodeAxes',\n 'nodeDisplayState',\n 'nodePosition',\n 'parseProtocolText',\n 'progressOf',\n 'projectExtensionPoints',\n 'projectInspector',\n 'sameProtocolValue',\n 'searchGraph',\n 'smallCorpusShape',\n]);\n\nconst DEVTOOLS_ROOT_REASON =\n 'The Devtools root is what an application attaches the panel with — `installDevtools`, its mode and its theme.';\n\nconst RESOURCE_MIRROR = new Set([\n 'skipChange',\n 'EventDelivery',\n 'LiveDelivery',\n 'ConsumerResource',\n 'OwnedPaginatedResource',\n 'OwnedResource',\n 'PaginatedResource',\n 'PaginationOutcome',\n 'PaginationState',\n 'Resource',\n 'ResourceCommit',\n 'ResourceCommitOutcome',\n 'ResourceData',\n 'ResourceEpoch',\n 'ResourceFailure',\n 'ResourceIdleReason',\n 'ResourceKey',\n 'ResourceOperationOutcome',\n 'ResourcePagination',\n 'ResourceSkip',\n 'ResourceState',\n]);\n\nconst ENTRY_MOVES: readonly EntryMoveRow[] = [\n {\n decision: 'D517',\n from: '@opetope/core',\n names: new Set(['State']),\n reason: 'A writable test readable is published by Runtime/testing; Core keeps its state cell type internal.',\n rename: new Map([['State', 'TestReadable']]),\n to: '@opetope/runtime/testing',\n },\n {\n decision: 'D502',\n // D517: the input tuple of a command execution is internal; a test wrapper writes `RunCommandArgs`.\n except: new Set(['CommandInputArgs']),\n from: '@opetope/core/testing',\n names: 'all',\n reason: 'Runtime/testing is the sole home of non-React test words.',\n rename: new Map([['command', 'testCommand']]),\n to: '@opetope/runtime/testing',\n },\n {\n decision: 'D502',\n from: '@opetope/react/testing',\n names: new Set([\n 'CommandTimeoutError',\n 'EventuallyOptions',\n 'ModelInstance',\n 'OpenModelOptions',\n 'RunCommandOptions',\n 'SettleTarget',\n 'TestPagination',\n 'TestPaginationOptions',\n 'TestPaginationRequest',\n 'TestResource',\n 'TestResourceOptions',\n 'WaitOptions',\n 'WaitTimeoutError',\n 'command',\n 'eventually',\n 'openModel',\n 'runCommand',\n 'settled',\n 'testPagination',\n 'testReadable',\n 'testResource',\n 'testResourceEpoch',\n 'waitFor',\n 'yieldTurn',\n ]),\n reason: 'React/testing publishes only renderer and scenario words; Runtime/testing publishes shared test words.',\n rename: new Map([['command', 'testCommand']]),\n to: '@opetope/runtime/testing',\n },\n {\n decision: 'D502',\n from: '@opetope/runtime/testing',\n names: new Set(['command']),\n reason: 'The sole command fixture is named testCommand.',\n rename: new Map([['command', 'testCommand']]),\n to: '@opetope/runtime/testing',\n },\n {\n decision: 'D502',\n from: '@opetope/navigation/testing',\n names: new Set(['fakeLinkSource', 'fakeLinkCodec', 'FakeLinkSource', 'FakeLinkCodecOptions']),\n reason: 'Testing fixtures use the test prefix for values and their named types.',\n rename: new Map([\n ['fakeLinkSource', 'testLinkSource'],\n ['fakeLinkCodec', 'testLinkCodec'],\n ['FakeLinkSource', 'TestLinkSource'],\n ['FakeLinkCodecOptions', 'TestLinkCodecOptions'],\n ]),\n to: '@opetope/navigation/testing',\n },\n {\n decision: 'D511',\n from: '@opetope/navigation',\n names: new Set(['OpenScreenResult', 'ReplaceScreenResult', 'DismissScreenResult']),\n reason: 'Navigation commands answer discriminated outcome records.',\n rename: new Map([\n ['OpenScreenResult', 'OpenScreenOutcome'],\n ['ReplaceScreenResult', 'ReplaceScreenOutcome'],\n ['DismissScreenResult', 'DismissScreenOutcome'],\n ]),\n to: '@opetope/navigation',\n },\n {\n decision: 'D511',\n from: '@opetope/navigation/links',\n names: new Set(['LinkResult']),\n reason: 'A link handler answers a discriminated outcome record.',\n rename: new Map([['LinkResult', 'LinkOutcome']]),\n to: '@opetope/navigation/links',\n },\n {\n decision: 'D501',\n from: '@opetope/runtime',\n names: RESOURCE_MIRROR,\n reason: 'Feature own declares composition; ModelContext.resource and its Resource types are published by Core.',\n to: '@opetope/core',\n },\n {\n decision: 'D495',\n from: '@opetope/devtools',\n names: DEVTOOLS_PROTOCOL,\n reason:\n '`@opetope/devtools/protocol` holds the protocol, the store and the projections a headless reader takes; the root attaches the panel.',\n to: '@opetope/devtools/protocol',\n },\n {\n decision: 'D495',\n from: '@opetope/devtools/integration',\n names: 'all',\n reason: `\\`@opetope/devtools/integration\\` is gone. ${DEVTOOLS_ROOT_REASON}`,\n to: '@opetope/devtools',\n },\n {\n decision: 'D495',\n from: '@opetope/devtools/react',\n names: new Set(['DevtoolsMode', 'DevtoolsTheme', 'defaultTheme']),\n reason: `${DEVTOOLS_ROOT_REASON} \\`/react\\` keeps the components of the panel for a host that composes it itself.`,\n to: '@opetope/devtools',\n },\n];\n\nexport type { EntryMoveRow };\nexport { ENTRY_MOVES };\n"],"names":["DEVTOOLS_PROTOCOL","DEVTOOLS_ROOT_REASON","RESOURCE_MIRROR","ENTRY_MOVES"],"mappings":"AAoBA,MAAMA,EAAoB,IAAI,IAAI,CAChC,yBACA,gBACA,sBACA,0BACA,iBACA,kBACA,eACA,yBACA,4BACA,sBACA,oBACA,uBACA,iBACA,uBACA,0BACA,oBACA,6BACA,oBACA,iBACA,iBACA,mBACA,SACA,cACA,eACA,cACA,sBACA,iBACA,qBACA,wBACA,kBACA,yBACA,yBACA,sBACA,mBACA,iBACA,uBACA,sBACA,qBACA,yBACA,wBACA,yBACA,iBACA,mBACA,qBACA,oBACA,wBACA,uBACA,kBACA,iBACA,mBACA,qBACA,sBACA,sBACA,qBACA,kBACA,4BACA,qBACA,uBACA,wBACA,qBACA,sBACA,0BACA,sBACA,6BACA,kBACA,uBACA,eACA,4BACA,eACA,kBACA,sBACA,uBACA,kBACA,eACA,iBACA,eACA,aACA,qBACA,uBACA,0BACA,oBACA,mBACA,sBACA,iBACA,sBACA,eACA,gBACA,mBACA,oBACA,mBACA,mBACA,eACA,kBACA,YACA,aACA,aACA,uBACA,uBACA,0BACA,wBACA,oBACA,uBACA,2BACA,uBACA,cACA,YACA,qBACA,iBACA,uBACA,gBACA,qBACA,mBACA,iBACA,iBACA,eACA,eACA,gBACA,gBACA,yBACA,aACA,aACA,cACA,iBACA,sBACA,wBACA,wBACA,mBACA,mBACA,4BACA,qBACA,sBACA,0BACA,6BACA,WACA,iBACA,YACA,aACA,sBACA,iBACA,eACA,sBACA,mBACA,aACA,aACA,mBACA,WACA,mBACA,eACA,oBACA,aACA,yBACA,mBACA,oBACA,cACA,kBACD,CAAA,EAEKC,EACJ,qHAEIC,EAAkB,IAAI,IAAI,CAC9B,aACA,gBACA,eACA,mBACA,yBACA,gBACA,oBACA,oBACA,kBACA,WACA,iBACA,wBACA,eACA,gBACA,kBACA,qBACA,cACA,2BACA,qBACA,eACA,eACD,CAAA,EAEKC,EAAuC,CAC3C,CACE,SAAU,OACV,KAAM,gBACN,MAAO,IAAI,IAAI,CAAC,OAAO,CAAC,EACxB,OAAQ,qGACR,OAAQ,IAAI,IAAI,CAAC,CAAC,QAAS,cAAc,CAAC,CAAC,EAC3C,GAAI,0BACL,EACD,CACE,SAAU,OAEV,OAAQ,IAAI,IAAI,CAAC,kBAAkB,CAAC,EACpC,KAAM,wBACN,MAAO,MACP,OAAQ,4DACR,OAAQ,IAAI,IAAI,CAAC,CAAC,UAAW,aAAa,CAAC,CAAC,EAC5C,GAAI,0BACL,EACD,CACE,SAAU,OACV,KAAM,yBACN,MAAO,IAAI,IAAI,CACb,sBACA,oBACA,gBACA,mBACA,oBACA,eACA,iBACA,wBACA,wBACA,eACA,sBACA,cACA,mBACA,UACA,aACA,YACA,aACA,UACA,iBACA,eACA,eACA,oBACA,UACA,YACD,EACD,OAAQ,yGACR,OAAQ,IAAI,IAAI,CAAC,CAAC,UAAW,aAAa,CAAC,CAAC,EAC5C,GAAI,0BACL,EACD,CACE,SAAU,OACV,KAAM,2BACN,MAAO,IAAI,IAAI,CAAC,SAAS,CAAC,EAC1B,OAAQ,iDACR,OAAQ,IAAI,IAAI,CAAC,CAAC,UAAW,aAAa,CAAC,CAAC,EAC5C,GAAI,0BACL,EACD,CACE,SAAU,OACV,KAAM,8BACN,MAAO,IAAI,IAAI,CAAC,iBAAkB,gBAAiB,iBAAkB,sBAAsB,CAAC,EAC5F,OAAQ,yEACR,OAAQ,IAAI,IAAI,CACd,CAAC,iBAAkB,gBAAgB,EACnC,CAAC,gBAAiB,eAAe,EACjC,CAAC,iBAAkB,gBAAgB,EACnC,CAAC,uBAAwB,sBAAsB,EAChD,EACD,GAAI,6BACL,EACD,CACE,SAAU,OACV,KAAM,sBACN,MAAO,IAAI,IAAI,CAAC,mBAAoB,sBAAuB,qBAAqB,CAAC,EACjF,OAAQ,4DACR,OAAQ,IAAI,IAAI,CACd,CAAC,mBAAoB,mBAAmB,EACxC,CAAC,sBAAuB,sBAAsB,EAC9C,CAAC,sBAAuB,sBAAsB,EAC/C,EACD,GAAI,qBACL,EACD,CACE,SAAU,OACV,KAAM,4BACN,MAAO,IAAI,IAAI,CAAC,YAAY,CAAC,EAC7B,OAAQ,yDACR,OAAQ,IAAI,IAAI,CAAC,CAAC,aAAc,aAAa,CAAC,CAAC,EAC/C,GAAI,2BACL,EACD,CACE,SAAU,OACV,KAAM,mBACN,MAAOD,EACP,OAAQ,wGACR,GAAI,eACL,EACD,CACE,SAAU,OACV,KAAM,oBACN,MAAOF,EACP,OACE,uIACF,GAAI,4BACL,EACD,CACE,SAAU,OACV,KAAM,gCACN,MAAO,MACP,OAAQ,8CAA8CC,CAAoB,GAC1E,GAAI,mBACL,EACD,CACE,SAAU,OACV,KAAM,0BACN,MAAO,IAAI,IAAI,CAAC,eAAgB,gBAAiB,cAAc,CAAC,EAChE,OAAQ,GAAGA,CAAoB,oFAC/B,GAAI,mBACL"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/types';
|
|
2
|
+
import type { ReportFixFunction, SourceCode } from './rule.js';
|
|
3
|
+
/** One statement that names what another entry of the same package publishes now, and the rewrite that moves it. */
|
|
4
|
+
type EntryMove = {
|
|
5
|
+
readonly data: Readonly<Record<string, string>>;
|
|
6
|
+
readonly fix: ReportFixFunction | null;
|
|
7
|
+
readonly node: TSESTree.Node;
|
|
8
|
+
};
|
|
9
|
+
/** `import { … } from '<entry>'`, a namespace of it, or an import of it with no names. */
|
|
10
|
+
declare function importMove(source: SourceCode, node: TSESTree.ImportDeclaration): EntryMove | undefined;
|
|
11
|
+
declare function staticMemberName(node: TSESTree.MemberExpression): string | undefined;
|
|
12
|
+
/** A static member of a namespace import can be diagnosed even when other exports stay at that entry. */
|
|
13
|
+
declare function namespaceMemberMove(source: SourceCode, node: TSESTree.MemberExpression): EntryMove | undefined;
|
|
14
|
+
/** `testing.CommandInputArgs` in a type is a qualified namespace use, not a MemberExpression. */
|
|
15
|
+
declare function namespaceTypeMove(source: SourceCode, node: TSESTree.TSQualifiedName): EntryMove | undefined;
|
|
16
|
+
/** `export { … } from '<entry>'` and `export type { … } from '<entry>'`, split the way an import is. */
|
|
17
|
+
declare function reexportMove(source: SourceCode, node: TSESTree.ExportNamedDeclaration): EntryMove | undefined;
|
|
18
|
+
/** `export * from '<entry>'` of an entry names moved out of: reported, because it does not say which names it passes. */
|
|
19
|
+
declare function starMove(node: TSESTree.ExportAllDeclaration): EntryMove | undefined;
|
|
20
|
+
/** `import('<entry>').Name` in a type, where the name moved or the whole entry did: reported, never rewritten. */
|
|
21
|
+
declare function typeImportMove(node: TSESTree.TSImportType): EntryMove | undefined;
|
|
22
|
+
/** `import('<entry>')` of an entry that moved as a whole. */
|
|
23
|
+
declare function dynamicMove(source: SourceCode, node: TSESTree.ImportExpression): EntryMove | undefined;
|
|
24
|
+
export type { EntryMove };
|
|
25
|
+
export { dynamicMove, importMove, namespaceMemberMove, namespaceTypeMove, reexportMove, starMove, staticMemberName, typeImportMove, };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import{DefinitionType as E}from"@typescript-eslint/scope-manager";import{AST_NODE_TYPES as a}from"@typescript-eslint/types";import{importTypeSource as L,sourceText as R}from"./ast.js";import{ENTRY_MOVES as T}from"./entry-move-rows.js";import{importName as b}from"./model-bindings.js";import{findVariable as P}from"./rule.js";const l={comment:"A comment inside the declaration would be lost with it, so the rewrite is yours",fixed:"The rewrite is mechanical, so `--fix` writes it",rename:"A whole-module use does not identify each renamed member; rewrite it by hand",syntax:"Comments, import attributes, or an incompatible target import prevent a safe rewrite; update this declaration by hand",star:"An `export *` does not say which names it passes on, so the rewrite is yours",type:"A type written as `import(\u2026)` is rewritten by hand",unnamed:"An import with no names says nothing a rewrite could move; change it by hand"};function d(n,e){return T.find(t=>t.from===n&&(t.names==="all"?e===void 0||t.except?.has(e)!==!0:e!==void 0&&t.names.has(e)))}function x(n){return T.find(e=>e.from===n&&e.names==="all")}function B(n){return T.filter(e=>e.from===n)}function w(n){return n.type===a.ImportSpecifier?b(n):n.local.type===a.Identifier?n.local.name:n.local.value}function $(n){return[...new Set(n)]}function g(n,e,t){return{...t,decision:$(e.map(r=>r.decision)).join(", "),from:n,reason:$(e.map(r=>r.reason)).join(" "),to:$(e.map(r=>`\`${r.to}\``)).join(" and ")}}function I(n,e,t){const r=e.getText(n).charAt(0);return`${r}${t}${r}`}function v(n,e){const t=new Map;for(const r of e){const i=d(n,w(r))?.to??n,o=t.get(i);o===void 0?t.set(i,[r]):o.push(r)}return t}function _(n){return n.type===a.ImportSpecifier?{imported:n.imported,kept:n.local}:{imported:n.local,kept:n.exported}}function G(n,e,t){return e.type===a.Literal?I(e,n,t):t}function V(n,e,t){return e.range[0]===t.range[0]&&e.range[1]===t.range[1]?` as ${n.getText(t)}`:""}function h(n,e,t){const r=w(e),i=d(t,r)?.rename?.get(r);if(i===void 0)return n.getText(e);const o=n.getText(e),{imported:u,kept:s}=_(e),[f,p]=u.range;return o.slice(0,f-e.range[0])+G(n,u,i)+V(n,u,s)+o.slice(p-e.range[0])}function Y(n){return n.type===a.ImportSpecifier?n.importKind==="type":n.exportKind==="type"}function H(n,e,t,r,i){if(t)return`${e} type { ${r.map(u=>h(n,u,i)).join(", ")} }`;if(!r.every(Y))return`${e} { ${r.map(u=>h(n,u,i)).join(", ")} }`;const o=r.map(u=>h(n,u,i).replace(/^type\s+/u,""));return`${e} type { ${o.join(", ")} }`}function M(n,e,t,r){const[i,o]=e.type===a.ImportDeclaration?["import",e.importKind]:["export",e.exportKind];return[...r].map(([u,s])=>`${H(n,i,o==="type",s,t.value)} from ${I(t,n,u)};`).join(`
|
|
2
|
+
`)}function K(n,e){return n.importKind===e.importKind||n.importKind==="type"&&e.importKind==="value"}function D(n,e,t){return e.attributes.length>0||e.specifiers.length===0||n.getCommentsInside(e).length>0?!1:e.specifiers.every(r=>r.type===a.ImportSpecifier&&(d(t,b(r))?.to??t)===t)}function Q(n,e,t,r){return r.type!==a.ImportDeclaration||r===e||r.source.value!==t||!K(e,r)?!1:D(n,r,t)}function W(n,e,t){return e.type!==a.ImportDeclaration||!K(e,t)||e.attributes.length>0||n.getCommentsInside(e).length>0||!e.specifiers.every(r=>r.type===a.ImportSpecifier)?!1:v(e.source.value,e.specifiers).has(t.source.value)}function S(n,e,t,r=!0){if(e.attributes.length>0||n.getCommentsInside(e).length>0)return;const i=e.parent;if(i.type!==a.Program)return;const o=i.body.indexOf(e);return i.body.find((u,s)=>{if(!Q(n,e,t,u))return!1;const f=i.body.slice(Math.min(o,s)+1,Math.max(o,s));return!r||f.every(p=>W(n,p,u))})}function q(n,e){return e.parent.type!==a.Program||!D(n,e,e.source.value)||!e.specifiers.some(t=>{const r=b(t);return d(e.source.value,r)?.rename?.has(r)})?!1:e.parent.body.some(t=>t.type===a.ImportDeclaration&&t!==e&&t.source.value!==e.source.value&&t.specifiers.every(r=>r.type===a.ImportSpecifier)&&v(t.source.value,t.specifiers).has(e.source.value)&&S(n,t,e.source.value)===e)}function J(n,e,t,r){const i=h(n,e,t.source.value);return t.importKind==="type"&&r.importKind==="value"?`type ${i}`:i}function N(n,e){const t=n.getText(),r=t.slice(t.lastIndexOf(`
|
|
3
|
+
`,e.range[0]-1)+1,e.range[0]),i=t.slice(e.range[1]),o=/^[ \t]*\r?\n/u.exec(i);return/^[ \t]*$/u.test(r)&&o!==null?[e.range[0],e.range[1]+o[0].length]:e.range}function U(n,e,t,r,i){const o=n.getText(),u=o.slice(t.range[1],r.range[0]);if(!u.includes(`
|
|
4
|
+
`))return` ${i.join(", ")} `;const s=e.specifiers[0],f=o.lastIndexOf(`
|
|
5
|
+
`,s.range[0]-1)+1,p=o.lastIndexOf(`
|
|
6
|
+
`,r.range[0]-1)+1,c=o.slice(f,s.range[0]),m=o.slice(p,r.range[0]),y=/,\s*$/u.test(u)?",":"";return`
|
|
7
|
+
${c}${i.join(`,
|
|
8
|
+
${c}`)}${y}
|
|
9
|
+
${m}`}function X(n,e,t,r){const i=new Map;if(e.type!==a.ImportDeclaration)return i;for(const o of r.keys()){if(o===t)continue;const u=S(n,e,o);u!==void 0&&i.set(o,u)}return i}function j(n,e,t,r){const i=n.getTokens(t),o=i.find(f=>f.value==="{"),u=i.findLast(f=>f.value==="}");if(o===void 0||u===void 0)return null;const s=[...t.specifiers.map(f=>h(n,f,t.source.value)),...r];return e.replaceTextRange([o.range[1],u.range[0]],U(n,t,o,u,s))}function O(n,e,t){const r=e.specifiers;return(v(e.source.value,r).get(t)??[]).map(i=>h(n,i,e.source.value))}function Z(n,e,t,r){return e.parent.type!==a.Program?[e]:e.parent.body.filter(i=>i.type===a.ImportDeclaration&&i!==r&&i.specifiers.every(o=>o.type===a.ImportSpecifier)&&O(n,i,t).length>0&&S(n,i,t)===r)}function ee(n,e,t,r){const i=t.specifiers,o=new Map([...v(t.source.value,i)].filter(([u])=>u!==r));return o.size===0?e.removeRange(N(n,t)):e.replaceText(t,M(n,t,t.source,o))}function ne(n,e,t,r,i){const o=Z(n,t,r,i),u=o.flatMap(f=>O(n,f,r).map(p=>f.importKind==="type"&&i.importKind==="value"?`type ${p}`:p)),s=j(n,e,i,u);return s===null?null:[s,...o.map(f=>ee(n,e,f,r))]}function te(n,e,t,r,i){const o=[];for(const[s,f]of i){const p=r.get(s)?.map(m=>J(n,m,t,f))??[],c=j(n,e,f,p);if(c===null)return null;o.push(c)}const u=new Map([...r].filter(([s])=>!i.has(s)));return o.push(u.size===0?e.removeRange(N(n,t)):e.replaceText(t,M(n,t,t.source,u))),o}function re(n,e,t,r){return t.flatMap(i=>{const o=w(i);return d(r,o)?.rename?.has(o)?[e.replaceText(i,h(n,i,r))]:[]})}function ie(n,e,t,r,i,o){const[u]=o.size===1?[...o.keys()]:[];if(u===void 0)return e.replaceText(t,M(n,t,r,o));const s=[];return u!==r.value&&s.push(e.replaceText(r,I(r,n,u))),s.push(...re(n,e,i,r.value)),s}function oe(n,e,t,r,i,o,u){if(t.type===a.ImportDeclaration&&u.size===1){const[s,f]=[...u][0];return ne(n,e,t,s,f)}return t.type===a.ImportDeclaration&&u.size>1?te(n,e,t,o,u):ie(n,e,t,r,i,o)}function ue(n,e,t,r){const i=v(t.value,r);if(i.size>1&&n.getCommentsInside(e).length>0)return{fix:null,how:l.comment};if(i.size>1&&e.attributes.length>0)return{fix:null,how:l.syntax};const o=X(n,e,t.value,i);return{fix:u=>oe(n,u,e,t,r,i,o),how:l.fixed}}function A(n,e,t,r){const i=t.value,o=r.flatMap(c=>{const m=w(c),y=d(i,m);return y===void 0?[]:[{name:m,row:y}]});if(o.length===0)return;const{fix:u,how:s}=ue(n,e,t,r),f=o.map(({name:c,row:m})=>{const y=m.rename?.get(c);return y===void 0?`\`${c}\``:`\`${c}\` (now \`${y}\`)`}).join(", "),p={how:s,names:f,them:o.length===1?"it":"them",verb:e.type===a.ImportDeclaration?"import":"export"};return{data:g(i,o.map(({row:c})=>c),p),fix:u,node:t}}function F(n,e){const t=e.value,r=x(t);if(r!==void 0)return{data:g(t,[r],{how:r.rename===void 0?l.fixed:l.rename,names:"its former exports",them:"them",verb:"import"}),fix:r.rename===void 0?i=>i.replaceText(e,I(e,n,r.to)):null,node:e}}function ae(n,e){const t=e.source.value;if(q(n,e))return;if(e.specifiers.length===0){const i=x(t),o={how:l.unnamed,names:"its former exports",them:"them",verb:"import"};return i===void 0?void 0:{data:g(t,[i],o),fix:null,node:e.source}}const r=e.specifiers.filter(i=>i.type===a.ImportSpecifier);return r.length!==e.specifiers.length?F(n,e.source):A(n,e,e.source,r)}function se(n,e){const t=P(n.getScope(e),e),[r]=t?.defs??[];return r?.type===E.ImportBinding&&r.node.type===a.ImportNamespaceSpecifier&&r.parent.type===a.ImportDeclaration?r.parent:void 0}function k(n,e,t,r){const i=se(n,e);if(i===void 0)return;const o=i.source.value;if(x(o)!==void 0)return;const u=d(o,t);if(u===void 0)return;const s=u.rename?.get(t);return{data:g(o,[u],{how:"A namespace can include names that stayed here; import this member explicitly by hand",names:s===void 0?`\`${t}\``:`\`${t}\` (now \`${s}\`)`,them:"it",verb:"import"}),fix:null,node:r}}function z(n){return n.computed?n.property.type===a.Literal&&typeof n.property.value=="string"?n.property.value:void 0:n.property.type===a.Identifier?n.property.name:void 0}function fe(n,e){if(e.object.type!==a.Identifier)return;const t=z(e);return t===void 0?void 0:k(n,e.object,t,e.property)}function ce(n,e){return e.left.type===a.Identifier?k(n,e.left,e.right.name,e.right):void 0}function pe(n,e){return e.source===null?void 0:A(n,e,e.source,e.specifiers)}function me(n){const e=n.source.value,t=B(e);if(t.length===0)return;const r=x(e)===void 0?"some of the names this `export *` passes on":"its former exports";return{data:g(e,t,{how:l.star,names:r,them:"them",verb:"export"}),fix:null,node:n.source}}function C(n){if(n!=null)return n.type===a.Identifier?n.name:n.type===a.TSQualifiedName?C(n.left):void 0}function le(n){const e=L(n),t=e===null?void 0:R(e);if(e===null||t===void 0||t===null)return;const r=C(n.qualifier),i=d(t,r);if(i===void 0)return;const o=r===void 0?{names:"its former exports",them:"them"}:{names:`\`${r}\``,them:"it"};return{data:g(t,[i],{how:l.type,...o,verb:"import"}),fix:null,node:e}}function de(n,e){const t=e.source;if(!(t.type!==a.Literal||typeof t.value!="string"))return F(n,t)}export{de as dynamicMove,ae as importMove,fe as namespaceMemberMove,ce as namespaceTypeMove,pe as reexportMove,me as starMove,z as staticMemberName,le as typeImportMove};
|
|
10
|
+
//# sourceMappingURL=entry-moves.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-moves.js","sources":["../src/entry-moves.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 { importTypeSource, sourceText } from './ast';\nimport { ENTRY_MOVES } from './entry-move-rows';\nimport type { EntryMoveRow } from './entry-move-rows';\nimport { importName } from './model-bindings';\nimport { findVariable } from './rule';\nimport type { ReportFixFunction, RuleFix, RuleFixer, SourceCode } from './rule';\n\n/** One statement that names what another entry of the same package publishes now, and the rewrite that moves it. */\ntype EntryMove = {\n readonly data: Readonly<Record<string, string>>;\n readonly fix: ReportFixFunction | null;\n readonly node: TSESTree.Node;\n};\n\n/** A named specifier of an import or of a re-export from another module. */\ntype Named = TSESTree.ExportSpecifier | TSESTree.ImportSpecifier;\n\n/** A statement whose named specifiers can be split between entries: `import { … } from` and `export { … } from`. */\ntype NamedStatement = TSESTree.ExportNamedDeclaration | TSESTree.ImportDeclaration;\n\n/** Why a report carries no rewrite, or the word that it does; the message closes the sentence. */\nconst HOW = {\n comment: 'A comment inside the declaration would be lost with it, so the rewrite is yours',\n fixed: 'The rewrite is mechanical, so `--fix` writes it',\n rename: 'A whole-module use does not identify each renamed member; rewrite it by hand',\n syntax:\n 'Comments, import attributes, or an incompatible target import prevent a safe rewrite; update this declaration by hand',\n star: 'An `export *` does not say which names it passes on, so the rewrite is yours',\n type: 'A type written as `import(…)` is rewritten by hand',\n unnamed: 'An import with no names says nothing a rewrite could move; change it by hand',\n} as const;\n\n/** The row that moved this name of `from`, or the row of an entry that is gone whole. */\nfunction rowOf(from: string, name: string | undefined): EntryMoveRow | undefined {\n return ENTRY_MOVES.find(\n row =>\n row.from === from &&\n (row.names === 'all'\n ? name === undefined || row.except?.has(name) !== true\n : name !== undefined && row.names.has(name)),\n );\n}\n\n/** The row of an entry that is gone whole, where `from` is one. */\nfunction goneRow(from: string): EntryMoveRow | undefined {\n return ENTRY_MOVES.find(row => row.from === from && row.names === 'all');\n}\n\n/** Every row that moved something out of `from`. */\nfunction rowsFrom(from: string): readonly EntryMoveRow[] {\n return ENTRY_MOVES.filter(row => row.from === from);\n}\n\n/** The name a specifier carries at the entry it is taken from, past the alias this file gives it. */\nfunction entryName(specifier: Named): string {\n if (specifier.type === AST_NODE_TYPES.ImportSpecifier) return importName(specifier);\n\n return specifier.local.type === AST_NODE_TYPES.Identifier ? specifier.local.name : specifier.local.value;\n}\n\nfunction unique(values: readonly string[]): readonly string[] {\n return [...new Set(values)];\n}\n\n/** The message of a move, assembled from the rows that moved the names. */\nfunction dataOf(\n from: string,\n rows: readonly EntryMoveRow[],\n words: { readonly how: string; readonly names: string; readonly them: string; readonly verb: string },\n): Readonly<Record<string, string>> {\n return {\n ...words,\n decision: unique(rows.map(row => row.decision)).join(', '),\n from,\n reason: unique(rows.map(row => row.reason)).join(' '),\n to: unique(rows.map(row => `\\`${row.to}\\``)).join(' and '),\n };\n}\n\n/** The same string literal, written with the quote the author used. */\nfunction quoted(literal: TSESTree.StringLiteral, source: SourceCode, value: string): string {\n const quote = source.getText(literal).charAt(0);\n\n return `${quote}${value}${quote}`;\n}\n\n/** The specifiers of the statement grouped by the entry that publishes each now, in written order. */\nfunction groupsOf(from: string, specifiers: readonly Named[]): Map<string, Named[]> {\n const groups = new Map<string, Named[]>();\n\n for (const specifier of specifiers) {\n const entry = rowOf(from, entryName(specifier))?.to ?? from;\n const group = groups.get(entry);\n\n if (group === undefined) groups.set(entry, [specifier]);\n else group.push(specifier);\n }\n\n return groups;\n}\n\n/** The source name may change, but a user's local and re-exported spelling is theirs to keep. */\nfunction sourceTokens(specifier: Named): {\n readonly imported: TSESTree.Identifier | TSESTree.StringLiteral;\n readonly kept: TSESTree.Identifier | TSESTree.StringLiteral;\n} {\n return specifier.type === AST_NODE_TYPES.ImportSpecifier\n ? { imported: specifier.imported, kept: specifier.local }\n : { imported: specifier.local, kept: specifier.exported };\n}\n\nfunction replacementToken(\n source: SourceCode,\n token: TSESTree.Identifier | TSESTree.StringLiteral,\n next: string,\n): string {\n return token.type === AST_NODE_TYPES.Literal ? quoted(token, source, next) : next;\n}\n\nfunction keptAlias(source: SourceCode, imported: TSESTree.Node, kept: TSESTree.Node): string {\n return imported.range[0] === kept.range[0] && imported.range[1] === kept.range[1]\n ? ` as ${source.getText(kept)}`\n : '';\n}\n\nfunction namedText(source: SourceCode, specifier: Named, from: string): string {\n const name = entryName(specifier);\n const replacement = rowOf(from, name)?.rename?.get(name);\n if (replacement === undefined) return source.getText(specifier);\n const written = source.getText(specifier);\n const { imported, kept } = sourceTokens(specifier);\n const [start, end] = imported.range;\n return (\n written.slice(0, start - specifier.range[0]) +\n replacementToken(source, imported, replacement) +\n keptAlias(source, imported, kept) +\n written.slice(end - specifier.range[0])\n );\n}\n\n/** Whether a specifier carries its own `type`: `import { type Mode }`, `export { type Theme }`. */\nfunction inlineType(specifier: Named): boolean {\n return specifier.type === AST_NODE_TYPES.ImportSpecifier\n ? specifier.importKind === 'type'\n : specifier.exportKind === 'type';\n}\n\n/**\n * One statement for one entry, with its specifiers as written — their aliases and `type` modifiers included. A group\n * whose every specifier is `type` becomes a type-only statement without the modifiers: under `verbatimModuleSyntax`\n * `import { type Mode } from …` keeps `import {} from …`, a load of the entry the source never asked for.\n */\nfunction groupText(source: SourceCode, keyword: string, whole: boolean, group: readonly Named[], from: string): string {\n if (whole) return `${keyword} type { ${group.map(specifier => namedText(source, specifier, from)).join(', ')} }`;\n\n if (!group.every(inlineType))\n return `${keyword} { ${group.map(specifier => namedText(source, specifier, from)).join(', ')} }`;\n\n const names = group.map(specifier => namedText(source, specifier, from).replace(/^type\\s+/u, ''));\n\n return `${keyword} type { ${names.join(', ')} }`;\n}\n\n/** One statement per entry, in the order the entries are first written. */\nfunction splitText(\n source: SourceCode,\n node: NamedStatement,\n literal: TSESTree.StringLiteral,\n groups: ReadonlyMap<string, readonly Named[]>,\n): string {\n const [keyword, kind] =\n node.type === AST_NODE_TYPES.ImportDeclaration ? ['import', node.importKind] : ['export', node.exportKind];\n\n return [...groups]\n .map(\n ([entry, group]) =>\n `${groupText(source, keyword, kind === 'type', group, literal.value)} from ${quoted(literal, source, entry)};`,\n )\n .join('\\n');\n}\n\n/** A target declaration can accept the moved names without dropping attributes, comments, or other bindings. */\nfunction compatibleKind(from: TSESTree.ImportDeclaration, target: TSESTree.ImportDeclaration): boolean {\n return from.importKind === target.importKind || (from.importKind === 'type' && target.importKind === 'value');\n}\n\nfunction cleanNamedTarget(source: SourceCode, node: TSESTree.ImportDeclaration, target: string): boolean {\n if (node.attributes.length > 0 || node.specifiers.length === 0 || source.getCommentsInside(node).length > 0)\n return false;\n return node.specifiers.every(\n specifier =>\n specifier.type === AST_NODE_TYPES.ImportSpecifier &&\n (rowOf(target, importName(specifier))?.to ?? target) === target,\n );\n}\n\nfunction isMergeTarget(\n source: SourceCode,\n from: TSESTree.ImportDeclaration,\n target: string,\n candidate: TSESTree.ProgramStatement,\n): candidate is TSESTree.ImportDeclaration {\n if (candidate.type !== AST_NODE_TYPES.ImportDeclaration || candidate === from) return false;\n if (candidate.source.value !== target || !compatibleKind(from, candidate)) return false;\n return cleanNamedTarget(source, candidate, target);\n}\n\n/** A wide fix may cross only other migrations it incorporates; Oxlint would swallow unrelated fixes there. */\nfunction mergeBridge(source: SourceCode, node: TSESTree.ProgramStatement, target: TSESTree.ImportDeclaration): boolean {\n if (node.type !== AST_NODE_TYPES.ImportDeclaration || !compatibleKind(node, target)) return false;\n if (node.attributes.length > 0 || source.getCommentsInside(node).length > 0) return false;\n if (!node.specifiers.every(specifier => specifier.type === AST_NODE_TYPES.ImportSpecifier)) return false;\n return groupsOf(node.source.value, node.specifiers).has(target.source.value);\n}\n\nfunction mergeTarget(\n source: SourceCode,\n node: TSESTree.ImportDeclaration,\n target: string,\n local = true,\n): TSESTree.ImportDeclaration | undefined {\n if (node.attributes.length > 0 || source.getCommentsInside(node).length > 0) return undefined;\n const parent = node.parent;\n if (parent.type !== AST_NODE_TYPES.Program) return undefined;\n const index = parent.body.indexOf(node);\n return parent.body.find((statement, targetIndex): statement is TSESTree.ImportDeclaration => {\n if (!isMergeTarget(source, node, target, statement)) return false;\n const between = parent.body.slice(Math.min(index, targetIndex) + 1, Math.max(index, targetIndex));\n return !local || between.every(declaration => mergeBridge(source, declaration, statement));\n });\n}\n\n/** An incoming merge owns the target's rename too, so the target must not emit a competing fix/report. */\nfunction renamedByIncomingMerge(source: SourceCode, target: TSESTree.ImportDeclaration): boolean {\n if (target.parent.type !== AST_NODE_TYPES.Program || !cleanNamedTarget(source, target, target.source.value))\n return false;\n if (\n !target.specifiers.some(specifier => {\n const name = importName(specifier as TSESTree.ImportSpecifier);\n return rowOf(target.source.value, name)?.rename?.has(name);\n })\n )\n return false;\n return target.parent.body.some(\n statement =>\n statement.type === AST_NODE_TYPES.ImportDeclaration &&\n statement !== target &&\n statement.source.value !== target.source.value &&\n statement.specifiers.every(specifier => specifier.type === AST_NODE_TYPES.ImportSpecifier) &&\n groupsOf(statement.source.value, statement.specifiers).has(target.source.value) &&\n mergeTarget(source, statement, target.source.value) === target,\n );\n}\n\n/** An import-type name merged into a value import keeps its type-only status inline. */\nfunction mergedSpecifierText(\n source: SourceCode,\n specifier: TSESTree.ImportSpecifier,\n from: TSESTree.ImportDeclaration,\n target: TSESTree.ImportDeclaration,\n): string {\n const written = namedText(source, specifier, from.source.value);\n return from.importKind === 'type' && target.importKind === 'value' ? `type ${written}` : written;\n}\n\n/** Remove a standalone import's newline too, so merging does not introduce a formatting-only change. */\nfunction removedImportRange(source: SourceCode, node: TSESTree.ImportDeclaration): readonly [number, number] {\n const code = source.getText();\n const before = code.slice(code.lastIndexOf('\\n', node.range[0] - 1) + 1, node.range[0]);\n const after = code.slice(node.range[1]);\n const lineEnd = /^[ \\t]*\\r?\\n/u.exec(after);\n return /^[ \\t]*$/u.test(before) && lineEnd !== null ? [node.range[0], node.range[1] + lineEnd[0].length] : node.range;\n}\n\n/** Keep a target's one-line or multiline import layout when adding names to it. */\nfunction mergedNamesText(\n source: SourceCode,\n target: TSESTree.ImportDeclaration,\n opening: TSESTree.Token,\n closing: TSESTree.Token,\n names: readonly string[],\n): string {\n const code = source.getText();\n const inside = code.slice(opening.range[1], closing.range[0]);\n if (!inside.includes('\\n')) return ` ${names.join(', ')} `;\n const first = target.specifiers[0]!;\n const firstLine = code.lastIndexOf('\\n', first.range[0] - 1) + 1;\n const closingLine = code.lastIndexOf('\\n', closing.range[0] - 1) + 1;\n const indent = code.slice(firstLine, first.range[0]);\n const closingIndent = code.slice(closingLine, closing.range[0]);\n const trailingComma = /,\\s*$/u.test(inside) ? ',' : '';\n return `\\n${indent}${names.join(`,\\n${indent}`)}${trailingComma}\\n${closingIndent}`;\n}\n\ntype NamedGroups = ReadonlyMap<string, readonly Named[]>;\n\nfunction targetImports(\n source: SourceCode,\n node: NamedStatement,\n from: string,\n groups: NamedGroups,\n): ReadonlyMap<string, TSESTree.ImportDeclaration> {\n const targets = new Map<string, TSESTree.ImportDeclaration>();\n if (node.type !== AST_NODE_TYPES.ImportDeclaration) return targets;\n for (const entry of groups.keys()) {\n if (entry === from) continue;\n const target = mergeTarget(source, node, entry);\n if (target !== undefined) targets.set(entry, target);\n }\n return targets;\n}\n\nfunction targetContentFix(\n source: SourceCode,\n fixer: RuleFixer,\n target: TSESTree.ImportDeclaration,\n incoming: readonly string[],\n): RuleFix | null {\n const tokens = source.getTokens(target);\n const opening = tokens.find(token => token.value === '{');\n const closing = tokens.findLast(token => token.value === '}');\n if (opening === undefined || closing === undefined) return null;\n const names = [\n ...target.specifiers.map(specifier =>\n namedText(source, specifier as TSESTree.ImportSpecifier, target.source.value),\n ),\n ...incoming,\n ];\n return fixer.replaceTextRange(\n [opening.range[1], closing.range[0]],\n mergedNamesText(source, target, opening, closing, names),\n );\n}\n\nfunction importGroup(source: SourceCode, statement: TSESTree.ImportDeclaration, entry: string): readonly string[] {\n const named = statement.specifiers as TSESTree.ImportSpecifier[];\n return (groupsOf(statement.source.value, named).get(entry) ?? []).map(specifier =>\n namedText(source, specifier, statement.source.value),\n );\n}\n\nfunction compatibleSources(\n source: SourceCode,\n node: TSESTree.ImportDeclaration,\n entry: string,\n target: TSESTree.ImportDeclaration,\n): readonly TSESTree.ImportDeclaration[] {\n if (node.parent.type !== AST_NODE_TYPES.Program) return [node];\n return node.parent.body.filter(\n (statement): statement is TSESTree.ImportDeclaration =>\n statement.type === AST_NODE_TYPES.ImportDeclaration &&\n statement !== target &&\n statement.specifiers.every(specifier => specifier.type === AST_NODE_TYPES.ImportSpecifier) &&\n importGroup(source, statement, entry).length > 0 &&\n mergeTarget(source, statement, entry) === target,\n );\n}\n\nfunction withoutMergedGroup(\n source: SourceCode,\n fixer: RuleFixer,\n statement: TSESTree.ImportDeclaration,\n entry: string,\n): RuleFix {\n const named = statement.specifiers as TSESTree.ImportSpecifier[];\n const remaining = new Map([...groupsOf(statement.source.value, named)].filter(([name]) => name !== entry));\n return remaining.size === 0\n ? fixer.removeRange(removedImportRange(source, statement))\n : fixer.replaceText(statement, splitText(source, statement, statement.source, remaining));\n}\n\nfunction mergeOneTargetFix(\n source: SourceCode,\n fixer: RuleFixer,\n node: TSESTree.ImportDeclaration,\n entry: string,\n target: TSESTree.ImportDeclaration,\n): readonly RuleFix[] | null {\n const compatible = compatibleSources(source, node, entry, target);\n const incoming = compatible.flatMap(statement =>\n importGroup(source, statement, entry).map(name =>\n statement.importKind === 'type' && target.importKind === 'value' ? `type ${name}` : name,\n ),\n );\n const targetEdit = targetContentFix(source, fixer, target, incoming);\n return targetEdit === null\n ? null\n : [targetEdit, ...compatible.map(statement => withoutMergedGroup(source, fixer, statement, entry))];\n}\n\nfunction mergeManyTargetsFix(\n source: SourceCode,\n fixer: RuleFixer,\n node: TSESTree.ImportDeclaration,\n groups: NamedGroups,\n targets: ReadonlyMap<string, TSESTree.ImportDeclaration>,\n): readonly RuleFix[] | null {\n const changes: RuleFix[] = [];\n for (const [entry, target] of targets) {\n const incoming =\n groups\n .get(entry)\n ?.map(specifier => mergedSpecifierText(source, specifier as TSESTree.ImportSpecifier, node, target)) ?? [];\n const edit = targetContentFix(source, fixer, target, incoming);\n if (edit === null) return null;\n changes.push(edit);\n }\n const remaining = new Map([...groups].filter(([entry]) => !targets.has(entry)));\n changes.push(\n remaining.size === 0\n ? fixer.removeRange(removedImportRange(source, node))\n : fixer.replaceText(node, splitText(source, node, node.source, remaining)),\n );\n return changes;\n}\n\nfunction renamedSpecifierFixes(\n source: SourceCode,\n fixer: RuleFixer,\n specifiers: readonly Named[],\n from: string,\n): readonly RuleFix[] {\n return specifiers.flatMap(specifier => {\n const name = entryName(specifier);\n return rowOf(from, name)?.rename?.has(name)\n ? [fixer.replaceText(specifier, namedText(source, specifier, from))]\n : [];\n });\n}\n\nfunction simpleNamedFix(\n source: SourceCode,\n fixer: RuleFixer,\n node: NamedStatement,\n literal: TSESTree.StringLiteral,\n specifiers: readonly Named[],\n groups: NamedGroups,\n): RuleFix | readonly RuleFix[] {\n const [only] = groups.size === 1 ? [...groups.keys()] : [];\n if (only === undefined) return fixer.replaceText(node, splitText(source, node, literal, groups));\n const changes: RuleFix[] = [];\n if (only !== literal.value) changes.push(fixer.replaceText(literal, quoted(literal, source, only)));\n changes.push(...renamedSpecifierFixes(source, fixer, specifiers, literal.value));\n return changes;\n}\n\nfunction applyNamedFix(\n source: SourceCode,\n fixer: RuleFixer,\n node: NamedStatement,\n literal: TSESTree.StringLiteral,\n specifiers: readonly Named[],\n groups: NamedGroups,\n targets: ReadonlyMap<string, TSESTree.ImportDeclaration>,\n): RuleFix | readonly RuleFix[] | null {\n if (node.type === AST_NODE_TYPES.ImportDeclaration && targets.size === 1) {\n const [entry, target] = [...targets][0]!;\n return mergeOneTargetFix(source, fixer, node, entry, target);\n }\n if (node.type === AST_NODE_TYPES.ImportDeclaration && targets.size > 1)\n return mergeManyTargetsFix(source, fixer, node, groups, targets);\n return simpleNamedFix(source, fixer, node, literal, specifiers, groups);\n}\n\n/** Move one named declaration while retaining authored local and public aliases. */\nfunction namedFix(\n source: SourceCode,\n node: NamedStatement,\n literal: TSESTree.StringLiteral,\n specifiers: readonly Named[],\n): { readonly fix: ReportFixFunction | null; readonly how: string } {\n const groups = groupsOf(literal.value, specifiers);\n if (groups.size > 1 && source.getCommentsInside(node).length > 0) return { fix: null, how: HOW.comment };\n if (groups.size > 1 && node.attributes.length > 0) return { fix: null, how: HOW.syntax };\n const targets = targetImports(source, node, literal.value, groups);\n return {\n fix: fixer => applyNamedFix(source, fixer, node, literal, specifiers, groups, targets),\n how: HOW.fixed,\n };\n}\n\n/** The names of a named import or re-export that another entry publishes now. */\nfunction namedMove(\n source: SourceCode,\n node: NamedStatement,\n literal: TSESTree.StringLiteral,\n specifiers: readonly Named[],\n): EntryMove | undefined {\n const from = literal.value;\n const moved = specifiers.flatMap(specifier => {\n const name = entryName(specifier);\n const row = rowOf(from, name);\n\n return row === undefined ? [] : [{ name, row }];\n });\n\n if (moved.length === 0) return undefined;\n\n const { fix, how } = namedFix(source, node, literal, specifiers);\n const names = moved\n .map(({ name, row }) => {\n const renamed = row.rename?.get(name);\n\n return renamed === undefined ? `\\`${name}\\`` : `\\`${name}\\` (now \\`${renamed}\\`)`;\n })\n .join(', ');\n const words = {\n how,\n names,\n them: moved.length === 1 ? 'it' : 'them',\n verb: node.type === AST_NODE_TYPES.ImportDeclaration ? 'import' : 'export',\n };\n\n return {\n data: dataOf(\n from,\n moved.map(({ row }) => row),\n words,\n ),\n fix,\n node: literal,\n };\n}\n\n/** An entry that is gone whole — a namespace import, or `import('<entry>')` — takes the new entry's name. */\nfunction wholeMove(source: SourceCode, literal: TSESTree.StringLiteral): EntryMove | undefined {\n const from = literal.value;\n const row = goneRow(from);\n\n if (row === undefined) return undefined;\n\n return {\n data: dataOf(from, [row], {\n how: row.rename === undefined ? HOW.fixed : HOW.rename,\n names: 'its former exports',\n them: 'them',\n verb: 'import',\n }),\n fix: row.rename === undefined ? fixer => fixer.replaceText(literal, quoted(literal, source, row.to)) : null,\n node: literal,\n };\n}\n\n/** `import { … } from '<entry>'`, a namespace of it, or an import of it with no names. */\nfunction importMove(source: SourceCode, node: TSESTree.ImportDeclaration): EntryMove | undefined {\n const from = node.source.value;\n\n if (renamedByIncomingMerge(source, node)) return undefined;\n\n if (node.specifiers.length === 0) {\n const row = goneRow(from);\n const words = { how: HOW.unnamed, names: 'its former exports', them: 'them', verb: 'import' };\n\n return row === undefined ? undefined : { data: dataOf(from, [row], words), fix: null, node: node.source };\n }\n\n const named = node.specifiers.filter(specifier => specifier.type === AST_NODE_TYPES.ImportSpecifier);\n\n // A namespace moves whole only where the whole entry did; a namespace of an entry that kept names is left alone.\n if (named.length !== node.specifiers.length) return wholeMove(source, node.source);\n\n return namedMove(source, node, node.source, named);\n}\n\n/** One statically named value or type read from a namespace whose entry retained other exports. */\nfunction namespaceImport(source: SourceCode, object: TSESTree.Identifier): TSESTree.ImportDeclaration | undefined {\n const binding = findVariable(source.getScope(object), object);\n const [definition] = binding?.defs ?? [];\n return definition?.type === DefinitionType.ImportBinding &&\n definition.node.type === AST_NODE_TYPES.ImportNamespaceSpecifier &&\n definition.parent.type === AST_NODE_TYPES.ImportDeclaration\n ? definition.parent\n : undefined;\n}\n\nfunction namespaceMove(\n source: SourceCode,\n object: TSESTree.Identifier,\n name: string,\n word: TSESTree.Node,\n): EntryMove | undefined {\n const declaration = namespaceImport(source, object);\n if (declaration === undefined) return undefined;\n const from = declaration.source.value;\n if (goneRow(from) !== undefined) return undefined;\n const row = rowOf(from, name);\n if (row === undefined) return undefined;\n const next = row.rename?.get(name);\n return {\n data: dataOf(from, [row], {\n how: 'A namespace can include names that stayed here; import this member explicitly by hand',\n names: next === undefined ? `\\`${name}\\`` : `\\`${name}\\` (now \\`${next}\\`)`,\n them: 'it',\n verb: 'import',\n }),\n fix: null,\n node: word,\n };\n}\n\nfunction staticMemberName(node: TSESTree.MemberExpression): string | undefined {\n if (!node.computed) return node.property.type === AST_NODE_TYPES.Identifier ? node.property.name : undefined;\n return node.property.type === AST_NODE_TYPES.Literal && typeof node.property.value === 'string'\n ? node.property.value\n : undefined;\n}\n\n/** A static member of a namespace import can be diagnosed even when other exports stay at that entry. */\nfunction namespaceMemberMove(source: SourceCode, node: TSESTree.MemberExpression): EntryMove | undefined {\n if (node.object.type !== AST_NODE_TYPES.Identifier) return undefined;\n const name = staticMemberName(node);\n return name === undefined ? undefined : namespaceMove(source, node.object, name, node.property);\n}\n\n/** `testing.CommandInputArgs` in a type is a qualified namespace use, not a MemberExpression. */\nfunction namespaceTypeMove(source: SourceCode, node: TSESTree.TSQualifiedName): EntryMove | undefined {\n return node.left.type === AST_NODE_TYPES.Identifier\n ? namespaceMove(source, node.left, node.right.name, node.right)\n : undefined;\n}\n\n/** `export { … } from '<entry>'` and `export type { … } from '<entry>'`, split the way an import is. */\nfunction reexportMove(source: SourceCode, node: TSESTree.ExportNamedDeclaration): EntryMove | undefined {\n return node.source === null ? undefined : namedMove(source, node, node.source, node.specifiers);\n}\n\n/** `export * from '<entry>'` of an entry names moved out of: reported, because it does not say which names it passes. */\nfunction starMove(node: TSESTree.ExportAllDeclaration): EntryMove | undefined {\n const from = node.source.value;\n const rows = rowsFrom(from);\n\n if (rows.length === 0) return undefined;\n\n const names = goneRow(from) === undefined ? 'some of the names this `export *` passes on' : 'its former exports';\n\n return {\n data: dataOf(from, rows, { how: HOW.star, names, them: 'them', verb: 'export' }),\n fix: null,\n node: node.source,\n };\n}\n\n/** The first name a type import reads off its module: `Options` of `import('<entry>').Options.Field`. */\nfunction qualifierName(qualifier: TSESTree.Node | null | undefined): string | undefined {\n if (qualifier === null || qualifier === undefined) return undefined;\n\n if (qualifier.type === AST_NODE_TYPES.Identifier) return qualifier.name;\n\n return qualifier.type === AST_NODE_TYPES.TSQualifiedName ? qualifierName(qualifier.left) : undefined;\n}\n\n/** `import('<entry>').Name` in a type, where the name moved or the whole entry did: reported, never rewritten. */\nfunction typeImportMove(node: TSESTree.TSImportType): EntryMove | undefined {\n const written = importTypeSource(node);\n const from = written === null ? undefined : sourceText(written);\n\n if (written === null || from === undefined || from === null) return undefined;\n\n const name = qualifierName(node.qualifier);\n const row = rowOf(from, name);\n\n if (row === undefined) return undefined;\n\n const words =\n name === undefined ? { names: 'its former exports', them: 'them' } : { names: `\\`${name}\\``, them: 'it' };\n\n return { data: dataOf(from, [row], { how: HOW.type, ...words, verb: 'import' }), fix: null, node: written };\n}\n\n/** `import('<entry>')` of an entry that moved as a whole. */\nfunction dynamicMove(source: SourceCode, node: TSESTree.ImportExpression): EntryMove | undefined {\n const literal = node.source;\n\n if (literal.type !== AST_NODE_TYPES.Literal || typeof literal.value !== 'string') return undefined;\n\n return wholeMove(source, literal);\n}\n\nexport type { EntryMove };\nexport {\n dynamicMove,\n importMove,\n namespaceMemberMove,\n namespaceTypeMove,\n reexportMove,\n starMove,\n staticMemberName,\n typeImportMove,\n};\n"],"names":["HOW","rowOf","from","name","ENTRY_MOVES","row","goneRow","rowsFrom","entryName","specifier","AST_NODE_TYPES","importName","unique","values","dataOf","rows","words","quoted","literal","source","value","quote","groupsOf","specifiers","groups","entry","group","sourceTokens","replacementToken","token","next","keptAlias","imported","kept","namedText","replacement","written","start","end","inlineType","groupText","keyword","whole","names","splitText","node","kind","compatibleKind","target","cleanNamedTarget","isMergeTarget","candidate","mergeBridge","mergeTarget","local","parent","index","statement","targetIndex","between","declaration","renamedByIncomingMerge","mergedSpecifierText","removedImportRange","code","before","after","lineEnd","mergedNamesText","opening","closing","inside","first","firstLine","closingLine","indent","closingIndent","trailingComma","targetImports","targets","targetContentFix","fixer","incoming","tokens","importGroup","named","compatibleSources","withoutMergedGroup","remaining","mergeOneTargetFix","compatible","targetEdit","mergeManyTargetsFix","changes","edit","renamedSpecifierFixes","simpleNamedFix","only","applyNamedFix","namedFix","namedMove","moved","fix","how","renamed","wholeMove","importMove","namespaceImport","object","binding","findVariable","definition","DefinitionType","namespaceMove","word","staticMemberName","namespaceMemberMove","namespaceTypeMove","reexportMove","starMove","qualifierName","qualifier","typeImportMove","importTypeSource","sourceText","dynamicMove"],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/types';
|
|
2
|
+
import type { SourceCode } from './rule.js';
|
|
2
3
|
interface BodyRecordEntry {
|
|
3
4
|
readonly implementation: TSESTree.Node | undefined;
|
|
4
5
|
readonly options: TSESTree.Node | undefined;
|
|
5
6
|
}
|
|
7
|
+
declare function isBodyCall(source: SourceCode, call: TSESTree.CallExpression): boolean;
|
|
6
8
|
/** Resolve local record/tuple aliases only after identifying the authentic authoring API by its import. */
|
|
7
|
-
declare function bodyRecordEntries(source:
|
|
8
|
-
export { bodyRecordEntries };
|
|
9
|
+
declare function bodyRecordEntries(source: SourceCode, call: TSESTree.CallExpression): readonly BodyRecordEntry[];
|
|
10
|
+
export { bodyRecordEntries, isBodyCall };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{AST_NODE_TYPES as r}from"@typescript-eslint/
|
|
1
|
+
import{AST_NODE_TYPES as r}from"@typescript-eslint/types";import{findProperty as s}from"./ast.js";import{localValue as p,isApi as a}from"./model-bindings.js";function f(n,t){const e=p(n,t.callee);return e.type!==r.MemberExpression||e.computed||e.property.type!==r.Identifier||e.property.name!=="body"?!1:a(n,e.object,"@opetope/runtime","defineFeature")}function l(n,t){if(!f(n,t))return;const e=t.arguments[1];if(e===void 0)return;const i=p(n,e);return i.type===r.ObjectExpression?i:void 0}function y(n,t){const e=l(n,t);if(e===void 0)return[];const i=s(e,"provides");if(i===void 0)return[];const u=p(n,i.value);return u.type!==r.ObjectExpression?[]:u.properties.flatMap(d=>{if(d.type!==r.Property)return[];const o=p(n,d.value);return[{implementation:o.type===r.ArrayExpression?o.elements[0]??void 0:o,options:o.type===r.ArrayExpression?o.elements[1]??void 0:void 0}]})}export{y as bodyRecordEntries,f as isBodyCall};
|
|
2
2
|
//# sourceMappingURL=feature-body-records.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-body-records.js","sources":["../src/feature-body-records.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"file":"feature-body-records.js","sources":["../src/feature-body-records.ts"],"sourcesContent":["import { AST_NODE_TYPES } from '@typescript-eslint/types';\nimport type { TSESTree } from '@typescript-eslint/types';\n\nimport { findProperty } from './ast';\nimport { isApi, localValue } from './model-bindings';\nimport type { SourceCode } from './rule';\n\ninterface BodyRecordEntry {\n readonly implementation: TSESTree.Node | undefined;\n readonly options: TSESTree.Node | undefined;\n}\n\nfunction isBodyCall(source: SourceCode, call: TSESTree.CallExpression): boolean {\n const callee = localValue(source, call.callee);\n if (callee.type !== AST_NODE_TYPES.MemberExpression || callee.computed) return false;\n if (callee.property.type !== AST_NODE_TYPES.Identifier || callee.property.name !== 'body') return false;\n return isApi(source, callee.object, '@opetope/runtime', 'defineFeature');\n}\n\nfunction bodySections(source: SourceCode, call: TSESTree.CallExpression): TSESTree.ObjectExpression | undefined {\n if (!isBodyCall(source, call)) return undefined;\n const input = call.arguments[1];\n if (input === undefined) return undefined;\n const value = localValue(source, input);\n return value.type === AST_NODE_TYPES.ObjectExpression ? value : undefined;\n}\n\n/** Resolve local record/tuple aliases only after identifying the authentic authoring API by its import. */\nfunction bodyRecordEntries(source: SourceCode, call: TSESTree.CallExpression): readonly BodyRecordEntry[] {\n const sections = bodySections(source, call);\n if (sections === undefined) return [];\n const property = findProperty(sections, 'provides');\n if (property === undefined) return [];\n const record = localValue(source, property.value);\n if (record.type !== AST_NODE_TYPES.ObjectExpression) return [];\n return record.properties.flatMap(entry => {\n if (entry.type !== AST_NODE_TYPES.Property) return [];\n const value = localValue(source, entry.value);\n return [\n {\n implementation: value.type === AST_NODE_TYPES.ArrayExpression ? (value.elements[0] ?? undefined) : value,\n options: value.type === AST_NODE_TYPES.ArrayExpression ? (value.elements[1] ?? undefined) : undefined,\n },\n ];\n });\n}\n\nexport { bodyRecordEntries, isBodyCall };\n"],"names":["isBodyCall","source","call","callee","localValue","AST_NODE_TYPES","isApi","bodySections","input","value","bodyRecordEntries","sections","property","findProperty","record","entry"],"mappings":"8JAYA,SAASA,EAAWC,EAAoBC,EAA6B,CACnE,MAAMC,EAASC,EAAWH,EAAQC,EAAK,MAAM,EAE7C,OADIC,EAAO,OAASE,EAAe,kBAAoBF,EAAO,UAC1DA,EAAO,SAAS,OAASE,EAAe,YAAcF,EAAO,SAAS,OAAS,OAAe,GAC3FG,EAAML,EAAQE,EAAO,OAAQ,mBAAoB,eAAe,CACzE,CAEA,SAASI,EAAaN,EAAoBC,EAA6B,CACrE,GAAI,CAACF,EAAWC,EAAQC,CAAI,EAAG,OAC/B,MAAMM,EAAQN,EAAK,UAAU,CAAC,EAC9B,GAAIM,IAAU,OAAW,OACzB,MAAMC,EAAQL,EAAWH,EAAQO,CAAK,EACtC,OAAOC,EAAM,OAASJ,EAAe,iBAAmBI,EAAQ,MAClE,CAGA,SAASC,EAAkBT,EAAoBC,EAA6B,CAC1E,MAAMS,EAAWJ,EAAaN,EAAQC,CAAI,EAC1C,GAAIS,IAAa,OAAW,MAAO,CAAA,EACnC,MAAMC,EAAWC,EAAaF,EAAU,UAAU,EAClD,GAAIC,IAAa,OAAW,MAAO,CAAA,EACnC,MAAME,EAASV,EAAWH,EAAQW,EAAS,KAAK,EAChD,OAAIE,EAAO,OAAST,EAAe,iBAAyB,CAAA,EACrDS,EAAO,WAAW,QAAQC,GAAQ,CACvC,GAAIA,EAAM,OAASV,EAAe,SAAU,MAAO,CAAA,EACnD,MAAMI,EAAQL,EAAWH,EAAQc,EAAM,KAAK,EAC5C,MAAO,CACL,CACE,eAAgBN,EAAM,OAASJ,EAAe,gBAAmBI,EAAM,SAAS,CAAC,GAAK,OAAaA,EACnG,QAASA,EAAM,OAASJ,EAAe,gBAAmBI,EAAM,SAAS,CAAC,GAAK,OAAa,MAC7F,EAEL,CAAC,CACH"}
|