@webpieces/eslint-rules 0.4.716 → 0.4.718
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/README.md
CHANGED
|
@@ -7,7 +7,7 @@ ESLint rules for WebPieces code patterns and architecture enforcement.
|
|
|
7
7
|
- `catch-error-pattern` - Enforce toError() usage in catch blocks
|
|
8
8
|
- `no-unmanaged-exceptions` - Discourage try-catch outside tests
|
|
9
9
|
- `max-method-lines` - Enforce maximum method length (test-framework container callbacks such as `describe(...)` are exempt in `*.spec.ts` / `*.test.ts` — see below)
|
|
10
|
-
- `max-file-lines` - Enforce maximum file length
|
|
10
|
+
- `max-file-lines` - Enforce maximum file length (machine-generated trees are exempt with no config; `allowedPaths` adds your own un-authored trees)
|
|
11
11
|
- `enforce-architecture` - Enforce architecture dependency boundaries
|
|
12
12
|
- `no-json-property-primitive-type` - Ban @JsonProperty({ type: String/Number/Boolean })
|
|
13
13
|
- `require-typed-template` - Require [templateClassType] on ng-template with let- variables (Angular)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/eslint-rules",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.718",
|
|
4
4
|
"description": "ESLint rules for WebPieces code patterns and architecture enforcement",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"directory": "packages/tooling/eslint-rules"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@webpieces/rules-config": "0.4.
|
|
25
|
+
"@webpieces/rules-config": "0.4.718"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"eslint": ">=8.0.0"
|
|
@@ -5,7 +5,13 @@
|
|
|
5
5
|
* Default: 700 lines
|
|
6
6
|
*
|
|
7
7
|
* Configuration:
|
|
8
|
-
* '@webpieces/max-file-lines': ['error', { max: 700 }]
|
|
8
|
+
* '@webpieces/max-file-lines': ['error', { max: 700, allowedPaths: ['vendor-glob-here'] }]
|
|
9
|
+
*
|
|
10
|
+
* Machine-generated trees (the GENERATED_CODE_PATHS list in @webpieces/rules-config: __generated__
|
|
11
|
+
* and generated directories at any depth, .generated.ts / .generated.tsx files, and dist) are exempt
|
|
12
|
+
* with NO configuration, and `allowedPaths` ADDS your own un-authored trees to that floor — the same
|
|
13
|
+
* exemption the edit-time hook and the build-time validator apply, so one engine cannot pass a file
|
|
14
|
+
* the next one blocks. Never list hand-written code there; a long file you wrote gets refactored.
|
|
9
15
|
*/
|
|
10
16
|
import type { Rule } from 'eslint';
|
|
11
17
|
declare const rule: Rule.RuleModule;
|
|
@@ -6,8 +6,16 @@
|
|
|
6
6
|
* Default: 700 lines
|
|
7
7
|
*
|
|
8
8
|
* Configuration:
|
|
9
|
-
* '@webpieces/max-file-lines': ['error', { max: 700 }]
|
|
9
|
+
* '@webpieces/max-file-lines': ['error', { max: 700, allowedPaths: ['vendor-glob-here'] }]
|
|
10
|
+
*
|
|
11
|
+
* Machine-generated trees (the GENERATED_CODE_PATHS list in @webpieces/rules-config: __generated__
|
|
12
|
+
* and generated directories at any depth, .generated.ts / .generated.tsx files, and dist) are exempt
|
|
13
|
+
* with NO configuration, and `allowedPaths` ADDS your own un-authored trees to that floor — the same
|
|
14
|
+
* exemption the edit-time hook and the build-time validator apply, so one engine cannot pass a file
|
|
15
|
+
* the next one blocks. Never list hand-written code there; a long file you wrote gets refactored.
|
|
10
16
|
*/
|
|
17
|
+
const tslib_1 = require("tslib");
|
|
18
|
+
const path = tslib_1.__importStar(require("path"));
|
|
11
19
|
const rules_config_1 = require("@webpieces/rules-config");
|
|
12
20
|
const toError_1 = require("../toError");
|
|
13
21
|
const workspace_root_1 = require("../workspace-root");
|
|
@@ -50,6 +58,10 @@ const rule = {
|
|
|
50
58
|
type: 'integer',
|
|
51
59
|
minimum: 1,
|
|
52
60
|
},
|
|
61
|
+
allowedPaths: {
|
|
62
|
+
type: 'array',
|
|
63
|
+
items: { type: 'string' },
|
|
64
|
+
},
|
|
53
65
|
},
|
|
54
66
|
additionalProperties: false,
|
|
55
67
|
},
|
|
@@ -58,6 +70,21 @@ const rule = {
|
|
|
58
70
|
create(context) {
|
|
59
71
|
const options = context.options[0];
|
|
60
72
|
const maxLines = options?.max ?? 700;
|
|
73
|
+
// Machine-generated trees are exempt with no configuration, exactly as they are in the
|
|
74
|
+
// edit-time hook and the build-time validator — an exemption honoured by one engine and
|
|
75
|
+
// ignored by another is the same file passing here and blocking there. `allowedPaths` adds
|
|
76
|
+
// to that floor; it is for files this repo did not author, never for hand-written code.
|
|
77
|
+
const filename = context.filename || context.getFilename();
|
|
78
|
+
const relPath = path.relative(workspace.workspaceRoot(context), filename);
|
|
79
|
+
// Normally the workspace-relative path is what the globs are written against. When root
|
|
80
|
+
// resolution degenerates (no repo root above the file, or the file sits outside it) that path
|
|
81
|
+
// is a bare basename or a `../` climb and would hide a `**/__generated__/**` match, so the
|
|
82
|
+
// absolute path is judged instead — never in addition, so a repo checked out under a directory
|
|
83
|
+
// named `dist` or `generated` is not exempted wholesale.
|
|
84
|
+
const rooted = relPath !== '' && !relPath.startsWith('..') && relPath.includes(path.sep);
|
|
85
|
+
const judged = rooted ? relPath : filename;
|
|
86
|
+
if ((0, rules_config_1.isPathExcluded)(judged, [...rules_config_1.GENERATED_CODE_PATHS, ...(options?.allowedPaths ?? [])]))
|
|
87
|
+
return {};
|
|
61
88
|
return {
|
|
62
89
|
// webpieces-disable no-any-unknown -- ESTree AST nodes require any for dynamic properties
|
|
63
90
|
Program(node) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"max-file-lines.js","sourceRoot":"","sources":["../../../../../../packages/tooling/eslint-rules/src/rules/max-file-lines.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"max-file-lines.js","sourceRoot":"","sources":["../../../../../../packages/tooling/eslint-rules/src/rules/max-file-lines.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ESLint rule to enforce maximum file length\n *\n * Enforces a configurable maximum line count for files.\n * Default: 700 lines\n *\n * Configuration:\n * '@webpieces/max-file-lines': ['error', { max: 700, allowedPaths: ['vendor-glob-here'] }]\n *\n * Machine-generated trees (the GENERATED_CODE_PATHS list in @webpieces/rules-config: __generated__\n * and generated directories at any depth, .generated.ts / .generated.tsx files, and dist) are exempt\n * with NO configuration, and `allowedPaths` ADDS your own un-authored trees to that floor — the same\n * exemption the edit-time hook and the build-time validator apply, so one engine cannot pass a file\n * the next one blocks. Never list hand-written code there; a long file you wrote gets refactored.\n */\n\nimport type { Rule } from 'eslint';\nimport * as path from 'path';\nimport { writeTemplateIfMissing, isPathExcluded, GENERATED_CODE_PATHS } from '@webpieces/rules-config';\nimport { toError } from '../toError';\nimport { EslintWorkspaceRoot } from '../workspace-root';\n\nconst INSTRUCT_FILE = 'webpieces.filesize.md';\nconst workspace = new EslintWorkspaceRoot();\n\ninterface FileLinesOptions {\n max: number;\n allowedPaths?: string[];\n}\n\n// Module-level flag to prevent redundant file creation\nlet fileDocCreated = false;\n\nfunction ensureFileDoc(context: Rule.RuleContext): void {\n if (fileDocCreated) return;\n const workspaceRoot = workspace.workspaceRoot(context);\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n writeTemplateIfMissing(workspaceRoot, INSTRUCT_FILE);\n fileDocCreated = true;\n } catch (err: unknown) {\n const error = toError(err);\n console.warn('[webpieces] Could not write webpieces.filesize.md', error);\n }\n}\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Enforce maximum file length',\n category: 'Best Practices',\n recommended: false,\n url: 'https://github.com/deanhiller/webpieces-ts',\n },\n messages: {\n tooLong:\n 'AI Agent: READ .webpieces/instruct-ai/webpieces.filesize.md (at the repo root) for fix instructions. File has {{actual}} lines (max: {{max}})',\n },\n fixable: undefined,\n schema: [\n {\n type: 'object',\n properties: {\n max: {\n type: 'integer',\n minimum: 1,\n },\n allowedPaths: {\n type: 'array',\n items: { type: 'string' },\n },\n },\n additionalProperties: false,\n },\n ],\n },\n\n create(context: Rule.RuleContext): Rule.RuleListener {\n const options = context.options[0] as FileLinesOptions | undefined;\n const maxLines = options?.max ?? 700;\n\n // Machine-generated trees are exempt with no configuration, exactly as they are in the\n // edit-time hook and the build-time validator — an exemption honoured by one engine and\n // ignored by another is the same file passing here and blocking there. `allowedPaths` adds\n // to that floor; it is for files this repo did not author, never for hand-written code.\n const filename = context.filename || context.getFilename();\n const relPath = path.relative(workspace.workspaceRoot(context), filename);\n // Normally the workspace-relative path is what the globs are written against. When root\n // resolution degenerates (no repo root above the file, or the file sits outside it) that path\n // is a bare basename or a `../` climb and would hide a `**/__generated__/**` match, so the\n // absolute path is judged instead — never in addition, so a repo checked out under a directory\n // named `dist` or `generated` is not exempted wholesale.\n const rooted = relPath !== '' && !relPath.startsWith('..') && relPath.includes(path.sep);\n const judged = rooted ? relPath : filename;\n if (isPathExcluded(judged, [...GENERATED_CODE_PATHS, ...(options?.allowedPaths ?? [])])) return {};\n\n return {\n // webpieces-disable no-any-unknown -- ESTree AST nodes require any for dynamic properties\n Program(node: any): void {\n ensureFileDoc(context);\n\n const sourceCode = context.sourceCode || context.getSourceCode();\n const lines = sourceCode.lines;\n const lineCount = lines.length;\n\n if (lineCount > maxLines) {\n context.report({\n node,\n messageId: 'tooLong',\n data: {\n actual: String(lineCount),\n max: String(maxLines),\n },\n });\n }\n },\n };\n },\n};\n\nexport = rule;\n"]}
|