pasika 0.10.35 → 0.10.37
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/dist/eslint/pasika/index.js +62 -22
- package/package.json +1 -1
|
@@ -1882,11 +1882,21 @@ function resolveComponentPlacement(componentFile, index) {
|
|
|
1882
1882
|
return { countedConsumers: counted, expectedFolder: shared, reason: "ccf" };
|
|
1883
1883
|
}
|
|
1884
1884
|
var formatFolder = (folder) => `src/${folder.join("/")}/`;
|
|
1885
|
+
function hasExactEntry(directory, entryName) {
|
|
1886
|
+
try {
|
|
1887
|
+
return fs2.readdirSync(directory).includes(entryName);
|
|
1888
|
+
} catch {
|
|
1889
|
+
return false;
|
|
1890
|
+
}
|
|
1891
|
+
}
|
|
1892
|
+
function hasComponentOwner(folderPath, folderName) {
|
|
1893
|
+
return hasExactEntry(folderPath, `${folderName}.tsx`);
|
|
1894
|
+
}
|
|
1885
1895
|
function isValidComponentFolder(folder, sourceRoot) {
|
|
1886
1896
|
const name = folder[folder.length - 1];
|
|
1887
1897
|
if (!name || SUPPORT_FOLDERS2.has(name)) return false;
|
|
1888
1898
|
const folderPath = path10.join(sourceRoot, ...folder);
|
|
1889
|
-
return
|
|
1899
|
+
return hasComponentOwner(folderPath, name) && hasExactEntry(folderPath, "index.ts");
|
|
1890
1900
|
}
|
|
1891
1901
|
function owningFolderOf(consumer, sourceRoot) {
|
|
1892
1902
|
const result = outOfSupportFolders(folderSegmentsOf(consumer, sourceRoot));
|
|
@@ -2156,7 +2166,7 @@ function componentFolderStart(segments) {
|
|
|
2156
2166
|
return -1;
|
|
2157
2167
|
}
|
|
2158
2168
|
function hasComponentBarrel(folderPath) {
|
|
2159
|
-
return
|
|
2169
|
+
return hasExactEntry(folderPath, "index.ts");
|
|
2160
2170
|
}
|
|
2161
2171
|
function componentFolderViolation(segments, sourceRoot) {
|
|
2162
2172
|
const start = componentFolderStart(segments);
|
|
@@ -2166,7 +2176,7 @@ function componentFolderViolation(segments, sourceRoot) {
|
|
|
2166
2176
|
if (!folder || SUPPORT_FOLDERS2.has(folder)) continue;
|
|
2167
2177
|
const folderPath = path13.join(sourceRoot, ...segments.slice(0, depth + 1));
|
|
2168
2178
|
const label = `src/${segments.slice(0, depth + 1).join("/")}/`;
|
|
2169
|
-
if (!
|
|
2179
|
+
if (!hasComponentOwner(folderPath, folder)) {
|
|
2170
2180
|
return `A folder that is not a support folder must be a component folder; add "${folder}.tsx" to ${label} or move its files into a support folder.`;
|
|
2171
2181
|
}
|
|
2172
2182
|
if (!hasComponentBarrel(folderPath)) {
|
|
@@ -3875,40 +3885,70 @@ var hookComplexityRule = {
|
|
|
3875
3885
|
if (relative.startsWith("..")) return {};
|
|
3876
3886
|
const segments = relative.split(path28.sep);
|
|
3877
3887
|
const sourceText = context.sourceCode.text;
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
|
|
3881
|
-
|
|
3882
|
-
|
|
3888
|
+
const index = getProjectIndex(sourceRoot);
|
|
3889
|
+
const localHookCalls = /* @__PURE__ */ new Set();
|
|
3890
|
+
const hooks = [];
|
|
3891
|
+
function registerHook(node, name, body, exported) {
|
|
3892
|
+
if (!name || !isHookName3(name) || !body) return;
|
|
3893
|
+
hooks.push({ node, name, body, exported });
|
|
3894
|
+
}
|
|
3895
|
+
function reportHooks() {
|
|
3883
3896
|
const parentFolder = segments.length >= 2 ? segments[segments.length - 2] : void 0;
|
|
3884
3897
|
const inSupportFolder = parentFolder === "hooks";
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3898
|
+
for (const { node, name, body, exported } of hooks) {
|
|
3899
|
+
const score = computeExtractionScore(body, sourceText);
|
|
3900
|
+
const hasLocalConsumer = localHookCalls.has(name);
|
|
3901
|
+
const externalConsumerCount = exported ? index?.symbolConsumers.get(symbolKey(filename, name))?.size ?? 0 : 0;
|
|
3902
|
+
if (score >= 2) {
|
|
3903
|
+
if (!inSupportFolder && (exported || hasLocalConsumer)) {
|
|
3904
|
+
context.report({
|
|
3905
|
+
node,
|
|
3906
|
+
message: `Hook "${name}" has an extraction score of ${String(score)} and must be extracted to a hooks/ folder. See docs/next-codebase-guide/rules/hook-extraction-rule.md`
|
|
3907
|
+
});
|
|
3908
|
+
}
|
|
3909
|
+
continue;
|
|
3910
|
+
}
|
|
3911
|
+
const consumerCount = externalConsumerCount + (hasLocalConsumer ? 1 : 0);
|
|
3912
|
+
if (inSupportFolder && exported) {
|
|
3913
|
+
if (consumerCount < 2) {
|
|
3914
|
+
context.report({
|
|
3915
|
+
node,
|
|
3916
|
+
message: `Hook "${name}" has an extraction score below two and must be inlined directly into its sole consumer instead of remaining a custom hook. See docs/next-codebase-guide/rules/hook-extraction-rule.md`
|
|
3917
|
+
});
|
|
3918
|
+
}
|
|
3919
|
+
continue;
|
|
3920
|
+
}
|
|
3921
|
+
const isSingleLocalConsumer = hasLocalConsumer && externalConsumerCount === 0;
|
|
3922
|
+
if (isSingleLocalConsumer) {
|
|
3923
|
+
context.report({
|
|
3924
|
+
node,
|
|
3925
|
+
message: `Hook "${name}" has one local consumer and an extraction score below two; inline its React primitives and handlers directly into the consumer instead of keeping a custom hook. See docs/next-codebase-guide/rules/hook-extraction-rule.md`
|
|
3926
|
+
});
|
|
3927
|
+
}
|
|
3895
3928
|
}
|
|
3896
3929
|
}
|
|
3897
3930
|
return {
|
|
3898
3931
|
FunctionDeclaration(node) {
|
|
3899
3932
|
const exported = node.parent?.type === "ExportNamedDeclaration";
|
|
3900
|
-
|
|
3933
|
+
registerHook(node, node.id?.name, node.body, exported);
|
|
3901
3934
|
},
|
|
3902
3935
|
VariableDeclarator(node) {
|
|
3903
3936
|
if (node.id.type !== "Identifier") return;
|
|
3904
|
-
const exported = node.parent.parent?.type === "ExportNamedDeclaration";
|
|
3905
|
-
if (!exported) return;
|
|
3906
3937
|
const init = node.init;
|
|
3907
3938
|
if (!init || init.type !== "ArrowFunctionExpression" && init.type !== "FunctionExpression") {
|
|
3908
3939
|
return;
|
|
3909
3940
|
}
|
|
3910
3941
|
if (init.body.type !== "BlockStatement") return;
|
|
3911
|
-
|
|
3942
|
+
const exported = node.parent.parent?.type === "ExportNamedDeclaration";
|
|
3943
|
+
registerHook(node, node.id.name, init.body, exported);
|
|
3944
|
+
},
|
|
3945
|
+
CallExpression(node) {
|
|
3946
|
+
if (node.callee.type === "Identifier" && isHookName3(node.callee.name)) {
|
|
3947
|
+
localHookCalls.add(node.callee.name);
|
|
3948
|
+
}
|
|
3949
|
+
},
|
|
3950
|
+
"Program:exit"() {
|
|
3951
|
+
reportHooks();
|
|
3912
3952
|
}
|
|
3913
3953
|
};
|
|
3914
3954
|
}
|