@lewishowles/lint-config 0.2.0 → 0.4.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 +15 -0
- package/README.md +87 -64
- package/base.json +57 -57
- package/comments/plugin.js +32 -0
- package/comments/rules/block-comments.js +70 -0
- package/comments/rules/class-documentation.js +131 -0
- package/comments/rules/configured-api-calls.js +143 -0
- package/comments/rules/function-documentation.js +111 -0
- package/comments/rules/jsdoc-tag-formatting.js +70 -0
- package/comments/rules/line-comments.js +86 -0
- package/comments/rules/max-line-length.js +159 -0
- package/comments/rules/placement.js +290 -0
- package/comments/rules/sentence-punctuation.js +275 -0
- package/comments/rules/variable-declarations.js +88 -0
- package/comments/rules/vue-component-documentation.js +169 -0
- package/comments/rules/vue-emit-documentation.js +123 -0
- package/comments/rules/vue-prop-documentation.js +224 -0
- package/comments/utils/documentation.js +349 -0
- package/comments/utils/jsdoc.js +756 -0
- package/comments/utils/source.js +346 -0
- package/comments/utils/vue-macro.js +70 -0
- package/comments/utils/wrap.js +118 -0
- package/comments.json +23 -0
- package/package.json +12 -3
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { isDirectiveComment } from "../utils/source.js";
|
|
3
|
+
|
|
4
|
+
// Captures the opening tag's attributes separately, so the setup attribute
|
|
5
|
+
// can be tested without the tag being available from Oxlint's extracted AST.
|
|
6
|
+
const scriptBlockPattern =
|
|
7
|
+
/(?<openingTag><script\b(?<attributes>[^>]*)>)(?<content>[\s\S]*?)<\/script\s*>/gi;
|
|
8
|
+
|
|
9
|
+
// Only a standalone setup attribute qualifies, avoiding matches such as
|
|
10
|
+
// data-setup or setup-mode.
|
|
11
|
+
const setupAttributePattern = /(?:^|\s)setup(?:\s|=|$)/i;
|
|
12
|
+
// Match only indentation and one line break, so documentation sits directly
|
|
13
|
+
// after the script tag.
|
|
14
|
+
const immediateCommentGapPattern = /^[ \t]*(?:\r?\n[ \t]*)?$/;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Read raw Vue source because extracted script text cannot identify script
|
|
18
|
+
* setup.
|
|
19
|
+
*
|
|
20
|
+
* @param {object} context
|
|
21
|
+
* The Oxlint rule context.
|
|
22
|
+
*
|
|
23
|
+
* @returns {string|null}
|
|
24
|
+
* The Vue source, when the physical filename can be read.
|
|
25
|
+
*/
|
|
26
|
+
function getVueSource(context) {
|
|
27
|
+
try {
|
|
28
|
+
// The extracted script text does not include the component markup.
|
|
29
|
+
// Read the opening tag from the Vue file instead.
|
|
30
|
+
const physicalFilename = context.physicalFilename;
|
|
31
|
+
|
|
32
|
+
if (typeof physicalFilename !== "string" || !physicalFilename.endsWith(".vue")) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!existsSync(physicalFilename)) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return readFileSync(physicalFilename, "utf8");
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get raw Vue script blocks in source order.
|
|
48
|
+
*
|
|
49
|
+
* @param {object} context
|
|
50
|
+
* The Oxlint rule context.
|
|
51
|
+
*
|
|
52
|
+
* @returns {RegExpMatchArray[]}
|
|
53
|
+
* The Vue script blocks, or an empty array when the source is unavailable.
|
|
54
|
+
*/
|
|
55
|
+
function getScriptBlocks(context) {
|
|
56
|
+
// Component markup is only available from the physical Vue file.
|
|
57
|
+
const vueSource = getVueSource(context);
|
|
58
|
+
|
|
59
|
+
return vueSource ? Array.from(vueSource.matchAll(scriptBlockPattern)) : [];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Find the raw script block matching the current Program's extracted text.
|
|
64
|
+
*
|
|
65
|
+
* @param {object} context
|
|
66
|
+
* The rule context for the extracted script block.
|
|
67
|
+
*
|
|
68
|
+
* @returns {RegExpMatchArray|undefined}
|
|
69
|
+
* The matching raw script block, when one is found.
|
|
70
|
+
*/
|
|
71
|
+
function findScriptBlock(context) {
|
|
72
|
+
// Re-read on every call rather than caching, since this file's other
|
|
73
|
+
// script blocks may not have been visited yet or ever in this run.
|
|
74
|
+
const scriptBlocks = getScriptBlocks(context);
|
|
75
|
+
|
|
76
|
+
return scriptBlocks.find(
|
|
77
|
+
(scriptBlock) => scriptBlock.groups.content.trim() === context.sourceCode.text.trim(),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Check whether a script block uses Vue's setup attribute.
|
|
83
|
+
*
|
|
84
|
+
* @param {RegExpMatchArray} scriptBlock
|
|
85
|
+
* The raw Vue script block.
|
|
86
|
+
*
|
|
87
|
+
* @returns {boolean}
|
|
88
|
+
* Whether the script block is a script setup block.
|
|
89
|
+
*/
|
|
90
|
+
function isScriptSetupBlock(scriptBlock) {
|
|
91
|
+
// Inspect only the opening tag, so setup code cannot affect the block type.
|
|
92
|
+
const scriptAttributes = scriptBlock.groups?.attributes ?? "";
|
|
93
|
+
|
|
94
|
+
return setupAttributePattern.test(scriptAttributes);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Check whether a Vue script setup block starts with a documentation comment.
|
|
99
|
+
*
|
|
100
|
+
* @param {object} context
|
|
101
|
+
* The rule context for the extracted script block.
|
|
102
|
+
* @param {RegExpMatchArray|undefined} scriptBlock
|
|
103
|
+
* The script block matched to the current component's entry point.
|
|
104
|
+
*
|
|
105
|
+
* @returns {boolean}
|
|
106
|
+
* Whether the component has the required documentation comment.
|
|
107
|
+
*/
|
|
108
|
+
function hasComponentDocumentation(context, scriptBlock) {
|
|
109
|
+
if (!scriptBlock || !isScriptSetupBlock(scriptBlock)) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// This Program visitor runs once per script block, so sourceCode is scoped
|
|
114
|
+
// to the current block and [0] cannot pick up a comment from another one.
|
|
115
|
+
const comment = context.sourceCode.getAllComments()[0];
|
|
116
|
+
|
|
117
|
+
// Lint directives alter rule execution but cannot document a component.
|
|
118
|
+
if (comment?.type !== "Block" || isDirectiveComment(comment)) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// A blank line would separate the component documentation from its entry point.
|
|
123
|
+
const commentGap = context.sourceCode.text.slice(0, comment.range[0]);
|
|
124
|
+
|
|
125
|
+
return immediateCommentGapPattern.test(commentGap);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export default {
|
|
129
|
+
meta: {
|
|
130
|
+
docs: { description: "Require documentation for Vue script setup components." },
|
|
131
|
+
type: "suggestion",
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* Create the checks that inspect each script block.
|
|
135
|
+
*
|
|
136
|
+
* @param {object} context
|
|
137
|
+
* The Oxlint rule context.
|
|
138
|
+
*
|
|
139
|
+
* @returns {object}
|
|
140
|
+
* The script-block checks for this rule.
|
|
141
|
+
*/
|
|
142
|
+
createOnce(context) {
|
|
143
|
+
return {
|
|
144
|
+
/**
|
|
145
|
+
* Check the current component's script setup block for documentation.
|
|
146
|
+
*
|
|
147
|
+
* @param {object} node
|
|
148
|
+
* The entry point parsed from the current script block.
|
|
149
|
+
*/
|
|
150
|
+
Program(node) {
|
|
151
|
+
// createOnce builds this visitor once for the whole run, and a
|
|
152
|
+
// single file's script blocks are not necessarily visited
|
|
153
|
+
// consecutively, so the matching block is looked up fresh on each
|
|
154
|
+
// call rather than tracked with shared state.
|
|
155
|
+
const scriptBlock = findScriptBlock(context);
|
|
156
|
+
|
|
157
|
+
if (hasComponentDocumentation(context, scriptBlock)) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
context.report({
|
|
162
|
+
message:
|
|
163
|
+
"Vue script setup components require a documentation block after the opening tag.",
|
|
164
|
+
node: node.body[0] ?? node,
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
},
|
|
169
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { getCommentNeighbours, isDirectiveComment, isLeadingComment } from "../utils/source.js";
|
|
2
|
+
import { getObjectArgument, getObjectProperties, isNamedCall } from "../utils/vue-macro.js";
|
|
3
|
+
|
|
4
|
+
// Matches the single newline and indentation allowed between a comment and an
|
|
5
|
+
// event.
|
|
6
|
+
const immediateCommentGapPattern = /^\r?\n[ \t]*$/;
|
|
7
|
+
|
|
8
|
+
// The message shared by all undocumented runtime events.
|
|
9
|
+
const missingCommentMessage =
|
|
10
|
+
"Vue emit declarations require an immediately preceding block comment.";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Return whether the current lint target is a physical Vue single-file
|
|
14
|
+
* component.
|
|
15
|
+
*
|
|
16
|
+
* @param {object} context
|
|
17
|
+
* The Oxlint rule context.
|
|
18
|
+
*
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
* Whether the current file has a Vue filename.
|
|
21
|
+
*/
|
|
22
|
+
function isVueFile(context) {
|
|
23
|
+
try {
|
|
24
|
+
// Use the physical path because the AST does not identify Vue files.
|
|
25
|
+
const physicalFilename = context.physicalFilename;
|
|
26
|
+
|
|
27
|
+
return typeof physicalFilename === "string" && physicalFilename.endsWith(".vue");
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Return whether a property has an immediately preceding block comment.
|
|
35
|
+
*
|
|
36
|
+
* @param {object} sourceCode
|
|
37
|
+
* The Oxlint source code object.
|
|
38
|
+
* @param {object} property
|
|
39
|
+
* The property to inspect.
|
|
40
|
+
*
|
|
41
|
+
* @returns {boolean}
|
|
42
|
+
* Whether the property has the required documentation comment.
|
|
43
|
+
*/
|
|
44
|
+
function hasBlockComment(sourceCode, property) {
|
|
45
|
+
// Finds the closest preceding comment.
|
|
46
|
+
const comment = sourceCode
|
|
47
|
+
.getAllComments()
|
|
48
|
+
.findLast((candidate) => candidate.range[1] <= property.range[0]);
|
|
49
|
+
|
|
50
|
+
if (comment?.type !== "Block" || isDirectiveComment(comment)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Checks the comments immediately around the property.
|
|
55
|
+
const { next, previous } = getCommentNeighbours(sourceCode, comment);
|
|
56
|
+
// The source text between the comment and the property.
|
|
57
|
+
const gap = sourceCode.text.slice(comment.range[1], property.range[0]);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
next?.range[0] === property.range[0] &&
|
|
61
|
+
isLeadingComment(sourceCode, comment, previous) &&
|
|
62
|
+
immediateCommentGapPattern.test(gap)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Report missing comments for runtime emit events.
|
|
68
|
+
*
|
|
69
|
+
* @param {object} context
|
|
70
|
+
* The Oxlint rule context.
|
|
71
|
+
* @param {object} objectExpression
|
|
72
|
+
* The runtime emits object to inspect.
|
|
73
|
+
*/
|
|
74
|
+
function reportEventDocumentation(context, objectExpression) {
|
|
75
|
+
for (const property of getObjectProperties(objectExpression)) {
|
|
76
|
+
// Checks whether this event has the required documentation.
|
|
77
|
+
const hasDocumentation = hasBlockComment(context.sourceCode, property);
|
|
78
|
+
|
|
79
|
+
if (!hasDocumentation) {
|
|
80
|
+
context.report({ message: missingCommentMessage, node: property });
|
|
81
|
+
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export default {
|
|
88
|
+
meta: {
|
|
89
|
+
docs: { description: "Require block comments for Vue runtime emits." },
|
|
90
|
+
type: "suggestion",
|
|
91
|
+
},
|
|
92
|
+
/**
|
|
93
|
+
* Create the rule's node visitors.
|
|
94
|
+
*
|
|
95
|
+
* @param {object} context
|
|
96
|
+
* The Oxlint rule context.
|
|
97
|
+
*
|
|
98
|
+
* @returns {object}
|
|
99
|
+
* The call-expression visitor for this rule.
|
|
100
|
+
*/
|
|
101
|
+
createOnce(context) {
|
|
102
|
+
return {
|
|
103
|
+
/**
|
|
104
|
+
* Check runtime defineEmits calls for event documentation.
|
|
105
|
+
*
|
|
106
|
+
* @param {object} node
|
|
107
|
+
* The call expression to inspect.
|
|
108
|
+
*/
|
|
109
|
+
CallExpression(node) {
|
|
110
|
+
if (!isVueFile(context) || !isNamedCall(node, "defineEmits")) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Array and type-only forms have no runtime properties to document.
|
|
115
|
+
const emitsObject = getObjectArgument(node, 0);
|
|
116
|
+
|
|
117
|
+
if (emitsObject) {
|
|
118
|
+
reportEventDocumentation(context, emitsObject);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
},
|
|
123
|
+
};
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getObjectArgument,
|
|
3
|
+
getObjectProperties,
|
|
4
|
+
getPropertyName,
|
|
5
|
+
isNamedCall,
|
|
6
|
+
} from "../utils/vue-macro.js";
|
|
7
|
+
import { getCommentNeighbours, isDirectiveComment, isLeadingComment } from "../utils/source.js";
|
|
8
|
+
|
|
9
|
+
// Matches the single newline and indentation allowed between a comment and a
|
|
10
|
+
// prop.
|
|
11
|
+
const immediateCommentGapPattern = /^\r?\n[ \t]*$/;
|
|
12
|
+
|
|
13
|
+
// The message shared by runtime props and their withDefaults entries.
|
|
14
|
+
const missingCommentMessage =
|
|
15
|
+
"Vue prop declarations require an immediately preceding block comment.";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Return the runtime props object from a defineProps call or withDefaults
|
|
19
|
+
* wrapper.
|
|
20
|
+
*
|
|
21
|
+
* @param {object} callNode
|
|
22
|
+
* The call to inspect.
|
|
23
|
+
*
|
|
24
|
+
* @returns {object|null}
|
|
25
|
+
* The runtime props object, or null for type-only and unrelated calls.
|
|
26
|
+
*/
|
|
27
|
+
function getPropsObject(callNode) {
|
|
28
|
+
if (isNamedCall(callNode, "defineProps")) {
|
|
29
|
+
return getObjectArgument(callNode, 0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (!isNamedCall(callNode, "withDefaults")) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// withDefaults' first argument, expected to be the defineProps call.
|
|
37
|
+
const definePropsCall = callNode.arguments[0];
|
|
38
|
+
|
|
39
|
+
return isNamedCall(definePropsCall, "defineProps") ? getObjectArgument(definePropsCall, 0) : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Return the defaults object from a withDefaults call.
|
|
44
|
+
*
|
|
45
|
+
* @param {object} callNode
|
|
46
|
+
* The call to inspect.
|
|
47
|
+
*
|
|
48
|
+
* @returns {object|null}
|
|
49
|
+
* The defaults object, when the call has one.
|
|
50
|
+
*/
|
|
51
|
+
function getDefaultsObject(callNode) {
|
|
52
|
+
return isNamedCall(callNode, "withDefaults") ? getObjectArgument(callNode, 1) : null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Return whether a defineProps call is already handled by its withDefaults
|
|
57
|
+
* wrapper.
|
|
58
|
+
*
|
|
59
|
+
* @param {object} node
|
|
60
|
+
* The defineProps call to inspect.
|
|
61
|
+
*
|
|
62
|
+
* @returns {boolean}
|
|
63
|
+
* Whether the call is the first argument of withDefaults.
|
|
64
|
+
*/
|
|
65
|
+
function isWrappedDefinePropsCall(node) {
|
|
66
|
+
// The node's enclosing call, when present.
|
|
67
|
+
const parent = node.parent;
|
|
68
|
+
|
|
69
|
+
return isNamedCall(parent, "withDefaults") && parent.arguments[0] === node;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Return whether a property has an immediately preceding block comment.
|
|
74
|
+
*
|
|
75
|
+
* @param {object} sourceCode
|
|
76
|
+
* The Oxlint source code object.
|
|
77
|
+
* @param {object} property
|
|
78
|
+
* The property to inspect.
|
|
79
|
+
*
|
|
80
|
+
* @returns {boolean}
|
|
81
|
+
* Whether the property has the required documentation comment.
|
|
82
|
+
*/
|
|
83
|
+
function hasBlockComment(sourceCode, property) {
|
|
84
|
+
// Finds the closest preceding comment.
|
|
85
|
+
const comment = sourceCode
|
|
86
|
+
.getAllComments()
|
|
87
|
+
.findLast((candidate) => candidate.range[1] <= property.range[0]);
|
|
88
|
+
|
|
89
|
+
if (comment?.type !== "Block" || isDirectiveComment(comment)) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Checks the comments immediately around the property.
|
|
94
|
+
const { next, previous } = getCommentNeighbours(sourceCode, comment);
|
|
95
|
+
// The source text between the comment and the property.
|
|
96
|
+
const gap = sourceCode.text.slice(comment.range[1], property.range[0]);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
next?.range[0] === property.range[0] &&
|
|
100
|
+
isLeadingComment(sourceCode, comment, previous) &&
|
|
101
|
+
immediateCommentGapPattern.test(gap)
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Return the names of documented properties in an object expression.
|
|
107
|
+
*
|
|
108
|
+
* @param {object} sourceCode
|
|
109
|
+
* The Oxlint source code object.
|
|
110
|
+
* @param {object} objectExpression
|
|
111
|
+
* The object expression to inspect.
|
|
112
|
+
*
|
|
113
|
+
* @returns {Set<string>}
|
|
114
|
+
* The documented property names.
|
|
115
|
+
*/
|
|
116
|
+
function getDocumentedPropertyNames(sourceCode, objectExpression) {
|
|
117
|
+
// Accumulates property names with a qualifying comment.
|
|
118
|
+
const documentedPropertyNames = new Set();
|
|
119
|
+
|
|
120
|
+
for (const property of getObjectProperties(objectExpression)) {
|
|
121
|
+
// The property's name, when it can be determined.
|
|
122
|
+
const propertyName = getPropertyName(property);
|
|
123
|
+
|
|
124
|
+
if (propertyName !== null && hasBlockComment(sourceCode, property)) {
|
|
125
|
+
documentedPropertyNames.add(propertyName);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return documentedPropertyNames;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Report properties without their required block comments.
|
|
134
|
+
*
|
|
135
|
+
* @param {object} context
|
|
136
|
+
* The Oxlint rule context.
|
|
137
|
+
* @param {object} objectExpression
|
|
138
|
+
* The object expression whose properties should be checked.
|
|
139
|
+
* @param {Set<string>|undefined} exemptedPropertyNames
|
|
140
|
+
* Property names documented by a matching defineProps entry.
|
|
141
|
+
*/
|
|
142
|
+
function reportUndocumentedProperties(context, objectExpression, exemptedPropertyNames) {
|
|
143
|
+
for (const property of getObjectProperties(objectExpression)) {
|
|
144
|
+
// The property's name, when it can be determined.
|
|
145
|
+
const propertyName = getPropertyName(property);
|
|
146
|
+
|
|
147
|
+
if (propertyName !== null && exemptedPropertyNames?.has(propertyName)) {
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!hasBlockComment(context.sourceCode, property)) {
|
|
152
|
+
context.report({ message: missingCommentMessage, node: property });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Check runtime props and withDefaults entries for documentation.
|
|
159
|
+
*
|
|
160
|
+
* @param {object} context
|
|
161
|
+
* The Oxlint rule context.
|
|
162
|
+
* @param {object} node
|
|
163
|
+
* The call expression to inspect.
|
|
164
|
+
*/
|
|
165
|
+
function reportCallDocumentation(context, node) {
|
|
166
|
+
// The call's runtime props object, when present.
|
|
167
|
+
const propsObject = getPropsObject(node);
|
|
168
|
+
|
|
169
|
+
if (!propsObject) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Every runtime defineProps property owns a required comment.
|
|
174
|
+
reportUndocumentedProperties(context, propsObject);
|
|
175
|
+
|
|
176
|
+
// The call's withDefaults defaults object, when present.
|
|
177
|
+
const defaultsObject = getDefaultsObject(node);
|
|
178
|
+
|
|
179
|
+
if (!defaultsObject) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// A matching defineProps comment documents the corresponding default too.
|
|
184
|
+
const documentedPropertyNames = getDocumentedPropertyNames(context.sourceCode, propsObject);
|
|
185
|
+
|
|
186
|
+
reportUndocumentedProperties(context, defaultsObject, documentedPropertyNames);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export default {
|
|
190
|
+
meta: {
|
|
191
|
+
docs: { description: "Require block comments for Vue runtime props." },
|
|
192
|
+
type: "suggestion",
|
|
193
|
+
},
|
|
194
|
+
/**
|
|
195
|
+
* Create the rule's node visitors.
|
|
196
|
+
*
|
|
197
|
+
* @param {object} context
|
|
198
|
+
* The Oxlint rule context.
|
|
199
|
+
*
|
|
200
|
+
* @returns {object}
|
|
201
|
+
* The call-expression visitor for this rule.
|
|
202
|
+
*/
|
|
203
|
+
createOnce(context) {
|
|
204
|
+
return {
|
|
205
|
+
/**
|
|
206
|
+
* Check defineProps calls and their withDefaults wrapper.
|
|
207
|
+
*
|
|
208
|
+
* @param {object} node
|
|
209
|
+
* The call expression to inspect.
|
|
210
|
+
*/
|
|
211
|
+
CallExpression(node) {
|
|
212
|
+
if (!isNamedCall(node, "defineProps") && !isNamedCall(node, "withDefaults")) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (isNamedCall(node, "defineProps") && isWrappedDefinePropsCall(node)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
reportCallDocumentation(context, node);
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
},
|
|
224
|
+
};
|