pasika 0.10.31 → 0.10.32
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.d.ts +3 -5
- package/dist/eslint/pasika/index.js +161 -180
- package/package.json +2 -1
|
@@ -110,12 +110,11 @@ declare const tailwindRules: {
|
|
|
110
110
|
"stylesheet-ordering": _eslint_css.CSSRuleDefinition;
|
|
111
111
|
"css-variable-naming": _eslint_css.CSSRuleDefinition;
|
|
112
112
|
"custom-utility-apply": _eslint_css.CSSRuleDefinition;
|
|
113
|
-
"
|
|
113
|
+
"utility-mapping": _eslint_css.CSSRuleDefinition;
|
|
114
114
|
"theme-variable-namespace": _eslint_css.CSSRuleDefinition;
|
|
115
115
|
"css-entry-point": _eslint_css.CSSRuleDefinition;
|
|
116
116
|
"global-stylesheet": _eslint_css.CSSRuleDefinition;
|
|
117
117
|
"unused-utility": _eslint_css.CSSRuleDefinition;
|
|
118
|
-
"single-use-utility": _eslint_css.CSSRuleDefinition;
|
|
119
118
|
"global-selector-styling": _eslint_css.CSSRuleDefinition;
|
|
120
119
|
};
|
|
121
120
|
|
|
@@ -162,12 +161,11 @@ declare const pasikaPlugin: {
|
|
|
162
161
|
"stylesheet-ordering": _eslint_css.CSSRuleDefinition;
|
|
163
162
|
"css-variable-naming": _eslint_css.CSSRuleDefinition;
|
|
164
163
|
"custom-utility-apply": _eslint_css.CSSRuleDefinition;
|
|
165
|
-
"
|
|
164
|
+
"utility-mapping": _eslint_css.CSSRuleDefinition;
|
|
166
165
|
"theme-variable-namespace": _eslint_css.CSSRuleDefinition;
|
|
167
166
|
"css-entry-point": _eslint_css.CSSRuleDefinition;
|
|
168
167
|
"global-stylesheet": _eslint_css.CSSRuleDefinition;
|
|
169
168
|
"unused-utility": _eslint_css.CSSRuleDefinition;
|
|
170
|
-
"single-use-utility": _eslint_css.CSSRuleDefinition;
|
|
171
169
|
"global-selector-styling": _eslint_css.CSSRuleDefinition;
|
|
172
170
|
"doc-kind-suffix": _eslint_markdown.MarkdownRuleDefinition;
|
|
173
171
|
"title-matches-file-name": _eslint_markdown.MarkdownRuleDefinition;
|
|
@@ -222,6 +220,7 @@ declare const pasikaPlugin: {
|
|
|
222
220
|
"ui-state": eslint.Rule.RuleModule;
|
|
223
221
|
"no-mixed-concerns": eslint.Rule.RuleModule;
|
|
224
222
|
"no-arbitrary-tailwind": eslint.Rule.RuleModule;
|
|
223
|
+
"no-literal-inline-style": eslint.Rule.RuleModule;
|
|
225
224
|
"unknown-utility": eslint.Rule.RuleModule;
|
|
226
225
|
"enforce-cn-merge": {
|
|
227
226
|
meta: {
|
|
@@ -255,7 +254,6 @@ declare const pasikaPlugin: {
|
|
|
255
254
|
"locale-placement": eslint.Rule.RuleModule;
|
|
256
255
|
"sole-state-owner": eslint.Rule.RuleModule;
|
|
257
256
|
"locale-key-shape": eslint.Rule.RuleModule;
|
|
258
|
-
"shared-style-dedup": eslint.Rule.RuleModule;
|
|
259
257
|
"repeated-structure": eslint.Rule.RuleModule;
|
|
260
258
|
};
|
|
261
259
|
};
|
|
@@ -727,6 +727,74 @@ var noArbitraryTailwindRule = {
|
|
|
727
727
|
}
|
|
728
728
|
};
|
|
729
729
|
|
|
730
|
+
// eslint/rules/no-literal-inline-style.ts
|
|
731
|
+
function isStaticValue(value) {
|
|
732
|
+
if (value.type === "Literal") {
|
|
733
|
+
return typeof value.value === "string" || typeof value.value === "number" || typeof value.value === "boolean";
|
|
734
|
+
}
|
|
735
|
+
if (value.type === "TemplateLiteral") {
|
|
736
|
+
return value.expressions.length === 0;
|
|
737
|
+
}
|
|
738
|
+
if (value.type === "UnaryExpression" && (value.operator === "-" || value.operator === "+") && value.argument.type === "Literal") {
|
|
739
|
+
return true;
|
|
740
|
+
}
|
|
741
|
+
if (value.type === "ConditionalExpression") {
|
|
742
|
+
return isStaticValue(value.consequent) || isStaticValue(value.alternate);
|
|
743
|
+
}
|
|
744
|
+
if (value.type === "LogicalExpression") {
|
|
745
|
+
return isStaticValue(value.left) || isStaticValue(value.right);
|
|
746
|
+
}
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
function propertyName(property) {
|
|
750
|
+
if (!property.computed && property.key.type === "Identifier") return property.key.name;
|
|
751
|
+
if (property.key.type === "Literal" && typeof property.key.value === "string") return property.key.value;
|
|
752
|
+
return void 0;
|
|
753
|
+
}
|
|
754
|
+
function findStaticDeclaration(expression) {
|
|
755
|
+
for (const property of expression.properties) {
|
|
756
|
+
if (property.type !== "Property" || property.kind !== "init") continue;
|
|
757
|
+
const name = propertyName(property);
|
|
758
|
+
if (!name) continue;
|
|
759
|
+
if (isStaticValue(property.value)) return name;
|
|
760
|
+
}
|
|
761
|
+
return void 0;
|
|
762
|
+
}
|
|
763
|
+
function findStaticStyle(expression) {
|
|
764
|
+
if (expression.type === "ObjectExpression") return findStaticDeclaration(expression);
|
|
765
|
+
if (expression.type === "ConditionalExpression") {
|
|
766
|
+
return findStaticStyle(expression.consequent) ?? findStaticStyle(expression.alternate);
|
|
767
|
+
}
|
|
768
|
+
if (expression.type === "LogicalExpression") {
|
|
769
|
+
return findStaticStyle(expression.left) ?? findStaticStyle(expression.right);
|
|
770
|
+
}
|
|
771
|
+
return void 0;
|
|
772
|
+
}
|
|
773
|
+
var noLiteralInlineStyleRule = {
|
|
774
|
+
meta: {
|
|
775
|
+
schema: [],
|
|
776
|
+
type: "problem",
|
|
777
|
+
docs: {
|
|
778
|
+
description: "Disallow static CSS declarations in JSX style attributes."
|
|
779
|
+
}
|
|
780
|
+
},
|
|
781
|
+
create(context) {
|
|
782
|
+
return {
|
|
783
|
+
JSXAttribute(node) {
|
|
784
|
+
if (node.name?.name !== "style" || node.value?.type !== "JSXExpressionContainer") return;
|
|
785
|
+
const expression = node.value.expression;
|
|
786
|
+
if (!expression) return;
|
|
787
|
+
const name = findStaticStyle(expression);
|
|
788
|
+
if (!name) return;
|
|
789
|
+
context.report({
|
|
790
|
+
node,
|
|
791
|
+
message: `Static inline style "${name}" should use Tailwind. Keep inline styles for runtime-sourced values. See docs/next-tailwind-guide/rules/inline-style-rule.md`
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
|
|
730
798
|
// eslint/rules/unknown-utility.ts
|
|
731
799
|
import { existsSync, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
|
|
732
800
|
import { createRequire as createRequire2 } from "module";
|
|
@@ -4807,67 +4875,6 @@ var localeKeyShapeRule = {
|
|
|
4807
4875
|
}
|
|
4808
4876
|
};
|
|
4809
4877
|
|
|
4810
|
-
// eslint/rules/shared-style-dedup.ts
|
|
4811
|
-
import path40 from "path";
|
|
4812
|
-
import { readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
4813
|
-
var CLASS_NAME = /className="(?<classes>[^"]+)"/g;
|
|
4814
|
-
var comboCache;
|
|
4815
|
-
function combosFor(index) {
|
|
4816
|
-
const files = [...index.modules.keys()].filter((file) => file.endsWith(".tsx") || file.endsWith(".jsx")).sort((left, right) => left.localeCompare(right));
|
|
4817
|
-
let fingerprint2 = "";
|
|
4818
|
-
for (const file of files) {
|
|
4819
|
-
fingerprint2 += String(statSync3(file).mtimeMs);
|
|
4820
|
-
}
|
|
4821
|
-
if (comboCache?.sourceRoot === index.sourceRoot && comboCache.fingerprint === fingerprint2) {
|
|
4822
|
-
return comboCache.combos;
|
|
4823
|
-
}
|
|
4824
|
-
const combos = /* @__PURE__ */ new Map();
|
|
4825
|
-
for (const file of files) {
|
|
4826
|
-
const text = readFileSync6(file, "utf8");
|
|
4827
|
-
for (const match of text.matchAll(CLASS_NAME)) {
|
|
4828
|
-
const classes = (match.groups?.classes ?? "").split(/\s+/).filter(Boolean);
|
|
4829
|
-
if (classes.length < 2) continue;
|
|
4830
|
-
const key = [...classes].sort().join(" ");
|
|
4831
|
-
const users = combos.get(key) ?? /* @__PURE__ */ new Set();
|
|
4832
|
-
users.add(file);
|
|
4833
|
-
combos.set(key, users);
|
|
4834
|
-
}
|
|
4835
|
-
}
|
|
4836
|
-
comboCache = { sourceRoot: index.sourceRoot, fingerprint: fingerprint2, combos };
|
|
4837
|
-
return combos;
|
|
4838
|
-
}
|
|
4839
|
-
var sharedStyleDedupRule = {
|
|
4840
|
-
meta: {
|
|
4841
|
-
schema: [],
|
|
4842
|
-
type: "problem",
|
|
4843
|
-
docs: {
|
|
4844
|
-
description: "Require a className combination used by two or more components to become a named *-skin utility."
|
|
4845
|
-
}
|
|
4846
|
-
},
|
|
4847
|
-
create(context) {
|
|
4848
|
-
const sourceRoot = sourceRootOf(context);
|
|
4849
|
-
const file = path40.resolve(context.filename);
|
|
4850
|
-
const segments = segmentsOf(file, sourceRoot);
|
|
4851
|
-
if (segments.length === 0) return {};
|
|
4852
|
-
const index = getProjectIndex(sourceRoot);
|
|
4853
|
-
if (!index) return {};
|
|
4854
|
-
const combos = combosFor(index);
|
|
4855
|
-
const sharedHere = [...combos.entries()].filter(([, users]) => users.size >= 2 && users.has(file)).filter(([, users]) => [...users].sort((left, right) => left.localeCompare(right))[0] === file);
|
|
4856
|
-
if (sharedHere.length === 0) return {};
|
|
4857
|
-
return {
|
|
4858
|
-
Program(node) {
|
|
4859
|
-
for (const [combo, users] of sharedHere) {
|
|
4860
|
-
context.report({
|
|
4861
|
-
node,
|
|
4862
|
-
loc: { line: 1, column: 0 },
|
|
4863
|
-
message: `Class combination "${combo}" is used by ${String(users.size)} components and should change together; create a named *-skin Tailwind utility for it. See docs/next-tailwind-guide/rules/theme-and-utility-definition-rule.md`
|
|
4864
|
-
});
|
|
4865
|
-
}
|
|
4866
|
-
}
|
|
4867
|
-
};
|
|
4868
|
-
}
|
|
4869
|
-
};
|
|
4870
|
-
|
|
4871
4878
|
// eslint/rules/repeated-structure.ts
|
|
4872
4879
|
function nodeKind(node) {
|
|
4873
4880
|
return node.type;
|
|
@@ -5083,7 +5090,7 @@ var zodSchemaValidationRule = {
|
|
|
5083
5090
|
};
|
|
5084
5091
|
|
|
5085
5092
|
// eslint/rules/schema-casing.ts
|
|
5086
|
-
import
|
|
5093
|
+
import path40 from "path";
|
|
5087
5094
|
function isCamelCase(name) {
|
|
5088
5095
|
return /^[a-z][a-zA-Z0-9]*$/.test(name);
|
|
5089
5096
|
}
|
|
@@ -5111,9 +5118,9 @@ var schemaCasingRule = {
|
|
|
5111
5118
|
}
|
|
5112
5119
|
},
|
|
5113
5120
|
create(context) {
|
|
5114
|
-
const filename =
|
|
5121
|
+
const filename = path40.resolve(context.filename);
|
|
5115
5122
|
const sourceRoot = sourceRootOf(context);
|
|
5116
|
-
if (!filename.startsWith(sourceRoot +
|
|
5123
|
+
if (!filename.startsWith(sourceRoot + path40.sep)) return {};
|
|
5117
5124
|
let zodLocalName;
|
|
5118
5125
|
return {
|
|
5119
5126
|
ImportDeclaration(node) {
|
|
@@ -5145,7 +5152,7 @@ var schemaCasingRule = {
|
|
|
5145
5152
|
};
|
|
5146
5153
|
|
|
5147
5154
|
// eslint/rules/component-casing.ts
|
|
5148
|
-
import
|
|
5155
|
+
import path41 from "path";
|
|
5149
5156
|
function isPascalCase5(name) {
|
|
5150
5157
|
return /^[A-Z][A-Za-z0-9]*$/.test(name);
|
|
5151
5158
|
}
|
|
@@ -5158,10 +5165,10 @@ var componentCasingRule = {
|
|
|
5158
5165
|
}
|
|
5159
5166
|
},
|
|
5160
5167
|
create(context) {
|
|
5161
|
-
const filename =
|
|
5168
|
+
const filename = path41.resolve(context.filename);
|
|
5162
5169
|
const sourceRoot = sourceRootOf(context);
|
|
5163
|
-
if (!filename.startsWith(sourceRoot +
|
|
5164
|
-
if (
|
|
5170
|
+
if (!filename.startsWith(sourceRoot + path41.sep)) return {};
|
|
5171
|
+
if (path41.extname(filename) !== ".tsx") return {};
|
|
5165
5172
|
return {
|
|
5166
5173
|
Program(node) {
|
|
5167
5174
|
for (const declaration of findJsxReturningDeclarations(context.sourceCode.text, filename)) {
|
|
@@ -5178,7 +5185,7 @@ var componentCasingRule = {
|
|
|
5178
5185
|
};
|
|
5179
5186
|
|
|
5180
5187
|
// eslint/rules/source-under-src.ts
|
|
5181
|
-
import
|
|
5188
|
+
import path42 from "path";
|
|
5182
5189
|
var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
|
|
5183
5190
|
".agents",
|
|
5184
5191
|
".cache",
|
|
@@ -5219,14 +5226,14 @@ var sourceUnderSrcRule = {
|
|
|
5219
5226
|
}
|
|
5220
5227
|
},
|
|
5221
5228
|
create(context) {
|
|
5222
|
-
const filename =
|
|
5229
|
+
const filename = path42.resolve(context.filename);
|
|
5223
5230
|
if (!MODULE_EXTENSION.test(filename)) return {};
|
|
5224
|
-
const relative =
|
|
5231
|
+
const relative = path42.relative(context.cwd, filename).replace(/\\/g, "/");
|
|
5225
5232
|
if (relative === "src" || relative.startsWith("src/")) return {};
|
|
5226
5233
|
const topLevel = relative.split("/")[0] ?? "";
|
|
5227
5234
|
if (NON_SOURCE_ROOT_DIRS.has(topLevel)) return {};
|
|
5228
5235
|
if (!relative.includes("/")) {
|
|
5229
|
-
const basename =
|
|
5236
|
+
const basename = path42.basename(filename);
|
|
5230
5237
|
if (CONFIG_FILE.test(basename) || DECLARATION_FILE.test(basename) || basename.startsWith(".")) return {};
|
|
5231
5238
|
}
|
|
5232
5239
|
return {
|
|
@@ -5243,7 +5250,7 @@ var sourceUnderSrcRule = {
|
|
|
5243
5250
|
|
|
5244
5251
|
// eslint/rules/zirka-baseline.ts
|
|
5245
5252
|
import fs6 from "fs";
|
|
5246
|
-
import
|
|
5253
|
+
import path43 from "path";
|
|
5247
5254
|
var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
|
|
5248
5255
|
var PRETTIER_CONFIGS = [
|
|
5249
5256
|
"prettier.config.mjs",
|
|
@@ -5262,10 +5269,10 @@ var zirkaBaselineRule = {
|
|
|
5262
5269
|
}
|
|
5263
5270
|
},
|
|
5264
5271
|
create(context) {
|
|
5265
|
-
const filename =
|
|
5266
|
-
const basename =
|
|
5272
|
+
const filename = path43.resolve(context.filename);
|
|
5273
|
+
const basename = path43.basename(filename);
|
|
5267
5274
|
if (!ESLINT_CONFIG.test(basename)) return {};
|
|
5268
|
-
const projectRoot =
|
|
5275
|
+
const projectRoot = path43.dirname(filename);
|
|
5269
5276
|
const report3 = (message) => {
|
|
5270
5277
|
context.report({
|
|
5271
5278
|
node: context.sourceCode.ast,
|
|
@@ -5280,7 +5287,7 @@ var zirkaBaselineRule = {
|
|
|
5280
5287
|
'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
|
|
5281
5288
|
);
|
|
5282
5289
|
}
|
|
5283
|
-
const tsconfigPath =
|
|
5290
|
+
const tsconfigPath = path43.join(projectRoot, "tsconfig.json");
|
|
5284
5291
|
if (!fs6.existsSync(tsconfigPath)) {
|
|
5285
5292
|
report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
|
|
5286
5293
|
} else {
|
|
@@ -5298,13 +5305,13 @@ var zirkaBaselineRule = {
|
|
|
5298
5305
|
report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
|
|
5299
5306
|
}
|
|
5300
5307
|
}
|
|
5301
|
-
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs6.existsSync(
|
|
5308
|
+
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs6.existsSync(path43.join(projectRoot, name)));
|
|
5302
5309
|
if (!prettierConfigFile) {
|
|
5303
5310
|
report3(
|
|
5304
5311
|
"No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
|
|
5305
5312
|
);
|
|
5306
5313
|
} else {
|
|
5307
|
-
const content = fs6.readFileSync(
|
|
5314
|
+
const content = fs6.readFileSync(path43.join(projectRoot, prettierConfigFile), "utf8");
|
|
5308
5315
|
if (!content.includes("zirka")) {
|
|
5309
5316
|
report3(
|
|
5310
5317
|
"The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
|
|
@@ -5324,6 +5331,9 @@ function referencesZirka(sourceCode) {
|
|
|
5324
5331
|
return /require\(\s*["']zirka["']\s*\)/.test(sourceCode.getText());
|
|
5325
5332
|
}
|
|
5326
5333
|
|
|
5334
|
+
// eslint/rules/documentation/helpers.ts
|
|
5335
|
+
import path44 from "path";
|
|
5336
|
+
|
|
5327
5337
|
// constants/rfc2119.ts
|
|
5328
5338
|
var RFC_2119_KEYWORDS = ["MUST NOT", "MUST", "SHOULD NOT", "SHOULD", "MAY"];
|
|
5329
5339
|
var RFC_2119_PATTERN = new RegExp(`\\b(?<keyword>${RFC_2119_KEYWORDS.join("|")})\\b`);
|
|
@@ -5336,6 +5346,13 @@ function containsRfcKeyword(text) {
|
|
|
5336
5346
|
function getFilename(context) {
|
|
5337
5347
|
return context.filename;
|
|
5338
5348
|
}
|
|
5349
|
+
function isAgentDocument(filename) {
|
|
5350
|
+
const base = path44.basename(filename);
|
|
5351
|
+
return base === "AGENTS.md" || base === "CLAUDE.md";
|
|
5352
|
+
}
|
|
5353
|
+
function isDocumentationTemplate(filename) {
|
|
5354
|
+
return path44.basename(path44.dirname(filename)) === "_templates";
|
|
5355
|
+
}
|
|
5339
5356
|
function getTextContent(node) {
|
|
5340
5357
|
if ("value" in node && typeof node.value === "string") return node.value;
|
|
5341
5358
|
if ("children" in node) {
|
|
@@ -5369,7 +5386,7 @@ var docKindSuffixRule = {
|
|
|
5369
5386
|
return {
|
|
5370
5387
|
root(node) {
|
|
5371
5388
|
const filename = getFilename(context);
|
|
5372
|
-
if (!filename.endsWith(".md")) return;
|
|
5389
|
+
if (!filename.endsWith(".md") || isAgentDocument(filename) || isDocumentationTemplate(filename)) return;
|
|
5373
5390
|
if (filename.endsWith("-guide.md") || filename.endsWith("-rule.md") || filename.endsWith("-reference.md") || filename.endsWith("-policy.md")) {
|
|
5374
5391
|
return;
|
|
5375
5392
|
}
|
|
@@ -5400,7 +5417,7 @@ var titleMatchesFileNameRule = {
|
|
|
5400
5417
|
heading(node) {
|
|
5401
5418
|
if (node.depth !== 1) return;
|
|
5402
5419
|
const filename = getFilename(context);
|
|
5403
|
-
if (!filename.endsWith(".md")) return;
|
|
5420
|
+
if (!filename.endsWith(".md") || isAgentDocument(filename) || isDocumentationTemplate(filename)) return;
|
|
5404
5421
|
const title = getTextContent(node).trim();
|
|
5405
5422
|
const expectedFileName = toExpectedFileName(title);
|
|
5406
5423
|
const actualFileName = path45.basename(filename);
|
|
@@ -5680,12 +5697,16 @@ var rulePairedExamplesRule = {
|
|
|
5680
5697
|
if (!filename.endsWith("-rule.md")) return;
|
|
5681
5698
|
const exampleHeadings = [];
|
|
5682
5699
|
for (const child of node.children) {
|
|
5683
|
-
if (child.type
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5700
|
+
if (child.type !== "heading" || child.depth !== 2) continue;
|
|
5701
|
+
const text = getTextContent(child).trim();
|
|
5702
|
+
if (/^(?:Incorrect|Correct)\b/.test(text)) {
|
|
5703
|
+
exampleHeadings.push({ line: getLine(child), text });
|
|
5704
|
+
continue;
|
|
5688
5705
|
}
|
|
5706
|
+
context.report({
|
|
5707
|
+
node: child,
|
|
5708
|
+
message: `Rule level-2 heading must be an Incorrect/Correct example: ${text}`
|
|
5709
|
+
});
|
|
5689
5710
|
}
|
|
5690
5711
|
const incorrect = exampleHeadings.filter((h) => h.text.startsWith("Incorrect"));
|
|
5691
5712
|
const correct = exampleHeadings.filter((h) => h.text.startsWith("Correct"));
|
|
@@ -5826,7 +5847,7 @@ var referenceBlockHeadingsRule = {
|
|
|
5826
5847
|
return {
|
|
5827
5848
|
root(node) {
|
|
5828
5849
|
const filename = getFilename(context);
|
|
5829
|
-
if (!filename.endsWith("-reference.md")) return;
|
|
5850
|
+
if (!filename.endsWith("-reference.md") || isDocumentationTemplate(filename)) return;
|
|
5830
5851
|
const sectionHeadings = [];
|
|
5831
5852
|
for (const child of node.children) {
|
|
5832
5853
|
if (child.type === "heading" && child.depth >= 2) {
|
|
@@ -5900,7 +5921,7 @@ var supportDocumentPlacementRule = {
|
|
|
5900
5921
|
return {
|
|
5901
5922
|
root(node) {
|
|
5902
5923
|
const filename = getFilename(context);
|
|
5903
|
-
if (!filename.endsWith(".md")) return;
|
|
5924
|
+
if (!filename.endsWith(".md") || isDocumentationTemplate(filename)) return;
|
|
5904
5925
|
let kind;
|
|
5905
5926
|
if (filename.endsWith("-rule.md")) kind = "rule";
|
|
5906
5927
|
if (filename.endsWith("-reference.md")) kind = "reference";
|
|
@@ -5928,6 +5949,7 @@ var noTemplatePromptRule = {
|
|
|
5928
5949
|
}
|
|
5929
5950
|
},
|
|
5930
5951
|
create(context) {
|
|
5952
|
+
if (isDocumentationTemplate(getFilename(context))) return {};
|
|
5931
5953
|
return {
|
|
5932
5954
|
text(node) {
|
|
5933
5955
|
if (TEMPLATE_PROMPT.test(node.value)) {
|
|
@@ -5945,7 +5967,7 @@ var noTemplatePromptRule = {
|
|
|
5945
5967
|
import path48 from "path";
|
|
5946
5968
|
|
|
5947
5969
|
// eslint/rules/documentation/project-index.ts
|
|
5948
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
5970
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
|
|
5949
5971
|
import path47 from "path";
|
|
5950
5972
|
var KIND_BY_SUFFIX = [
|
|
5951
5973
|
["-rule.md", "rule"],
|
|
@@ -5956,14 +5978,14 @@ var KIND_BY_SUFFIX = [
|
|
|
5956
5978
|
function listMarkdownFiles(dir) {
|
|
5957
5979
|
return readdirSync3(dir).flatMap((entry) => {
|
|
5958
5980
|
const entryPath = path47.join(dir, entry);
|
|
5959
|
-
if (
|
|
5981
|
+
if (statSync3(entryPath).isDirectory()) {
|
|
5960
5982
|
return entry.startsWith("_") ? [] : listMarkdownFiles(entryPath);
|
|
5961
5983
|
}
|
|
5962
5984
|
return entry.endsWith(".md") ? [entryPath] : [];
|
|
5963
5985
|
});
|
|
5964
5986
|
}
|
|
5965
5987
|
function extractTitle(filePath) {
|
|
5966
|
-
const content =
|
|
5988
|
+
const content = readFileSync6(filePath, "utf8");
|
|
5967
5989
|
const match = /^# (?<title>.+)$/m.exec(content);
|
|
5968
5990
|
return match?.groups?.title?.trim() ?? "";
|
|
5969
5991
|
}
|
|
@@ -5989,7 +6011,7 @@ function getProjectDocs(docsRoot) {
|
|
|
5989
6011
|
function findDocsRoot(filePath) {
|
|
5990
6012
|
let dir = path47.dirname(filePath);
|
|
5991
6013
|
for (; ; ) {
|
|
5992
|
-
if (path47.basename(dir) === "docs" &&
|
|
6014
|
+
if (path47.basename(dir) === "docs" && statSync3(dir).isDirectory()) {
|
|
5993
6015
|
return dir;
|
|
5994
6016
|
}
|
|
5995
6017
|
const parent = path47.dirname(dir);
|
|
@@ -6166,7 +6188,7 @@ var policySubjectHeadingsRule = {
|
|
|
6166
6188
|
};
|
|
6167
6189
|
|
|
6168
6190
|
// eslint/rules/documentation/guide-link-anchors.ts
|
|
6169
|
-
import { existsSync as existsSync3, readFileSync as
|
|
6191
|
+
import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
|
|
6170
6192
|
import path49 from "path";
|
|
6171
6193
|
function visitSteps2(node, check) {
|
|
6172
6194
|
if (node.type === "list" && node.ordered) {
|
|
@@ -6197,7 +6219,7 @@ function documentAnchors(filePath) {
|
|
|
6197
6219
|
anchorsByFile.set(filePath, anchors);
|
|
6198
6220
|
let content;
|
|
6199
6221
|
try {
|
|
6200
|
-
content =
|
|
6222
|
+
content = readFileSync7(filePath, "utf8");
|
|
6201
6223
|
} catch {
|
|
6202
6224
|
return anchors;
|
|
6203
6225
|
}
|
|
@@ -6296,7 +6318,7 @@ var noNestedHowToRule = {
|
|
|
6296
6318
|
};
|
|
6297
6319
|
|
|
6298
6320
|
// eslint/rules/documentation/glossary-term-linking.ts
|
|
6299
|
-
import { readFileSync as
|
|
6321
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
6300
6322
|
import path50 from "path";
|
|
6301
6323
|
function isGlossary(filePath) {
|
|
6302
6324
|
return path50.basename(filePath).includes("glossary");
|
|
@@ -6317,7 +6339,7 @@ function extractTableTerms(content) {
|
|
|
6317
6339
|
}
|
|
6318
6340
|
function extractGlossaryTerms(filePath) {
|
|
6319
6341
|
if (!isGlossary(filePath)) return [];
|
|
6320
|
-
const content =
|
|
6342
|
+
const content = readFileSync8(filePath, "utf8");
|
|
6321
6343
|
const tableTerms = extractTableTerms(content);
|
|
6322
6344
|
if (tableTerms.length > 0) return tableTerms;
|
|
6323
6345
|
const terms = [];
|
|
@@ -6331,7 +6353,7 @@ function extractGlossaryTerms(filePath) {
|
|
|
6331
6353
|
function extractBlockHeadings(filePath) {
|
|
6332
6354
|
const headings = [];
|
|
6333
6355
|
let fenced = false;
|
|
6334
|
-
for (const line of
|
|
6356
|
+
for (const line of readFileSync8(filePath, "utf8").split("\n")) {
|
|
6335
6357
|
if (/^\s*(?:```|~~~)/.test(line)) {
|
|
6336
6358
|
fenced = !fenced;
|
|
6337
6359
|
continue;
|
|
@@ -6641,6 +6663,11 @@ function preludeIdentifiers(node) {
|
|
|
6641
6663
|
});
|
|
6642
6664
|
return names;
|
|
6643
6665
|
}
|
|
6666
|
+
function rawValue(node) {
|
|
6667
|
+
if (!node) return "";
|
|
6668
|
+
if (node.type === "Raw") return node.value;
|
|
6669
|
+
return "";
|
|
6670
|
+
}
|
|
6644
6671
|
function rules(node) {
|
|
6645
6672
|
const result = [];
|
|
6646
6673
|
walkNodes(node, (current) => {
|
|
@@ -6988,39 +7015,40 @@ var customUtilityApplyRule = {
|
|
|
6988
7015
|
}
|
|
6989
7016
|
};
|
|
6990
7017
|
|
|
6991
|
-
// eslint/rules/tailwind/
|
|
6992
|
-
|
|
7018
|
+
// eslint/rules/tailwind/utility-mapping.ts
|
|
7019
|
+
function applyOperationCount(utility) {
|
|
7020
|
+
let count = 0;
|
|
7021
|
+
for (const apply of atrulesNamed(utility, "apply")) {
|
|
7022
|
+
const identifiers = preludeIdentifiers(apply);
|
|
7023
|
+
if (identifiers.length > 0) {
|
|
7024
|
+
count += identifiers.length;
|
|
7025
|
+
continue;
|
|
7026
|
+
}
|
|
7027
|
+
const prelude = "prelude" in apply ? apply.prelude : void 0;
|
|
7028
|
+
const raw = prelude ? rawValue(prelude) : "";
|
|
7029
|
+
const rawOperations = raw.trim().split(/\s+/).filter(Boolean);
|
|
7030
|
+
count += rawOperations.length > 0 ? rawOperations.length : 1;
|
|
7031
|
+
}
|
|
7032
|
+
return count;
|
|
7033
|
+
}
|
|
7034
|
+
var utilityMappingRule = {
|
|
6993
7035
|
meta: {
|
|
6994
7036
|
schema: [],
|
|
6995
7037
|
type: "problem",
|
|
6996
7038
|
docs: {
|
|
6997
|
-
description: "Require
|
|
7039
|
+
description: "Require custom utilities to map exactly one Tailwind styling operation."
|
|
6998
7040
|
}
|
|
6999
7041
|
},
|
|
7000
7042
|
create(context) {
|
|
7001
7043
|
return {
|
|
7002
7044
|
"StyleSheet:exit"(node) {
|
|
7003
7045
|
for (const utility of atrulesNamed(node, "utility")) {
|
|
7004
|
-
const name = preludeIdentifiers(utility)[0];
|
|
7005
|
-
const
|
|
7006
|
-
if (
|
|
7046
|
+
const name = preludeIdentifiers(utility)[0] ?? "unknown";
|
|
7047
|
+
const operationCount = applyOperationCount(utility);
|
|
7048
|
+
if (operationCount === 1) continue;
|
|
7007
7049
|
context.report({
|
|
7008
7050
|
node: utility,
|
|
7009
|
-
message: `Custom utility "${name
|
|
7010
|
-
});
|
|
7011
|
-
}
|
|
7012
|
-
const combinations = /* @__PURE__ */ new Map();
|
|
7013
|
-
for (const apply of atrulesNamed(node, "apply")) {
|
|
7014
|
-
const classes = preludeIdentifiers(apply);
|
|
7015
|
-
if (new Set(classes).size < 2) continue;
|
|
7016
|
-
const key = [...classes].sort().join(" ");
|
|
7017
|
-
combinations.set(key, (combinations.get(key) ?? 0) + 1);
|
|
7018
|
-
}
|
|
7019
|
-
for (const [combo, count] of combinations) {
|
|
7020
|
-
if (count < 2) continue;
|
|
7021
|
-
context.report({
|
|
7022
|
-
node,
|
|
7023
|
-
message: `Combination "${combo}" appears ${String(count)} times. Create a *-skin custom Tailwind utility for it.`
|
|
7051
|
+
message: `Custom utility "${name}" maps ${String(operationCount)} Tailwind operations; custom utilities must map exactly one operation. Reusable presentation belongs in a component.`
|
|
7024
7052
|
});
|
|
7025
7053
|
}
|
|
7026
7054
|
}
|
|
@@ -7068,11 +7096,11 @@ var themeVariableNamespaceRule = {
|
|
|
7068
7096
|
};
|
|
7069
7097
|
|
|
7070
7098
|
// eslint/rules/tailwind/css-entry-point.ts
|
|
7071
|
-
import { statSync as
|
|
7099
|
+
import { statSync as statSync5 } from "fs";
|
|
7072
7100
|
import path54 from "path";
|
|
7073
7101
|
|
|
7074
7102
|
// eslint/rules/tailwind/source-files.ts
|
|
7075
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
7103
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync4 } from "fs";
|
|
7076
7104
|
import path52 from "path";
|
|
7077
7105
|
var CSS_EXTENSIONS = [".css"];
|
|
7078
7106
|
var MODULE_EXTENSIONS3 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
@@ -7089,7 +7117,7 @@ function findFiles(dir, extensions) {
|
|
|
7089
7117
|
const entryPath = path52.join(dir, entry);
|
|
7090
7118
|
let stats;
|
|
7091
7119
|
try {
|
|
7092
|
-
stats =
|
|
7120
|
+
stats = statSync4(entryPath);
|
|
7093
7121
|
} catch {
|
|
7094
7122
|
return [];
|
|
7095
7123
|
}
|
|
@@ -7103,7 +7131,7 @@ function cachedTextReader() {
|
|
|
7103
7131
|
let text = texts.get(file);
|
|
7104
7132
|
if (text === void 0) {
|
|
7105
7133
|
try {
|
|
7106
|
-
text =
|
|
7134
|
+
text = readFileSync9(file, "utf8");
|
|
7107
7135
|
} catch {
|
|
7108
7136
|
text = "";
|
|
7109
7137
|
}
|
|
@@ -7182,7 +7210,7 @@ var cssEntryPointRule = {
|
|
|
7182
7210
|
let cssFiles;
|
|
7183
7211
|
let moduleFiles;
|
|
7184
7212
|
try {
|
|
7185
|
-
if (!
|
|
7213
|
+
if (!statSync5(sourceRoot).isDirectory()) return {};
|
|
7186
7214
|
cssFiles = findFiles(sourceRoot, CSS_EXTENSIONS);
|
|
7187
7215
|
moduleFiles = findFiles(sourceRoot, MODULE_EXTENSIONS3);
|
|
7188
7216
|
} catch {
|
|
@@ -7270,7 +7298,7 @@ var globalStylesheetRule = {
|
|
|
7270
7298
|
};
|
|
7271
7299
|
|
|
7272
7300
|
// eslint/rules/tailwind/unused-utility.ts
|
|
7273
|
-
import { statSync as
|
|
7301
|
+
import { statSync as statSync6 } from "fs";
|
|
7274
7302
|
function usagePattern(name) {
|
|
7275
7303
|
return new RegExp(`(?<![\\w-])${escapeRegExp(name)}(?![\\w-])`);
|
|
7276
7304
|
}
|
|
@@ -7286,7 +7314,7 @@ var unusedUtilityRule = {
|
|
|
7286
7314
|
const sourceRoot = sourceRootOf(context);
|
|
7287
7315
|
let files;
|
|
7288
7316
|
try {
|
|
7289
|
-
if (!
|
|
7317
|
+
if (!statSync6(sourceRoot).isDirectory()) return {};
|
|
7290
7318
|
files = findFiles(sourceRoot, SOURCE_EXTENSIONS);
|
|
7291
7319
|
} catch {
|
|
7292
7320
|
return {};
|
|
@@ -7311,48 +7339,6 @@ var unusedUtilityRule = {
|
|
|
7311
7339
|
}
|
|
7312
7340
|
};
|
|
7313
7341
|
|
|
7314
|
-
// eslint/rules/tailwind/single-use-utility.ts
|
|
7315
|
-
import { statSync as statSync8 } from "fs";
|
|
7316
|
-
function usagePattern2(name) {
|
|
7317
|
-
return new RegExp(`(?<![\\\\w-])${escapeRegExp(name)}(?![\\\\w-])`);
|
|
7318
|
-
}
|
|
7319
|
-
var singleUseUtilityRule = {
|
|
7320
|
-
meta: {
|
|
7321
|
-
schema: [],
|
|
7322
|
-
type: "problem",
|
|
7323
|
-
docs: {
|
|
7324
|
-
description: "Disallow custom utilities referenced by only one source file."
|
|
7325
|
-
}
|
|
7326
|
-
},
|
|
7327
|
-
create(context) {
|
|
7328
|
-
const sourceRoot = sourceRootOf(context);
|
|
7329
|
-
let files;
|
|
7330
|
-
try {
|
|
7331
|
-
if (!statSync8(sourceRoot).isDirectory()) return {};
|
|
7332
|
-
files = findFiles(sourceRoot, SOURCE_EXTENSIONS);
|
|
7333
|
-
} catch {
|
|
7334
|
-
return {};
|
|
7335
|
-
}
|
|
7336
|
-
const textOf = cachedTextReader();
|
|
7337
|
-
return {
|
|
7338
|
-
"StyleSheet:exit"(node) {
|
|
7339
|
-
for (const utility of atrulesNamed(node, "utility")) {
|
|
7340
|
-
const name = preludeIdentifiers(utility)[0];
|
|
7341
|
-
if (!name) continue;
|
|
7342
|
-
const pattern = usagePattern2(name);
|
|
7343
|
-
const definition = `@utility ${name}`;
|
|
7344
|
-
const consumers = files.filter((file) => pattern.test(textOf(file).replaceAll(definition, "")));
|
|
7345
|
-
if (consumers.length !== 1) continue;
|
|
7346
|
-
context.report({
|
|
7347
|
-
node: utility,
|
|
7348
|
-
message: `Custom utility "${name}" is used by only one source file; keep that styling as static Tailwind classes in its consumer.`
|
|
7349
|
-
});
|
|
7350
|
-
}
|
|
7351
|
-
}
|
|
7352
|
-
};
|
|
7353
|
-
}
|
|
7354
|
-
};
|
|
7355
|
-
|
|
7356
7342
|
// eslint/rules/tailwind/global-selector-styling.ts
|
|
7357
7343
|
function hasStyling(node) {
|
|
7358
7344
|
for (const child of blockChildren2(node)) {
|
|
@@ -7394,12 +7380,11 @@ var tailwindRules = {
|
|
|
7394
7380
|
"stylesheet-ordering": stylesheetOrderingRule,
|
|
7395
7381
|
"css-variable-naming": cssVariableNamingRule,
|
|
7396
7382
|
"custom-utility-apply": customUtilityApplyRule,
|
|
7397
|
-
"
|
|
7383
|
+
"utility-mapping": utilityMappingRule,
|
|
7398
7384
|
"theme-variable-namespace": themeVariableNamespaceRule,
|
|
7399
7385
|
"css-entry-point": cssEntryPointRule,
|
|
7400
7386
|
"global-stylesheet": globalStylesheetRule,
|
|
7401
7387
|
"unused-utility": unusedUtilityRule,
|
|
7402
|
-
"single-use-utility": singleUseUtilityRule,
|
|
7403
7388
|
"global-selector-styling": globalSelectorStylingRule
|
|
7404
7389
|
};
|
|
7405
7390
|
|
|
@@ -7618,7 +7603,7 @@ var nextjsStackRule = {
|
|
|
7618
7603
|
};
|
|
7619
7604
|
|
|
7620
7605
|
// eslint/rules/package-json/vitest-coverage.ts
|
|
7621
|
-
import { existsSync as existsSync5, readFileSync as
|
|
7606
|
+
import { existsSync as existsSync5, readFileSync as readFileSync10 } from "fs";
|
|
7622
7607
|
import path55 from "path";
|
|
7623
7608
|
function memberName4(member) {
|
|
7624
7609
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
@@ -7696,7 +7681,7 @@ var vitestCoverageRule = {
|
|
|
7696
7681
|
});
|
|
7697
7682
|
return;
|
|
7698
7683
|
}
|
|
7699
|
-
const content =
|
|
7684
|
+
const content = readFileSync10(path55.join(context.cwd, configName), "utf8");
|
|
7700
7685
|
for (const metric of THRESHOLD_METRICS) {
|
|
7701
7686
|
if (!new RegExp(`\\b${metric}\\s*:\\s*[1-9]\\d*`).test(content)) {
|
|
7702
7687
|
context.report({ node, message: `${configName} must set a coverage threshold above zero for ${metric}.` });
|
|
@@ -7742,7 +7727,7 @@ var nextjsPackageJsonRules = {
|
|
|
7742
7727
|
};
|
|
7743
7728
|
|
|
7744
7729
|
// eslint/rules/husky/husky-hook.ts
|
|
7745
|
-
import { existsSync as existsSync6, readFileSync as
|
|
7730
|
+
import { existsSync as existsSync6, readFileSync as readFileSync11 } from "fs";
|
|
7746
7731
|
import path56 from "path";
|
|
7747
7732
|
var VITEST_CONFIG_NAMES2 = [
|
|
7748
7733
|
"vitest.config.ts",
|
|
@@ -7777,7 +7762,7 @@ var huskyHookRule = {
|
|
|
7777
7762
|
});
|
|
7778
7763
|
return;
|
|
7779
7764
|
}
|
|
7780
|
-
const content =
|
|
7765
|
+
const content = readFileSync11(hookPath, "utf8");
|
|
7781
7766
|
const scripts = root.members.find((member) => memberName5(member) === "scripts");
|
|
7782
7767
|
const scriptNames = new Set(scripts?.value.type === "Object" ? scripts.value.members.map(memberName5) : []);
|
|
7783
7768
|
const requireNamedScript = (name) => {
|
|
@@ -7839,7 +7824,7 @@ var huskyRules = {
|
|
|
7839
7824
|
};
|
|
7840
7825
|
|
|
7841
7826
|
// eslint/rules/vulyk/tracked-docs.ts
|
|
7842
|
-
import { existsSync as existsSync7, readFileSync as
|
|
7827
|
+
import { existsSync as existsSync7, readFileSync as readFileSync12 } from "fs";
|
|
7843
7828
|
import path57 from "path";
|
|
7844
7829
|
var PASIKA_REPO = "Bredansky/pasika";
|
|
7845
7830
|
var BASE_REQUIRED_TRACKED_DOCS = [
|
|
@@ -7882,7 +7867,7 @@ var trackedDocsRule = {
|
|
|
7882
7867
|
});
|
|
7883
7868
|
return;
|
|
7884
7869
|
}
|
|
7885
|
-
const config =
|
|
7870
|
+
const config = readFileSync12(configPath, "utf8");
|
|
7886
7871
|
if (!config.includes(PASIKA_REPO)) {
|
|
7887
7872
|
context.report({
|
|
7888
7873
|
node,
|
|
@@ -7989,6 +7974,7 @@ var pasikaNextjsAppRules = {
|
|
|
7989
7974
|
"ui-state": uiStateRule,
|
|
7990
7975
|
"no-mixed-concerns": noMixedConcernsRule,
|
|
7991
7976
|
"no-arbitrary-tailwind": noArbitraryTailwindRule,
|
|
7977
|
+
"no-literal-inline-style": noLiteralInlineStyleRule,
|
|
7992
7978
|
"unknown-utility": unknownUtilityRule,
|
|
7993
7979
|
"enforce-cn-merge": enforceCnMergeRule,
|
|
7994
7980
|
"cn-helper": cnHelperRule,
|
|
@@ -8011,7 +7997,6 @@ var pasikaNextjsAppRules = {
|
|
|
8011
7997
|
"locale-placement": localePlacementRule,
|
|
8012
7998
|
"sole-state-owner": soleStateOwnerRule,
|
|
8013
7999
|
"locale-key-shape": localeKeyShapeRule,
|
|
8014
|
-
"shared-style-dedup": sharedStyleDedupRule,
|
|
8015
8000
|
"repeated-structure": repeatedStructureRule
|
|
8016
8001
|
};
|
|
8017
8002
|
var pasikaPlugin = {
|
|
@@ -8108,10 +8093,6 @@ var zirkaConfig = {
|
|
|
8108
8093
|
};
|
|
8109
8094
|
var documentationConfig = {
|
|
8110
8095
|
files: ["docs/**/*.md"],
|
|
8111
|
-
// vulyk-generated agent files are not authored docs: with per-directory
|
|
8112
|
-
// targets they can land under docs/ (e.g. docs/AGENTS.md) and must not be
|
|
8113
|
-
// held to the documentation guide.
|
|
8114
|
-
ignores: ["**/_*/**", "**/AGENTS.md", "**/CLAUDE.md"],
|
|
8115
8096
|
plugins: {
|
|
8116
8097
|
markdown,
|
|
8117
8098
|
pasika: pasikaPlugin
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pasika",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.32",
|
|
4
4
|
"description": "Reusable agent setup package",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"tsx": "4.23.12",
|
|
89
89
|
"typescript": "6.0.3",
|
|
90
90
|
"vitest": "5.0.0",
|
|
91
|
+
"vulyk": "0.15.1",
|
|
91
92
|
"zirka": "0.0.65",
|
|
92
93
|
"zod": "4.4.3"
|
|
93
94
|
},
|