Skip to content

Commit 52fb47e

Browse files
committed
feat(eslint-plugin): add no-missing-exports rule (#2612)
1 parent 94cc16c commit 52fb47e

File tree

5 files changed

+119
-0
lines changed

5 files changed

+119
-0
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "@pinia/eslint-plugin",
3+
"version": "0.0.1",
4+
"main": "src/index.js",
5+
"type": "commonjs",
6+
"peerDependencies": {
7+
"eslint": "^8.0.0"
8+
},
9+
"scripts": {
10+
"test": "eslint --rule 'pinia/no-missing-exports: error' tests/*.js && node tests/no-missing-exports.test.js"
11+
}
12+
}
13+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
rules: {
3+
"pinia/no-missing-exports": "warn"
4+
}
5+
};
6+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
rules: {
3+
"no-missing-exports": require("./rules/no-missing-exports"),
4+
},
5+
6+
configs: {
7+
recommended: require("./configs/recommended"),
8+
}
9+
};
10+
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Rule goal:
3+
* Warn when variables declared inside a Pinia setup store
4+
* are NOT returned in the final return statement.
5+
*/
6+
7+
module.exports = {
8+
meta: {
9+
type: "problem",
10+
docs: {
11+
description:
12+
"Warn when variables declared inside a setup store are not exported via return()",
13+
},
14+
schema: [],
15+
},
16+
17+
create(context) {
18+
return {
19+
ReturnStatement(node) {
20+
const returnedNames = new Set();
21+
22+
// read return object properties (return { a, b })
23+
if (node.argument && node.argument.properties) {
24+
for (const prop of node.argument.properties) {
25+
if (prop.key && prop.key.name) {
26+
returnedNames.add(prop.key.name);
27+
}
28+
}
29+
}
30+
31+
// find variable declarations in the same function
32+
const fn = context
33+
.getAncestors()
34+
.reverse()
35+
.find(
36+
(n) =>
37+
n.type === "FunctionDeclaration" ||
38+
n.type === "FunctionExpression" ||
39+
n.type === "ArrowFunctionExpression"
40+
);
41+
42+
if (!fn || !fn.body || !fn.body.body) return;
43+
44+
for (const stmt of fn.body.body) {
45+
if (stmt.type === "VariableDeclaration") {
46+
for (const decl of stmt.declarations) {
47+
const name = decl.id.name;
48+
if (!returnedNames.has(name)) {
49+
context.report({
50+
node: decl,
51+
message: `Variable '${name}' is declared but not exported via return()`,
52+
});
53+
}
54+
}
55+
}
56+
}
57+
},
58+
};
59+
},
60+
};
61+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const rule = require("../src/rules/no-missing-exports");
2+
const { RuleTester } = require("eslint");
3+
4+
const tester = new RuleTester({
5+
parserOptions: { ecmaVersion: 2020, sourceType: "module" }
6+
});
7+
8+
tester.run("no-missing-exports", rule, {
9+
valid: [
10+
`
11+
export const useX = defineStore('x', () => {
12+
const a = 1;
13+
return { a };
14+
});
15+
`
16+
],
17+
invalid: [
18+
{
19+
code: `
20+
export const useX = defineStore('x', () => {
21+
const a = 1;
22+
const b = 2;
23+
return { a };
24+
});
25+
`,
26+
errors: [{ message: "Variable 'b' is declared but not exported via return()" }]
27+
}
28+
]
29+
});

0 commit comments

Comments
 (0)