pasika 0.5.6 → 0.5.8
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 +53 -24
- package/package.json +1 -1
|
@@ -123,8 +123,9 @@ function findSimpleRoot(component, _text, _filename) {
|
|
|
123
123
|
ts.forEachChild(node, visit);
|
|
124
124
|
};
|
|
125
125
|
visit(body);
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
const rendered = returns.filter((statement) => statement.expression?.kind !== ts.SyntaxKind.NullKeyword);
|
|
127
|
+
if (rendered.length !== 1) return void 0;
|
|
128
|
+
const expression = rendered[0]?.expression;
|
|
128
129
|
return expression && ts.isExpression(expression) ? rootFromExpression(expression) : void 0;
|
|
129
130
|
}
|
|
130
131
|
function getTestId(root) {
|
|
@@ -1355,6 +1356,16 @@ function isKebabCase2(str) {
|
|
|
1355
1356
|
return /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(str);
|
|
1356
1357
|
}
|
|
1357
1358
|
var SUPPORT_FOLDERS = /* @__PURE__ */ new Set(["types", "schemas", "hooks", "constants", "utils", "config", "locales"]);
|
|
1359
|
+
function parentComponentName(dirPath, folderName) {
|
|
1360
|
+
const componentFile = path9.join(dirPath, `${folderName}.tsx`);
|
|
1361
|
+
if (!fs.existsSync(componentFile)) return void 0;
|
|
1362
|
+
try {
|
|
1363
|
+
const exports = parseModule(componentFile).exports;
|
|
1364
|
+
return exports.find((moduleExport) => moduleExport.kind === "component")?.name;
|
|
1365
|
+
} catch {
|
|
1366
|
+
return void 0;
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1358
1369
|
var enforceBarrelExportsRule = {
|
|
1359
1370
|
meta: {
|
|
1360
1371
|
schema: [],
|
|
@@ -1373,8 +1384,8 @@ var enforceBarrelExportsRule = {
|
|
|
1373
1384
|
const parentFolderName = path9.basename(path9.dirname(dirPath));
|
|
1374
1385
|
if (SUPPORT_FOLDERS.has(folderName)) return {};
|
|
1375
1386
|
if (!isPascalCase4(folderName) && !isKebabCase2(folderName)) return {};
|
|
1376
|
-
const
|
|
1377
|
-
if (!
|
|
1387
|
+
const parentName = parentComponentName(dirPath, folderName);
|
|
1388
|
+
if (!parentName) return {};
|
|
1378
1389
|
if (!isPascalCase4(parentFolderName) && !isKebabCase2(parentFolderName)) return {};
|
|
1379
1390
|
const reExportedNames = /* @__PURE__ */ new Set();
|
|
1380
1391
|
return {
|
|
@@ -1388,18 +1399,18 @@ var enforceBarrelExportsRule = {
|
|
|
1388
1399
|
},
|
|
1389
1400
|
"Program:exit"() {
|
|
1390
1401
|
if (reExportedNames.size === 0) return;
|
|
1391
|
-
if (!reExportedNames.has(
|
|
1402
|
+
if (!reExportedNames.has(parentName)) {
|
|
1392
1403
|
context.report({
|
|
1393
1404
|
loc: { line: 1, column: 0 },
|
|
1394
|
-
message: `index.ts in "${folderName}/" must re-export "${
|
|
1405
|
+
message: `index.ts in "${folderName}/" must re-export "${parentName}". See docs/code-organization-guide/rules/folder-nesting-rule.md`
|
|
1395
1406
|
});
|
|
1396
1407
|
return;
|
|
1397
1408
|
}
|
|
1398
|
-
const nonParentExports = [...reExportedNames].filter((n) => n !==
|
|
1409
|
+
const nonParentExports = [...reExportedNames].filter((n) => n !== parentName);
|
|
1399
1410
|
if (nonParentExports.length > 0) {
|
|
1400
1411
|
context.report({
|
|
1401
1412
|
loc: { line: 1, column: 0 },
|
|
1402
|
-
message: `index.ts must not re-export exclusive children: ${nonParentExports.join(", ")}. Only "${
|
|
1413
|
+
message: `index.ts must not re-export exclusive children: ${nonParentExports.join(", ")}. Only "${parentName}" may be re-exported. See docs/code-organization-guide/rules/folder-nesting-rule.md`
|
|
1403
1414
|
});
|
|
1404
1415
|
}
|
|
1405
1416
|
}
|
|
@@ -1408,6 +1419,7 @@ var enforceBarrelExportsRule = {
|
|
|
1408
1419
|
};
|
|
1409
1420
|
|
|
1410
1421
|
// eslint/rules/component-placement.ts
|
|
1422
|
+
import fs2 from "fs";
|
|
1411
1423
|
import path11 from "path";
|
|
1412
1424
|
|
|
1413
1425
|
// eslint/project/ccf.ts
|
|
@@ -1506,6 +1518,13 @@ var REASON_TEXT = {
|
|
|
1506
1518
|
"across-layers": "its consumers span more than one layer, so no feature can own it"
|
|
1507
1519
|
};
|
|
1508
1520
|
var sameFolder = (left, right) => left.length === right.length && left.every((segment, depth) => segment === right[depth]);
|
|
1521
|
+
function isNestedInside(expectedFolder, currentFolder, componentFile) {
|
|
1522
|
+
if (currentFolder.length !== expectedFolder.length + 1) return false;
|
|
1523
|
+
if (!sameFolder(currentFolder.slice(0, -1), expectedFolder)) return false;
|
|
1524
|
+
const folderName = currentFolder[currentFolder.length - 1];
|
|
1525
|
+
if (!folderName) return false;
|
|
1526
|
+
return fs2.existsSync(path11.join(path11.dirname(componentFile), `${folderName}.tsx`));
|
|
1527
|
+
}
|
|
1509
1528
|
var componentPlacementRule = {
|
|
1510
1529
|
meta: {
|
|
1511
1530
|
schema: [],
|
|
@@ -1541,6 +1560,7 @@ var componentPlacementRule = {
|
|
|
1541
1560
|
return;
|
|
1542
1561
|
}
|
|
1543
1562
|
if (sameFolder(currentFolder, placement.expectedFolder)) return;
|
|
1563
|
+
if (isNestedInside(placement.expectedFolder, currentFolder, componentFile)) return;
|
|
1544
1564
|
const explanation = REASON_TEXT[placement.reason] ?? "that is where its consumers place it";
|
|
1545
1565
|
context.report({
|
|
1546
1566
|
node,
|
|
@@ -1597,7 +1617,7 @@ var supportFilePlacementRule = {
|
|
|
1597
1617
|
};
|
|
1598
1618
|
|
|
1599
1619
|
// eslint/rules/application-structure.ts
|
|
1600
|
-
import
|
|
1620
|
+
import fs3 from "fs";
|
|
1601
1621
|
import path13 from "path";
|
|
1602
1622
|
var MODULE_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
1603
1623
|
var ROUTING_FILES = /* @__PURE__ */ new Set([
|
|
@@ -1672,10 +1692,10 @@ function componentFolderViolation(segments, sourceRoot) {
|
|
|
1672
1692
|
if (!folder || SUPPORT_FOLDERS2.has(folder)) continue;
|
|
1673
1693
|
const folderPath = path13.join(sourceRoot, ...segments.slice(0, depth + 1));
|
|
1674
1694
|
const label = `src/${segments.slice(0, depth + 1).join("/")}/`;
|
|
1675
|
-
if (!
|
|
1695
|
+
if (!fs3.existsSync(path13.join(folderPath, `${folder}.tsx`))) {
|
|
1676
1696
|
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.`;
|
|
1677
1697
|
}
|
|
1678
|
-
if (!
|
|
1698
|
+
if (!fs3.existsSync(path13.join(folderPath, "index.ts"))) {
|
|
1679
1699
|
return `A component folder must have an index.ts that named-re-exports its component; add index.ts to ${label}.`;
|
|
1680
1700
|
}
|
|
1681
1701
|
}
|
|
@@ -1721,7 +1741,7 @@ var applicationStructureRule = {
|
|
|
1721
1741
|
);
|
|
1722
1742
|
}
|
|
1723
1743
|
const moduleRoot = configModuleRoot(filename, sourceRoot);
|
|
1724
|
-
if (moduleRoot && !
|
|
1744
|
+
if (moduleRoot && !fs3.existsSync(path13.join(moduleRoot, "index.ts"))) {
|
|
1725
1745
|
return report2(
|
|
1726
1746
|
context,
|
|
1727
1747
|
`Add src/config/${path13.basename(moduleRoot)}/index.ts as the configuration module entry point.`
|
|
@@ -1842,16 +1862,25 @@ var namedExportsRule = {
|
|
|
1842
1862
|
// eslint/rules/data-testid-case.ts
|
|
1843
1863
|
import path15 from "path";
|
|
1844
1864
|
var NEXT_ROUTING_FILES2 = /* @__PURE__ */ new Set([
|
|
1845
|
-
"
|
|
1865
|
+
"default",
|
|
1866
|
+
"error",
|
|
1867
|
+
"global-error",
|
|
1868
|
+
"instrumentation",
|
|
1846
1869
|
"layout",
|
|
1847
1870
|
"loading",
|
|
1848
|
-
"
|
|
1871
|
+
"middleware",
|
|
1849
1872
|
"not-found",
|
|
1873
|
+
"page",
|
|
1850
1874
|
"route",
|
|
1851
1875
|
"template",
|
|
1852
|
-
|
|
1853
|
-
"
|
|
1854
|
-
"
|
|
1876
|
+
// File conventions Next.js requires to keep their exact names in src/app/
|
|
1877
|
+
"apple-icon",
|
|
1878
|
+
"icon",
|
|
1879
|
+
"manifest",
|
|
1880
|
+
"opengraph-image",
|
|
1881
|
+
"robots",
|
|
1882
|
+
"sitemap",
|
|
1883
|
+
"twitter-image"
|
|
1855
1884
|
]);
|
|
1856
1885
|
var isPascalCase5 = (value) => /^[A-Z][A-Za-z0-9]*$/.test(value);
|
|
1857
1886
|
var isKebabCase3 = (value) => /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/.test(value);
|
|
@@ -1907,7 +1936,7 @@ function toKebabCase(value) {
|
|
|
1907
1936
|
}
|
|
1908
1937
|
|
|
1909
1938
|
// eslint/rules/support-folder-shape.ts
|
|
1910
|
-
import
|
|
1939
|
+
import fs4 from "fs";
|
|
1911
1940
|
import path16 from "path";
|
|
1912
1941
|
var SUPPORT_FOLDERS3 = /* @__PURE__ */ new Set(["constants", "types", "schemas"]);
|
|
1913
1942
|
var INDEX_NAMES = /* @__PURE__ */ new Set(["index.ts", "index.tsx", "index.mts", "index.cts"]);
|
|
@@ -1928,7 +1957,7 @@ var supportFolderShapeRule = {
|
|
|
1928
1957
|
const directory = path16.dirname(filename);
|
|
1929
1958
|
let entries;
|
|
1930
1959
|
try {
|
|
1931
|
-
entries =
|
|
1960
|
+
entries = fs4.readdirSync(directory);
|
|
1932
1961
|
} catch {
|
|
1933
1962
|
return {};
|
|
1934
1963
|
}
|
|
@@ -3776,7 +3805,7 @@ var sourceUnderSrcRule = {
|
|
|
3776
3805
|
};
|
|
3777
3806
|
|
|
3778
3807
|
// eslint/rules/zirka-baseline.ts
|
|
3779
|
-
import
|
|
3808
|
+
import fs5 from "fs";
|
|
3780
3809
|
import path36 from "path";
|
|
3781
3810
|
var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
|
|
3782
3811
|
var PRETTIER_CONFIGS = [
|
|
@@ -3815,12 +3844,12 @@ var zirkaBaselineRule = {
|
|
|
3815
3844
|
);
|
|
3816
3845
|
}
|
|
3817
3846
|
const tsconfigPath = path36.join(projectRoot, "tsconfig.json");
|
|
3818
|
-
if (!
|
|
3847
|
+
if (!fs5.existsSync(tsconfigPath)) {
|
|
3819
3848
|
report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
|
|
3820
3849
|
} else {
|
|
3821
3850
|
let extendsValue;
|
|
3822
3851
|
try {
|
|
3823
|
-
const parsed = JSON.parse(
|
|
3852
|
+
const parsed = JSON.parse(fs5.readFileSync(tsconfigPath, "utf8"));
|
|
3824
3853
|
extendsValue = typeof parsed === "object" && parsed !== null && "extends" in parsed ? parsed.extends : void 0;
|
|
3825
3854
|
} catch {
|
|
3826
3855
|
report3(
|
|
@@ -3832,13 +3861,13 @@ var zirkaBaselineRule = {
|
|
|
3832
3861
|
report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
|
|
3833
3862
|
}
|
|
3834
3863
|
}
|
|
3835
|
-
const prettierConfigFile = PRETTIER_CONFIGS.find((name) =>
|
|
3864
|
+
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs5.existsSync(path36.join(projectRoot, name)));
|
|
3836
3865
|
if (!prettierConfigFile) {
|
|
3837
3866
|
report3(
|
|
3838
3867
|
"No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
|
|
3839
3868
|
);
|
|
3840
3869
|
} else {
|
|
3841
|
-
const content =
|
|
3870
|
+
const content = fs5.readFileSync(path36.join(projectRoot, prettierConfigFile), "utf8");
|
|
3842
3871
|
if (!content.includes("zirka")) {
|
|
3843
3872
|
report3(
|
|
3844
3873
|
"The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
|