@geoql/oxlint-plugin-vue-doctor 0.1.1 → 1.0.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/README.md +1 -1
- package/dist/index.d.ts +16 -0
- package/dist/index.js +46 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ Vue 3 only. Severity levels are `error | warn | info`.
|
|
|
31
31
|
|
|
32
32
|
## Architecture
|
|
33
33
|
|
|
34
|
-
See [`docs/
|
|
34
|
+
See [`docs/SPEC.md`](../../docs/SPEC.md) §10 for how the JS plugin co-loads with oxlint's native `vue` plugin and why the script and template rules live in different passes.
|
|
35
35
|
|
|
36
36
|
## License
|
|
37
37
|
|
package/dist/index.d.ts
CHANGED
|
@@ -14,9 +14,19 @@ interface AstNode {
|
|
|
14
14
|
loc?: SourceLocation;
|
|
15
15
|
[key: string]: unknown;
|
|
16
16
|
}
|
|
17
|
+
interface Fix {
|
|
18
|
+
range: [number, number];
|
|
19
|
+
text: string;
|
|
20
|
+
node?: AstNode;
|
|
21
|
+
}
|
|
22
|
+
interface Fixer {
|
|
23
|
+
replaceText: (node: AstNode, text: string) => Fix;
|
|
24
|
+
}
|
|
25
|
+
type FixFn = (fixer: Fixer) => Fix;
|
|
17
26
|
interface ReportDescriptor {
|
|
18
27
|
node: AstNode;
|
|
19
28
|
message: string;
|
|
29
|
+
fix?: FixFn;
|
|
20
30
|
}
|
|
21
31
|
interface RuleContext {
|
|
22
32
|
report: (descriptor: ReportDescriptor) => void;
|
|
@@ -26,8 +36,14 @@ interface RuleContext {
|
|
|
26
36
|
capabilities?: Set<string>;
|
|
27
37
|
}
|
|
28
38
|
type RuleVisitor = (node: AstNode) => void;
|
|
39
|
+
interface RuleMeta {
|
|
40
|
+
name?: string;
|
|
41
|
+
fixable?: 'code' | 'whitespace';
|
|
42
|
+
}
|
|
29
43
|
interface Rule {
|
|
44
|
+
meta?: RuleMeta;
|
|
30
45
|
create: (context: RuleContext) => Record<string, RuleVisitor>;
|
|
46
|
+
fix?: (node: AstNode) => string | null;
|
|
31
47
|
}
|
|
32
48
|
interface Plugin {
|
|
33
49
|
meta: {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
//#region src/define-rule.ts
|
|
2
2
|
function defineRule(rule) {
|
|
3
|
-
|
|
3
|
+
const userFix = rule.fix;
|
|
4
|
+
if (!userFix) return rule;
|
|
5
|
+
return {
|
|
6
|
+
...rule,
|
|
7
|
+
meta: {
|
|
8
|
+
...rule.meta,
|
|
9
|
+
fixable: "code"
|
|
10
|
+
},
|
|
11
|
+
create(context) {
|
|
12
|
+
const wrapped = {
|
|
13
|
+
...context,
|
|
14
|
+
report(descriptor) {
|
|
15
|
+
const replacement = userFix(descriptor.node);
|
|
16
|
+
if (replacement === null) {
|
|
17
|
+
context.report(descriptor);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
context.report({
|
|
21
|
+
...descriptor,
|
|
22
|
+
fix: (fixer) => fixer.replaceText(descriptor.node, replacement)
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
return rule.create(wrapped);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
4
29
|
}
|
|
5
30
|
//#endregion
|
|
6
31
|
//#region src/rules/composition/defineProps-typed.ts
|
|
@@ -129,17 +154,27 @@ const noDestructureReactiveWithoutToRefs = defineRule({ create(context) {
|
|
|
129
154
|
//#endregion
|
|
130
155
|
//#region src/rules/ai-slop/no-em-dash-in-string.ts
|
|
131
156
|
const EM_DASH = "—";
|
|
132
|
-
const noEmDashInString = defineRule({
|
|
133
|
-
|
|
157
|
+
const noEmDashInString = defineRule({
|
|
158
|
+
create(context) {
|
|
159
|
+
return { Literal(node) {
|
|
160
|
+
const literal = node;
|
|
161
|
+
if (typeof literal.value !== "string") return;
|
|
162
|
+
if (!literal.value.includes(EM_DASH)) return;
|
|
163
|
+
context.report({
|
|
164
|
+
node,
|
|
165
|
+
message: "Em dash in string literal reads as AI-generated output; use comma, colon, or parentheses."
|
|
166
|
+
});
|
|
167
|
+
} };
|
|
168
|
+
},
|
|
169
|
+
fix(node) {
|
|
134
170
|
const literal = node;
|
|
135
|
-
if (typeof literal.value !== "string") return;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
} });
|
|
171
|
+
if (typeof literal.value !== "string") return null;
|
|
172
|
+
const raw = literal.raw;
|
|
173
|
+
if (typeof raw !== "string") return null;
|
|
174
|
+
if (!raw.includes(EM_DASH)) return null;
|
|
175
|
+
return raw.split(EM_DASH).join("-");
|
|
176
|
+
}
|
|
177
|
+
});
|
|
143
178
|
//#endregion
|
|
144
179
|
//#region src/shared/vue-auto-imported-symbols.ts
|
|
145
180
|
const VUE_AUTO_IMPORTED = new Set([
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["MESSAGE","calleeName","MESSAGE","MESSAGE","calleeName","isToRefsCall","MESSAGE","calleeName","MESSAGE","calleeName","MESSAGE","calleeName","MESSAGE","MESSAGE"],"sources":["../src/define-rule.ts","../src/rules/composition/defineProps-typed.ts","../src/rules/composition/prefer-script-setup-for-new-files.ts","../src/rules/ai-slop/no-destructure-props-without-toRefs.ts","../src/rules/ai-slop/no-destructure-reactive-without-toRefs.ts","../src/rules/ai-slop/no-em-dash-in-string.ts","../src/shared/vue-auto-imported-symbols.ts","../src/rules/ai-slop/no-imports-from-vue-when-auto-imported.ts","../src/rules/ai-slop/no-non-null-assertion-on-ref-value.ts","../src/rules/reactivity/prefer-readonly-for-injected.ts","../src/rules/reactivity/prefer-shallowRef-for-large-data.ts","../src/rules/reactivity/watch-without-cleanup.ts","../src/rules/performance/prefer-defineAsyncComponent-on-route.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":["import type { Rule } from './rule-types.js';\n\nexport function defineRule(rule: Rule): Rule {\n return rule;\n}\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/typescript/composition-api.html#typing-component-props';\nconst MESSAGE = `This defineProps() call declares props with a runtime object, which discards static type information. Use the type-only generic form (defineProps<{ ... }>()) so props are fully typed. See ${DOCS_URL}`;\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nexport const definePropsTyped = defineRule({\n create(context: RuleContext) {\n return {\n CallExpression(node: AstNode) {\n if (calleeName(node) !== 'defineProps') return;\n const firstArg = (node.arguments as AstNode[])[0];\n if (firstArg?.type === 'ObjectExpression') {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL = 'https://vuejs.org/api/sfc-script-setup.html';\nconst MESSAGE = `This component nests composition-API logic inside an options-object setup(). Use a <script setup> block instead — it removes the setup() boilerplate and exposes bindings to the template directly. See ${DOCS_URL}`;\n\nfunction isFunctionValue(node: AstNode | undefined): boolean {\n return (\n node?.type === 'ArrowFunctionExpression' ||\n node?.type === 'FunctionExpression'\n );\n}\n\nfunction isSetupProperty(prop: AstNode): boolean {\n if (prop.type !== 'Property' || prop.computed === true) return false;\n if (prop.shorthand === true) return false;\n const key = prop.key as AstNode;\n if (key.type !== 'Identifier' || key.name !== 'setup') return false;\n return isFunctionValue(prop.value as AstNode | undefined);\n}\n\nexport const preferScriptSetupForNewFiles = defineRule({\n create(context: RuleContext) {\n return {\n ExportDefaultDeclaration(node: AstNode) {\n const declaration = node.declaration as AstNode | undefined;\n if (declaration?.type !== 'ObjectExpression') return;\n const properties = declaration.properties as AstNode[];\n if (properties.some(isSetupProperty)) {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/components/props.html#reactive-props-destructure';\nconst MESSAGE = `Destructuring props loses reactivity. Wrap with toRefs(...) to keep refs. See ${DOCS_URL}`;\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction isDefinePropsCall(node: AstNode | undefined): boolean {\n if (!node || node.type !== 'CallExpression') return false;\n const name = calleeName(node);\n if (name === 'defineProps') return true;\n if (name === 'withDefaults') {\n const args = node.arguments as AstNode[] | undefined;\n return isDefinePropsCall(args?.[0]);\n }\n return false;\n}\n\nfunction isToRefsCall(node: AstNode | undefined): boolean {\n return node?.type === 'CallExpression' && calleeName(node) === 'toRefs';\n}\n\nexport const noDestructurePropsWithoutToRefs = defineRule({\n create(context: RuleContext) {\n const propsSources = new Set<string>();\n\n function registerSetupParam(fn: AstNode | undefined): void {\n const params = fn?.params as AstNode[] | undefined;\n const first = params?.[0];\n if (first?.type === 'Identifier') propsSources.add(first.name as string);\n }\n\n return {\n VariableDeclarator(node: AstNode) {\n const id = node.id as AstNode;\n const init = node.init as AstNode | undefined;\n if (id.type === 'Identifier' && isDefinePropsCall(init)) {\n propsSources.add(id.name as string);\n return;\n }\n if (id.type !== 'ObjectPattern' || !init) return;\n if (isToRefsCall(init)) return;\n const fromProps =\n isDefinePropsCall(init) ||\n (init.type === 'Identifier' && propsSources.has(init.name as string));\n if (fromProps) context.report({ node, message: MESSAGE });\n },\n Property(node: AstNode) {\n const key = node.key as AstNode | undefined;\n if (key?.type === 'Identifier' && key.name === 'setup') {\n registerSetupParam(node.value as AstNode);\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/essentials/reactivity-fundamentals.html#destructuring-reactive-state';\nconst MESSAGE = `Destructuring reactive state loses reactivity. Wrap with toRefs(...) or read single keys via toRef(state, 'key'). See ${DOCS_URL}`;\n\nconst REACTIVE_FACTORIES = new Set(['reactive', 'shallowReactive']);\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction isReactiveCall(node: AstNode | undefined): boolean {\n if (!node || node.type !== 'CallExpression') return false;\n const name = calleeName(node);\n if (name && REACTIVE_FACTORIES.has(name)) return true;\n if (name === 'readonly') {\n const args = node.arguments as AstNode[] | undefined;\n return isReactiveCall(args?.[0]);\n }\n return false;\n}\n\nfunction isToRefsCall(node: AstNode | undefined): boolean {\n return node?.type === 'CallExpression' && calleeName(node) === 'toRefs';\n}\n\nexport const noDestructureReactiveWithoutToRefs = defineRule({\n create(context: RuleContext) {\n const reactiveSources = new Set<string>();\n return {\n VariableDeclarator(node: AstNode) {\n const id = node.id as AstNode;\n const init = node.init as AstNode | undefined;\n if (id.type === 'Identifier' && isReactiveCall(init)) {\n reactiveSources.add(id.name as string);\n return;\n }\n if (id.type !== 'ObjectPattern' || !init) return;\n if (isToRefsCall(init)) return;\n const fromReactive =\n isReactiveCall(init) ||\n (init.type === 'Identifier' &&\n reactiveSources.has(init.name as string));\n if (fromReactive) context.report({ node, message: MESSAGE });\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst EM_DASH = '\\u2014';\n\ninterface LiteralNode extends AstNode {\n type: 'Literal';\n value: unknown;\n}\n\nexport const noEmDashInString = defineRule({\n create(context: RuleContext) {\n return {\n Literal(node: AstNode) {\n const literal = node as LiteralNode;\n if (typeof literal.value !== 'string') return;\n if (!literal.value.includes(EM_DASH)) return;\n context.report({\n node,\n message:\n 'Em dash in string literal reads as AI-generated output; use comma, colon, or parentheses.',\n });\n },\n };\n },\n});\n","export const VUE_AUTO_IMPORTED: ReadonlySet<string> = new Set([\n 'ref',\n 'shallowRef',\n 'computed',\n 'reactive',\n 'shallowReactive',\n 'readonly',\n 'shallowReadonly',\n 'toRef',\n 'toRefs',\n 'isRef',\n 'isReactive',\n 'isReadonly',\n 'isProxy',\n 'unref',\n 'triggerRef',\n 'customRef',\n 'markRaw',\n 'toRaw',\n 'watch',\n 'watchEffect',\n 'watchPostEffect',\n 'watchSyncEffect',\n 'effectScope',\n 'getCurrentScope',\n 'onScopeDispose',\n 'onMounted',\n 'onUpdated',\n 'onUnmounted',\n 'onBeforeMount',\n 'onBeforeUpdate',\n 'onBeforeUnmount',\n 'onErrorCaptured',\n 'onRenderTracked',\n 'onRenderTriggered',\n 'onActivated',\n 'onDeactivated',\n 'onServerPrefetch',\n 'provide',\n 'inject',\n 'hasInjectionContext',\n 'getCurrentInstance',\n 'nextTick',\n 'defineComponent',\n 'defineAsyncComponent',\n 'useTemplateRef',\n 'useId',\n 'useModel',\n]);\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\nimport { VUE_AUTO_IMPORTED } from '../../shared/vue-auto-imported-symbols.js';\n\nconst DOCS_URL = 'https://nuxt.com/docs/4.x/guide/concepts/auto-imports';\nconst WHOLE_MESSAGE = `The entire import from 'vue' can be removed — these names are auto-imported in this project. See ${DOCS_URL}`;\nconst SPECIFIER_MESSAGE = `This symbol is auto-imported in your project. Remove it from the 'vue' import — it is dead weight in the diff. See ${DOCS_URL}`;\n\nfunction isAutoImportedValueSpecifier(spec: AstNode): boolean {\n if (spec.importKind === 'type') return false;\n const imported = spec.imported as AstNode;\n return VUE_AUTO_IMPORTED.has(imported.name as string);\n}\n\nexport const noImportsFromVueWhenAutoImported = defineRule({\n create(context: RuleContext) {\n let gated = false;\n return {\n Program() {\n gated = context.capabilities?.has('auto-imports:vue') !== true;\n },\n ImportDeclaration(node: AstNode) {\n if (gated) return;\n if (node.importKind === 'type') return;\n const source = node.source as AstNode;\n if (source.value !== 'vue') return;\n const specifiers = node.specifiers as AstNode[];\n const named = specifiers.filter((s) => s.type === 'ImportSpecifier');\n if (named.length === 0) return;\n const offending = named.filter(isAutoImportedValueSpecifier);\n if (offending.length === 0) return;\n if (\n offending.length === named.length &&\n specifiers.length === named.length\n ) {\n context.report({ node, message: WHOLE_MESSAGE });\n return;\n }\n for (const spec of offending) {\n context.report({ node: spec, message: SPECIFIER_MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/typescript/composition-api.html#typing-ref';\nconst MESSAGE = `Non-null assertion on a ref's .value hides nullability. Add an explicit guard ('if (!r.value) return') or use optional chaining ('r.value?.x'). See ${DOCS_URL}`;\n\nconst REF_FACTORIES = new Set([\n 'ref',\n 'shallowRef',\n 'customRef',\n 'computed',\n 'useTemplateRef',\n]);\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction isRefFactoryCall(node: AstNode | undefined): boolean {\n if (!node || node.type !== 'CallExpression') return false;\n const name = calleeName(node);\n return name !== undefined && REF_FACTORIES.has(name);\n}\n\nfunction isDotValue(node: AstNode | undefined): node is AstNode {\n if (!node || node.type !== 'MemberExpression') return false;\n const property = node.property as AstNode | undefined;\n return (\n node.computed !== true &&\n property?.type === 'Identifier' &&\n property.name === 'value'\n );\n}\n\nexport const noNonNullAssertionOnRefValue = defineRule({\n create(context: RuleContext) {\n const refSources = new Set<string>();\n return {\n VariableDeclarator(node: AstNode) {\n const id = node.id as AstNode;\n if (\n id.type === 'Identifier' &&\n isRefFactoryCall(node.init as AstNode)\n ) {\n refSources.add(id.name as string);\n }\n },\n TSNonNullExpression(node: AstNode) {\n const arg = node.expression as AstNode | undefined;\n if (!isDotValue(arg)) return;\n const object = arg.object as AstNode | undefined;\n if (object?.type !== 'Identifier') return;\n if (!refSources.has(object.name as string)) return;\n context.report({ node, message: MESSAGE });\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/components/provide-inject.html#working-with-reactivity';\nconst MESSAGE = `Mutating an injected value from a consumer breaks one-way data flow and makes the source of changes hard to trace. Wrap the provided value in readonly() at the provide site and expose a dedicated mutator instead. See ${DOCS_URL}`;\n\nconst MUTATING_METHODS = new Set([\n 'push',\n 'pop',\n 'splice',\n 'shift',\n 'unshift',\n 'sort',\n 'reverse',\n]);\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction memberObjectName(node: AstNode | undefined): string | undefined {\n if (!node || node.type !== 'MemberExpression') return undefined;\n const object = node.object as AstNode;\n if (object.type !== 'Identifier') return undefined;\n return object.name as string;\n}\n\nexport const preferReadonlyForInjected = defineRule({\n create(context: RuleContext) {\n const injectedSources = new Set<string>();\n return {\n VariableDeclarator(node: AstNode) {\n const id = node.id as AstNode;\n const init = node.init as AstNode | undefined;\n if (\n id.type === 'Identifier' &&\n init?.type === 'CallExpression' &&\n calleeName(init) === 'inject'\n ) {\n injectedSources.add(id.name as string);\n }\n },\n AssignmentExpression(node: AstNode) {\n const name = memberObjectName(node.left as AstNode);\n if (name !== undefined && injectedSources.has(name)) {\n context.report({ node, message: MESSAGE });\n }\n },\n CallExpression(node: AstNode) {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type !== 'MemberExpression' || callee.computed === true) {\n return;\n }\n const name = memberObjectName(callee);\n if (name === undefined || !injectedSources.has(name)) return;\n const property = callee.property as AstNode;\n if (MUTATING_METHODS.has(property.name as string)) {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL = 'https://vuejs.org/api/reactivity-advanced.html#shallowref';\nconst MESSAGE = `This ref holds large or fetched data, so deep reactivity tracks every nested property and wastes memory and CPU. Use shallowRef() (and triggerRef on replacement) for large arrays, big objects, or server payloads. See ${DOCS_URL}`;\n\nconst ARRAY_LIMIT = 100;\nconst OBJECT_LIMIT = 50;\nconst FETCH_IDENTIFIERS = new Set(['$fetch', 'useFetch']);\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction isAxiosGet(node: AstNode): boolean {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type !== 'MemberExpression' || callee.computed === true) {\n return false;\n }\n const object = callee.object as AstNode;\n const property = callee.property as AstNode;\n return (\n object.type === 'Identifier' &&\n object.name === 'axios' &&\n property.name === 'get'\n );\n}\n\nfunction isFetchSource(node: AstNode): boolean {\n if (node.type !== 'CallExpression') return false;\n const name = calleeName(node);\n if (name !== undefined && FETCH_IDENTIFIERS.has(name)) return true;\n return isAxiosGet(node);\n}\n\nfunction isLargeData(node: AstNode | undefined): boolean {\n if (!node) return false;\n const value =\n node.type === 'AwaitExpression' ? (node.argument as AstNode) : node;\n if (value.type === 'ArrayExpression') {\n return (value.elements as AstNode[]).length > ARRAY_LIMIT;\n }\n if (value.type === 'ObjectExpression') {\n return (value.properties as AstNode[]).length > OBJECT_LIMIT;\n }\n return isFetchSource(value);\n}\n\nexport const preferShallowRefForLargeData = defineRule({\n create(context: RuleContext) {\n return {\n CallExpression(node: AstNode) {\n if (calleeName(node) !== 'ref') return;\n const init = (node.arguments as AstNode[])[0];\n if (isLargeData(init)) context.report({ node, message: MESSAGE });\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/essentials/watchers.html#side-effect-cleanup';\nconst MESSAGE = `This watcher registers a listener, timer, or observer but never cleans it up, so it leaks across re-runs and hot reloads. Return a cleanup function (or call onWatcherCleanup) inside the watcher. See ${DOCS_URL}`;\n\nconst REGISTER_CALLS = new Set([\n 'addEventListener',\n 'setInterval',\n 'setTimeout',\n]);\nconst OBSERVERS = new Set([\n 'IntersectionObserver',\n 'MutationObserver',\n 'ResizeObserver',\n]);\nconst CLEANUP_CALLS = new Set(['onCleanup', 'onWatcherCleanup']);\n\ninterface WatchFrame {\n sourceCall: AstNode;\n isEffect: boolean;\n hasRegistration: boolean;\n hasCleanup: boolean;\n}\n\nfunction calleeIdentifierName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction calledMethodName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n if (callee?.type === 'MemberExpression' && callee.computed !== true) {\n const property = callee.property as AstNode;\n return property.name as string;\n }\n return undefined;\n}\n\nfunction isFunction(node: AstNode | undefined): boolean {\n return (\n node?.type === 'ArrowFunctionExpression' ||\n node?.type === 'FunctionExpression'\n );\n}\n\nexport const watchWithoutCleanup = defineRule({\n create(context: RuleContext) {\n const watchStack: WatchFrame[] = [];\n\n return {\n CallExpression(node: AstNode) {\n const name = calleeIdentifierName(node);\n if (name === 'watch' || name === 'watchEffect') {\n const isEffect = name === 'watchEffect';\n const args = node.arguments as AstNode[];\n const callback = args[isEffect ? 0 : 1];\n if (!isFunction(callback)) return;\n watchStack.push({\n sourceCall: node,\n isEffect,\n hasRegistration: false,\n hasCleanup: false,\n });\n return;\n }\n if (watchStack.length === 0) return;\n const top = watchStack[watchStack.length - 1]!;\n const method = calledMethodName(node);\n if (method !== undefined && REGISTER_CALLS.has(method)) {\n top.hasRegistration = true;\n }\n if (method !== undefined && CLEANUP_CALLS.has(method) && top.isEffect) {\n top.hasCleanup = true;\n }\n },\n NewExpression(node: AstNode) {\n if (watchStack.length === 0) return;\n const callee = node.callee as AstNode | undefined;\n if (\n callee?.type === 'Identifier' &&\n OBSERVERS.has(callee.name as string)\n ) {\n watchStack[watchStack.length - 1]!.hasRegistration = true;\n }\n },\n ReturnStatement(node: AstNode) {\n if (watchStack.length === 0) return;\n if (isFunction(node.argument as AstNode | undefined)) {\n watchStack[watchStack.length - 1]!.hasCleanup = true;\n }\n },\n 'CallExpression:exit'(node: AstNode) {\n if (watchStack.length === 0) return;\n const top = watchStack[watchStack.length - 1]!;\n if (top.sourceCall !== node) return;\n watchStack.pop();\n if (top.hasRegistration && !top.hasCleanup) {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL = 'https://vuejs.org/guide/components/async.html';\nconst MESSAGE = `This route record's \\`component:\\` field references the imported component directly, which forces a synchronous import of the route bundle. Use \\`() => import('./Foo.vue')\\` or \\`defineAsyncComponent(() => import('./Foo.vue'))\\` to lazy-load the route. See ${DOCS_URL}`;\n\nfunction keyName(key: AstNode): unknown {\n return key.type === 'Identifier' ? key.name : key.value;\n}\n\nexport const preferDefineAsyncComponentOnRoute = defineRule({\n create(context: RuleContext) {\n return {\n Property(node: AstNode) {\n if (node.computed === true || node.shorthand === true) return;\n if (keyName(node.key as AstNode) !== 'component') return;\n const value = node.value as AstNode;\n if (value.type === 'Identifier') {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import type { Plugin } from './rule-types.js';\nimport { definePropsTyped } from './rules/composition/defineProps-typed.js';\nimport { preferScriptSetupForNewFiles } from './rules/composition/prefer-script-setup-for-new-files.js';\nimport { noDestructurePropsWithoutToRefs } from './rules/ai-slop/no-destructure-props-without-toRefs.js';\nimport { noDestructureReactiveWithoutToRefs } from './rules/ai-slop/no-destructure-reactive-without-toRefs.js';\nimport { noEmDashInString } from './rules/ai-slop/no-em-dash-in-string.js';\nimport { noImportsFromVueWhenAutoImported } from './rules/ai-slop/no-imports-from-vue-when-auto-imported.js';\nimport { noNonNullAssertionOnRefValue } from './rules/ai-slop/no-non-null-assertion-on-ref-value.js';\nimport { preferReadonlyForInjected } from './rules/reactivity/prefer-readonly-for-injected.js';\nimport { preferShallowRefForLargeData } from './rules/reactivity/prefer-shallowRef-for-large-data.js';\nimport { watchWithoutCleanup } from './rules/reactivity/watch-without-cleanup.js';\nimport { preferDefineAsyncComponentOnRoute } from './rules/performance/prefer-defineAsyncComponent-on-route.js';\n\nexport const plugin: Plugin = {\n meta: { name: 'vue-doctor' },\n rules: {\n 'no-em-dash-in-string': noEmDashInString,\n 'no-destructure-props-without-to-refs': noDestructurePropsWithoutToRefs,\n 'no-destructure-reactive-without-to-refs':\n noDestructureReactiveWithoutToRefs,\n 'no-non-null-assertion-on-ref-value': noNonNullAssertionOnRefValue,\n 'no-imports-from-vue-when-auto-imported': noImportsFromVueWhenAutoImported,\n 'reactivity/watch-without-cleanup': watchWithoutCleanup,\n 'reactivity/prefer-shallowRef-for-large-data': preferShallowRefForLargeData,\n 'reactivity/prefer-readonly-for-injected': preferReadonlyForInjected,\n 'composition/prefer-script-setup-for-new-files':\n preferScriptSetupForNewFiles,\n 'composition/defineProps-typed': definePropsTyped,\n 'performance/prefer-defineAsyncComponent-on-route':\n preferDefineAsyncComponentOnRoute,\n },\n};\n","import { plugin } from './plugin.js';\n\nexport default plugin;\nexport { plugin };\nexport { VUE_AUTO_IMPORTED } from './shared/vue-auto-imported-symbols.js';\nexport type { Rule, RuleContext } from './rule-types.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["MESSAGE","calleeName","MESSAGE","MESSAGE","calleeName","isToRefsCall","MESSAGE","calleeName","MESSAGE","calleeName","MESSAGE","calleeName","MESSAGE","MESSAGE"],"sources":["../src/define-rule.ts","../src/rules/composition/defineProps-typed.ts","../src/rules/composition/prefer-script-setup-for-new-files.ts","../src/rules/ai-slop/no-destructure-props-without-toRefs.ts","../src/rules/ai-slop/no-destructure-reactive-without-toRefs.ts","../src/rules/ai-slop/no-em-dash-in-string.ts","../src/shared/vue-auto-imported-symbols.ts","../src/rules/ai-slop/no-imports-from-vue-when-auto-imported.ts","../src/rules/ai-slop/no-non-null-assertion-on-ref-value.ts","../src/rules/reactivity/prefer-readonly-for-injected.ts","../src/rules/reactivity/prefer-shallowRef-for-large-data.ts","../src/rules/reactivity/watch-without-cleanup.ts","../src/rules/performance/prefer-defineAsyncComponent-on-route.ts","../src/plugin.ts","../src/index.ts"],"sourcesContent":["import type { Rule, RuleContext } from './rule-types.js';\n\nexport function defineRule(rule: Rule): Rule {\n const userFix = rule.fix;\n if (!userFix) return rule;\n return {\n ...rule,\n meta: { ...rule.meta, fixable: 'code' },\n create(context: RuleContext) {\n const wrapped: RuleContext = {\n ...context,\n report(descriptor) {\n const replacement = userFix(descriptor.node);\n if (replacement === null) {\n context.report(descriptor);\n return;\n }\n context.report({\n ...descriptor,\n fix: (fixer) => fixer.replaceText(descriptor.node, replacement),\n });\n },\n };\n return rule.create(wrapped);\n },\n };\n}\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/typescript/composition-api.html#typing-component-props';\nconst MESSAGE = `This defineProps() call declares props with a runtime object, which discards static type information. Use the type-only generic form (defineProps<{ ... }>()) so props are fully typed. See ${DOCS_URL}`;\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nexport const definePropsTyped = defineRule({\n create(context: RuleContext) {\n return {\n CallExpression(node: AstNode) {\n if (calleeName(node) !== 'defineProps') return;\n const firstArg = (node.arguments as AstNode[])[0];\n if (firstArg?.type === 'ObjectExpression') {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL = 'https://vuejs.org/api/sfc-script-setup.html';\nconst MESSAGE = `This component nests composition-API logic inside an options-object setup(). Use a <script setup> block instead — it removes the setup() boilerplate and exposes bindings to the template directly. See ${DOCS_URL}`;\n\nfunction isFunctionValue(node: AstNode | undefined): boolean {\n return (\n node?.type === 'ArrowFunctionExpression' ||\n node?.type === 'FunctionExpression'\n );\n}\n\nfunction isSetupProperty(prop: AstNode): boolean {\n if (prop.type !== 'Property' || prop.computed === true) return false;\n if (prop.shorthand === true) return false;\n const key = prop.key as AstNode;\n if (key.type !== 'Identifier' || key.name !== 'setup') return false;\n return isFunctionValue(prop.value as AstNode | undefined);\n}\n\nexport const preferScriptSetupForNewFiles = defineRule({\n create(context: RuleContext) {\n return {\n ExportDefaultDeclaration(node: AstNode) {\n const declaration = node.declaration as AstNode | undefined;\n if (declaration?.type !== 'ObjectExpression') return;\n const properties = declaration.properties as AstNode[];\n if (properties.some(isSetupProperty)) {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/components/props.html#reactive-props-destructure';\nconst MESSAGE = `Destructuring props loses reactivity. Wrap with toRefs(...) to keep refs. See ${DOCS_URL}`;\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction isDefinePropsCall(node: AstNode | undefined): boolean {\n if (!node || node.type !== 'CallExpression') return false;\n const name = calleeName(node);\n if (name === 'defineProps') return true;\n if (name === 'withDefaults') {\n const args = node.arguments as AstNode[] | undefined;\n return isDefinePropsCall(args?.[0]);\n }\n return false;\n}\n\nfunction isToRefsCall(node: AstNode | undefined): boolean {\n return node?.type === 'CallExpression' && calleeName(node) === 'toRefs';\n}\n\nexport const noDestructurePropsWithoutToRefs = defineRule({\n create(context: RuleContext) {\n const propsSources = new Set<string>();\n\n function registerSetupParam(fn: AstNode | undefined): void {\n const params = fn?.params as AstNode[] | undefined;\n const first = params?.[0];\n if (first?.type === 'Identifier') propsSources.add(first.name as string);\n }\n\n return {\n VariableDeclarator(node: AstNode) {\n const id = node.id as AstNode;\n const init = node.init as AstNode | undefined;\n if (id.type === 'Identifier' && isDefinePropsCall(init)) {\n propsSources.add(id.name as string);\n return;\n }\n if (id.type !== 'ObjectPattern' || !init) return;\n if (isToRefsCall(init)) return;\n const fromProps =\n isDefinePropsCall(init) ||\n (init.type === 'Identifier' && propsSources.has(init.name as string));\n if (fromProps) context.report({ node, message: MESSAGE });\n },\n Property(node: AstNode) {\n const key = node.key as AstNode | undefined;\n if (key?.type === 'Identifier' && key.name === 'setup') {\n registerSetupParam(node.value as AstNode);\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/essentials/reactivity-fundamentals.html#destructuring-reactive-state';\nconst MESSAGE = `Destructuring reactive state loses reactivity. Wrap with toRefs(...) or read single keys via toRef(state, 'key'). See ${DOCS_URL}`;\n\nconst REACTIVE_FACTORIES = new Set(['reactive', 'shallowReactive']);\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction isReactiveCall(node: AstNode | undefined): boolean {\n if (!node || node.type !== 'CallExpression') return false;\n const name = calleeName(node);\n if (name && REACTIVE_FACTORIES.has(name)) return true;\n if (name === 'readonly') {\n const args = node.arguments as AstNode[] | undefined;\n return isReactiveCall(args?.[0]);\n }\n return false;\n}\n\nfunction isToRefsCall(node: AstNode | undefined): boolean {\n return node?.type === 'CallExpression' && calleeName(node) === 'toRefs';\n}\n\nexport const noDestructureReactiveWithoutToRefs = defineRule({\n create(context: RuleContext) {\n const reactiveSources = new Set<string>();\n return {\n VariableDeclarator(node: AstNode) {\n const id = node.id as AstNode;\n const init = node.init as AstNode | undefined;\n if (id.type === 'Identifier' && isReactiveCall(init)) {\n reactiveSources.add(id.name as string);\n return;\n }\n if (id.type !== 'ObjectPattern' || !init) return;\n if (isToRefsCall(init)) return;\n const fromReactive =\n isReactiveCall(init) ||\n (init.type === 'Identifier' &&\n reactiveSources.has(init.name as string));\n if (fromReactive) context.report({ node, message: MESSAGE });\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst EM_DASH = '\\u2014';\n\ninterface LiteralNode extends AstNode {\n type: 'Literal';\n value: unknown;\n}\n\nexport const noEmDashInString = defineRule({\n create(context: RuleContext) {\n return {\n Literal(node: AstNode) {\n const literal = node as LiteralNode;\n if (typeof literal.value !== 'string') return;\n if (!literal.value.includes(EM_DASH)) return;\n context.report({\n node,\n message:\n 'Em dash in string literal reads as AI-generated output; use comma, colon, or parentheses.',\n });\n },\n };\n },\n fix(node: AstNode) {\n const literal = node as LiteralNode;\n if (typeof literal.value !== 'string') return null;\n const raw = literal.raw;\n if (typeof raw !== 'string') return null;\n if (!raw.includes(EM_DASH)) return null;\n return raw.split(EM_DASH).join('-');\n },\n});\n","export const VUE_AUTO_IMPORTED: ReadonlySet<string> = new Set([\n 'ref',\n 'shallowRef',\n 'computed',\n 'reactive',\n 'shallowReactive',\n 'readonly',\n 'shallowReadonly',\n 'toRef',\n 'toRefs',\n 'isRef',\n 'isReactive',\n 'isReadonly',\n 'isProxy',\n 'unref',\n 'triggerRef',\n 'customRef',\n 'markRaw',\n 'toRaw',\n 'watch',\n 'watchEffect',\n 'watchPostEffect',\n 'watchSyncEffect',\n 'effectScope',\n 'getCurrentScope',\n 'onScopeDispose',\n 'onMounted',\n 'onUpdated',\n 'onUnmounted',\n 'onBeforeMount',\n 'onBeforeUpdate',\n 'onBeforeUnmount',\n 'onErrorCaptured',\n 'onRenderTracked',\n 'onRenderTriggered',\n 'onActivated',\n 'onDeactivated',\n 'onServerPrefetch',\n 'provide',\n 'inject',\n 'hasInjectionContext',\n 'getCurrentInstance',\n 'nextTick',\n 'defineComponent',\n 'defineAsyncComponent',\n 'useTemplateRef',\n 'useId',\n 'useModel',\n]);\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\nimport { VUE_AUTO_IMPORTED } from '../../shared/vue-auto-imported-symbols.js';\n\nconst DOCS_URL = 'https://nuxt.com/docs/4.x/guide/concepts/auto-imports';\nconst WHOLE_MESSAGE = `The entire import from 'vue' can be removed — these names are auto-imported in this project. See ${DOCS_URL}`;\nconst SPECIFIER_MESSAGE = `This symbol is auto-imported in your project. Remove it from the 'vue' import — it is dead weight in the diff. See ${DOCS_URL}`;\n\nfunction isAutoImportedValueSpecifier(spec: AstNode): boolean {\n if (spec.importKind === 'type') return false;\n const imported = spec.imported as AstNode;\n return VUE_AUTO_IMPORTED.has(imported.name as string);\n}\n\nexport const noImportsFromVueWhenAutoImported = defineRule({\n create(context: RuleContext) {\n let gated = false;\n return {\n Program() {\n gated = context.capabilities?.has('auto-imports:vue') !== true;\n },\n ImportDeclaration(node: AstNode) {\n if (gated) return;\n if (node.importKind === 'type') return;\n const source = node.source as AstNode;\n if (source.value !== 'vue') return;\n const specifiers = node.specifiers as AstNode[];\n const named = specifiers.filter((s) => s.type === 'ImportSpecifier');\n if (named.length === 0) return;\n const offending = named.filter(isAutoImportedValueSpecifier);\n if (offending.length === 0) return;\n if (\n offending.length === named.length &&\n specifiers.length === named.length\n ) {\n context.report({ node, message: WHOLE_MESSAGE });\n return;\n }\n for (const spec of offending) {\n context.report({ node: spec, message: SPECIFIER_MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/typescript/composition-api.html#typing-ref';\nconst MESSAGE = `Non-null assertion on a ref's .value hides nullability. Add an explicit guard ('if (!r.value) return') or use optional chaining ('r.value?.x'). See ${DOCS_URL}`;\n\nconst REF_FACTORIES = new Set([\n 'ref',\n 'shallowRef',\n 'customRef',\n 'computed',\n 'useTemplateRef',\n]);\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction isRefFactoryCall(node: AstNode | undefined): boolean {\n if (!node || node.type !== 'CallExpression') return false;\n const name = calleeName(node);\n return name !== undefined && REF_FACTORIES.has(name);\n}\n\nfunction isDotValue(node: AstNode | undefined): node is AstNode {\n if (!node || node.type !== 'MemberExpression') return false;\n const property = node.property as AstNode | undefined;\n return (\n node.computed !== true &&\n property?.type === 'Identifier' &&\n property.name === 'value'\n );\n}\n\nexport const noNonNullAssertionOnRefValue = defineRule({\n create(context: RuleContext) {\n const refSources = new Set<string>();\n return {\n VariableDeclarator(node: AstNode) {\n const id = node.id as AstNode;\n if (\n id.type === 'Identifier' &&\n isRefFactoryCall(node.init as AstNode)\n ) {\n refSources.add(id.name as string);\n }\n },\n TSNonNullExpression(node: AstNode) {\n const arg = node.expression as AstNode | undefined;\n if (!isDotValue(arg)) return;\n const object = arg.object as AstNode | undefined;\n if (object?.type !== 'Identifier') return;\n if (!refSources.has(object.name as string)) return;\n context.report({ node, message: MESSAGE });\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/components/provide-inject.html#working-with-reactivity';\nconst MESSAGE = `Mutating an injected value from a consumer breaks one-way data flow and makes the source of changes hard to trace. Wrap the provided value in readonly() at the provide site and expose a dedicated mutator instead. See ${DOCS_URL}`;\n\nconst MUTATING_METHODS = new Set([\n 'push',\n 'pop',\n 'splice',\n 'shift',\n 'unshift',\n 'sort',\n 'reverse',\n]);\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction memberObjectName(node: AstNode | undefined): string | undefined {\n if (!node || node.type !== 'MemberExpression') return undefined;\n const object = node.object as AstNode;\n if (object.type !== 'Identifier') return undefined;\n return object.name as string;\n}\n\nexport const preferReadonlyForInjected = defineRule({\n create(context: RuleContext) {\n const injectedSources = new Set<string>();\n return {\n VariableDeclarator(node: AstNode) {\n const id = node.id as AstNode;\n const init = node.init as AstNode | undefined;\n if (\n id.type === 'Identifier' &&\n init?.type === 'CallExpression' &&\n calleeName(init) === 'inject'\n ) {\n injectedSources.add(id.name as string);\n }\n },\n AssignmentExpression(node: AstNode) {\n const name = memberObjectName(node.left as AstNode);\n if (name !== undefined && injectedSources.has(name)) {\n context.report({ node, message: MESSAGE });\n }\n },\n CallExpression(node: AstNode) {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type !== 'MemberExpression' || callee.computed === true) {\n return;\n }\n const name = memberObjectName(callee);\n if (name === undefined || !injectedSources.has(name)) return;\n const property = callee.property as AstNode;\n if (MUTATING_METHODS.has(property.name as string)) {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL = 'https://vuejs.org/api/reactivity-advanced.html#shallowref';\nconst MESSAGE = `This ref holds large or fetched data, so deep reactivity tracks every nested property and wastes memory and CPU. Use shallowRef() (and triggerRef on replacement) for large arrays, big objects, or server payloads. See ${DOCS_URL}`;\n\nconst ARRAY_LIMIT = 100;\nconst OBJECT_LIMIT = 50;\nconst FETCH_IDENTIFIERS = new Set(['$fetch', 'useFetch']);\n\nfunction calleeName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction isAxiosGet(node: AstNode): boolean {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type !== 'MemberExpression' || callee.computed === true) {\n return false;\n }\n const object = callee.object as AstNode;\n const property = callee.property as AstNode;\n return (\n object.type === 'Identifier' &&\n object.name === 'axios' &&\n property.name === 'get'\n );\n}\n\nfunction isFetchSource(node: AstNode): boolean {\n if (node.type !== 'CallExpression') return false;\n const name = calleeName(node);\n if (name !== undefined && FETCH_IDENTIFIERS.has(name)) return true;\n return isAxiosGet(node);\n}\n\nfunction isLargeData(node: AstNode | undefined): boolean {\n if (!node) return false;\n const value =\n node.type === 'AwaitExpression' ? (node.argument as AstNode) : node;\n if (value.type === 'ArrayExpression') {\n return (value.elements as AstNode[]).length > ARRAY_LIMIT;\n }\n if (value.type === 'ObjectExpression') {\n return (value.properties as AstNode[]).length > OBJECT_LIMIT;\n }\n return isFetchSource(value);\n}\n\nexport const preferShallowRefForLargeData = defineRule({\n create(context: RuleContext) {\n return {\n CallExpression(node: AstNode) {\n if (calleeName(node) !== 'ref') return;\n const init = (node.arguments as AstNode[])[0];\n if (isLargeData(init)) context.report({ node, message: MESSAGE });\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL =\n 'https://vuejs.org/guide/essentials/watchers.html#side-effect-cleanup';\nconst MESSAGE = `This watcher registers a listener, timer, or observer but never cleans it up, so it leaks across re-runs and hot reloads. Return a cleanup function (or call onWatcherCleanup) inside the watcher. See ${DOCS_URL}`;\n\nconst REGISTER_CALLS = new Set([\n 'addEventListener',\n 'setInterval',\n 'setTimeout',\n]);\nconst OBSERVERS = new Set([\n 'IntersectionObserver',\n 'MutationObserver',\n 'ResizeObserver',\n]);\nconst CLEANUP_CALLS = new Set(['onCleanup', 'onWatcherCleanup']);\n\ninterface WatchFrame {\n sourceCall: AstNode;\n isEffect: boolean;\n hasRegistration: boolean;\n hasCleanup: boolean;\n}\n\nfunction calleeIdentifierName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n return undefined;\n}\n\nfunction calledMethodName(node: AstNode): string | undefined {\n const callee = node.callee as AstNode | undefined;\n if (callee?.type === 'Identifier') return callee.name as string;\n if (callee?.type === 'MemberExpression' && callee.computed !== true) {\n const property = callee.property as AstNode;\n return property.name as string;\n }\n return undefined;\n}\n\nfunction isFunction(node: AstNode | undefined): boolean {\n return (\n node?.type === 'ArrowFunctionExpression' ||\n node?.type === 'FunctionExpression'\n );\n}\n\nexport const watchWithoutCleanup = defineRule({\n create(context: RuleContext) {\n const watchStack: WatchFrame[] = [];\n\n return {\n CallExpression(node: AstNode) {\n const name = calleeIdentifierName(node);\n if (name === 'watch' || name === 'watchEffect') {\n const isEffect = name === 'watchEffect';\n const args = node.arguments as AstNode[];\n const callback = args[isEffect ? 0 : 1];\n if (!isFunction(callback)) return;\n watchStack.push({\n sourceCall: node,\n isEffect,\n hasRegistration: false,\n hasCleanup: false,\n });\n return;\n }\n if (watchStack.length === 0) return;\n const top = watchStack[watchStack.length - 1]!;\n const method = calledMethodName(node);\n if (method !== undefined && REGISTER_CALLS.has(method)) {\n top.hasRegistration = true;\n }\n if (method !== undefined && CLEANUP_CALLS.has(method) && top.isEffect) {\n top.hasCleanup = true;\n }\n },\n NewExpression(node: AstNode) {\n if (watchStack.length === 0) return;\n const callee = node.callee as AstNode | undefined;\n if (\n callee?.type === 'Identifier' &&\n OBSERVERS.has(callee.name as string)\n ) {\n watchStack[watchStack.length - 1]!.hasRegistration = true;\n }\n },\n ReturnStatement(node: AstNode) {\n if (watchStack.length === 0) return;\n if (isFunction(node.argument as AstNode | undefined)) {\n watchStack[watchStack.length - 1]!.hasCleanup = true;\n }\n },\n 'CallExpression:exit'(node: AstNode) {\n if (watchStack.length === 0) return;\n const top = watchStack[watchStack.length - 1]!;\n if (top.sourceCall !== node) return;\n watchStack.pop();\n if (top.hasRegistration && !top.hasCleanup) {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import { defineRule } from '../../define-rule.js';\nimport type { AstNode, RuleContext } from '../../rule-types.js';\n\nconst DOCS_URL = 'https://vuejs.org/guide/components/async.html';\nconst MESSAGE = `This route record's \\`component:\\` field references the imported component directly, which forces a synchronous import of the route bundle. Use \\`() => import('./Foo.vue')\\` or \\`defineAsyncComponent(() => import('./Foo.vue'))\\` to lazy-load the route. See ${DOCS_URL}`;\n\nfunction keyName(key: AstNode): unknown {\n return key.type === 'Identifier' ? key.name : key.value;\n}\n\nexport const preferDefineAsyncComponentOnRoute = defineRule({\n create(context: RuleContext) {\n return {\n Property(node: AstNode) {\n if (node.computed === true || node.shorthand === true) return;\n if (keyName(node.key as AstNode) !== 'component') return;\n const value = node.value as AstNode;\n if (value.type === 'Identifier') {\n context.report({ node, message: MESSAGE });\n }\n },\n };\n },\n});\n","import type { Plugin } from './rule-types.js';\nimport { definePropsTyped } from './rules/composition/defineProps-typed.js';\nimport { preferScriptSetupForNewFiles } from './rules/composition/prefer-script-setup-for-new-files.js';\nimport { noDestructurePropsWithoutToRefs } from './rules/ai-slop/no-destructure-props-without-toRefs.js';\nimport { noDestructureReactiveWithoutToRefs } from './rules/ai-slop/no-destructure-reactive-without-toRefs.js';\nimport { noEmDashInString } from './rules/ai-slop/no-em-dash-in-string.js';\nimport { noImportsFromVueWhenAutoImported } from './rules/ai-slop/no-imports-from-vue-when-auto-imported.js';\nimport { noNonNullAssertionOnRefValue } from './rules/ai-slop/no-non-null-assertion-on-ref-value.js';\nimport { preferReadonlyForInjected } from './rules/reactivity/prefer-readonly-for-injected.js';\nimport { preferShallowRefForLargeData } from './rules/reactivity/prefer-shallowRef-for-large-data.js';\nimport { watchWithoutCleanup } from './rules/reactivity/watch-without-cleanup.js';\nimport { preferDefineAsyncComponentOnRoute } from './rules/performance/prefer-defineAsyncComponent-on-route.js';\n\nexport const plugin: Plugin = {\n meta: { name: 'vue-doctor' },\n rules: {\n 'no-em-dash-in-string': noEmDashInString,\n 'no-destructure-props-without-to-refs': noDestructurePropsWithoutToRefs,\n 'no-destructure-reactive-without-to-refs':\n noDestructureReactiveWithoutToRefs,\n 'no-non-null-assertion-on-ref-value': noNonNullAssertionOnRefValue,\n 'no-imports-from-vue-when-auto-imported': noImportsFromVueWhenAutoImported,\n 'reactivity/watch-without-cleanup': watchWithoutCleanup,\n 'reactivity/prefer-shallowRef-for-large-data': preferShallowRefForLargeData,\n 'reactivity/prefer-readonly-for-injected': preferReadonlyForInjected,\n 'composition/prefer-script-setup-for-new-files':\n preferScriptSetupForNewFiles,\n 'composition/defineProps-typed': definePropsTyped,\n 'performance/prefer-defineAsyncComponent-on-route':\n preferDefineAsyncComponentOnRoute,\n },\n};\n","import { plugin } from './plugin.js';\n\nexport default plugin;\nexport { plugin };\nexport { VUE_AUTO_IMPORTED } from './shared/vue-auto-imported-symbols.js';\nexport type { Rule, RuleContext } from './rule-types.js';\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geoql/oxlint-plugin-vue-doctor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "oxlint JS plugin for Vue 3 anti-patterns and AI-slop detection. Pairs with oxlint's built-in vue plugin via jsPlugins. TypeScript, ESM.",
|
|
6
6
|
"keywords": [
|