invar-tools 1.17.2__py3-none-any.whl → 1.17.3__py3-none-any.whl

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.
Files changed (58) hide show
  1. invar/node_tools/.gitignore +10 -6
  2. invar/node_tools/eslint-plugin/rules/__tests__/behavior.test.js +1321 -0
  3. invar/node_tools/eslint-plugin/rules/__tests__/behavior.test.js.map +1 -0
  4. invar/node_tools/eslint-plugin/rules/__tests__/e2e-scenarios.test.js +414 -0
  5. invar/node_tools/eslint-plugin/rules/__tests__/e2e-scenarios.test.js.map +1 -0
  6. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/core/function-lengths.js +142 -0
  7. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/core/function-lengths.js.map +1 -0
  8. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/core/has-io-imports.js +15 -0
  9. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/core/has-io-imports.js.map +1 -0
  10. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/core/valid-small.js +27 -0
  11. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/core/valid-small.js.map +1 -0
  12. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/exported-functions.js +43 -0
  13. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/exported-functions.js.map +1 -0
  14. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/shell/with-io.js +27 -0
  15. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/shell/with-io.js.map +1 -0
  16. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/tests/large.test.js +260 -0
  17. invar/node_tools/eslint-plugin/rules/__tests__/fixtures/tests/large.test.js.map +1 -0
  18. invar/node_tools/eslint-plugin/rules/max-file-lines.js +105 -0
  19. invar/node_tools/eslint-plugin/rules/max-file-lines.js.map +1 -0
  20. invar/node_tools/eslint-plugin/rules/max-function-lines.js +133 -0
  21. invar/node_tools/eslint-plugin/rules/max-function-lines.js.map +1 -0
  22. invar/node_tools/eslint-plugin/rules/no-any-in-schema.js +39 -0
  23. invar/node_tools/eslint-plugin/rules/no-any-in-schema.js.map +1 -0
  24. invar/node_tools/eslint-plugin/rules/no-empty-schema.js +69 -0
  25. invar/node_tools/eslint-plugin/rules/no-empty-schema.js.map +1 -0
  26. invar/node_tools/eslint-plugin/rules/no-impure-calls-in-core.js +52 -0
  27. invar/node_tools/eslint-plugin/rules/no-impure-calls-in-core.js.map +1 -0
  28. invar/node_tools/eslint-plugin/rules/no-io-in-core.js +99 -0
  29. invar/node_tools/eslint-plugin/rules/no-io-in-core.js.map +1 -0
  30. invar/node_tools/eslint-plugin/rules/no-pure-logic-in-shell.js +197 -0
  31. invar/node_tools/eslint-plugin/rules/no-pure-logic-in-shell.js.map +1 -0
  32. invar/node_tools/eslint-plugin/rules/no-redundant-type-schema.js +99 -0
  33. invar/node_tools/eslint-plugin/rules/no-redundant-type-schema.js.map +1 -0
  34. invar/node_tools/eslint-plugin/rules/no-runtime-imports.js +66 -0
  35. invar/node_tools/eslint-plugin/rules/no-runtime-imports.js.map +1 -0
  36. invar/node_tools/eslint-plugin/rules/require-complete-validation.js +104 -0
  37. invar/node_tools/eslint-plugin/rules/require-complete-validation.js.map +1 -0
  38. invar/node_tools/eslint-plugin/rules/require-jsdoc-example.js +81 -0
  39. invar/node_tools/eslint-plugin/rules/require-jsdoc-example.js.map +1 -0
  40. invar/node_tools/eslint-plugin/rules/require-schema-validation.js +308 -0
  41. invar/node_tools/eslint-plugin/rules/require-schema-validation.js.map +1 -0
  42. invar/node_tools/eslint-plugin/rules/shell-complexity.js +273 -0
  43. invar/node_tools/eslint-plugin/rules/shell-complexity.js.map +1 -0
  44. invar/node_tools/eslint-plugin/rules/shell-result-type.js +138 -0
  45. invar/node_tools/eslint-plugin/rules/shell-result-type.js.map +1 -0
  46. invar/node_tools/eslint-plugin/rules/thin-entry-points.js +174 -0
  47. invar/node_tools/eslint-plugin/rules/thin-entry-points.js.map +1 -0
  48. invar/node_tools/eslint-plugin/utils/layer-detection.js +91 -0
  49. invar/node_tools/eslint-plugin/utils/layer-detection.js.map +1 -0
  50. invar/node_tools/eslint-plugin/utils/math-example.js +31 -0
  51. invar/node_tools/eslint-plugin/utils/math-example.js.map +1 -0
  52. {invar_tools-1.17.2.dist-info → invar_tools-1.17.3.dist-info}/METADATA +1 -1
  53. {invar_tools-1.17.2.dist-info → invar_tools-1.17.3.dist-info}/RECORD +58 -8
  54. {invar_tools-1.17.2.dist-info → invar_tools-1.17.3.dist-info}/WHEEL +0 -0
  55. {invar_tools-1.17.2.dist-info → invar_tools-1.17.3.dist-info}/entry_points.txt +0 -0
  56. {invar_tools-1.17.2.dist-info → invar_tools-1.17.3.dist-info}/licenses/LICENSE +0 -0
  57. {invar_tools-1.17.2.dist-info → invar_tools-1.17.3.dist-info}/licenses/LICENSE-GPL +0 -0
  58. {invar_tools-1.17.2.dist-info → invar_tools-1.17.3.dist-info}/licenses/NOTICE +0 -0
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Rule: no-empty-schema
3
+ *
4
+ * Detect Zod schemas that match everything, providing false security.
5
+ *
6
+ * Detects:
7
+ * - z.object({}) with no properties
8
+ * - .passthrough() calls (defeats validation)
9
+ * - .loose() calls (ignores unknown properties)
10
+ */
11
+ export const noEmptySchema = {
12
+ meta: {
13
+ type: 'problem',
14
+ docs: {
15
+ description: 'Forbid empty or permissive Zod schemas that defeat validation',
16
+ recommended: true,
17
+ },
18
+ schema: [],
19
+ messages: {
20
+ emptyObject: 'Empty z.object({}) accepts any object. Add properties or use z.record()',
21
+ passthrough: 'Schema with .passthrough() bypasses unknown property validation. Remove or use .strict()',
22
+ loose: 'Schema with .loose() ignores unknown properties. Remove or use .strict()',
23
+ },
24
+ },
25
+ create(context) {
26
+ return {
27
+ CallExpression(node) {
28
+ const callee = node.callee;
29
+ // Check for z.object({})
30
+ if (callee.type === 'MemberExpression' &&
31
+ callee.object.type === 'Identifier' &&
32
+ callee.object.name === 'z' &&
33
+ callee.property.type === 'Identifier' &&
34
+ callee.property.name === 'object') {
35
+ const args = node.arguments;
36
+ if (args.length === 1 && args[0].type === 'ObjectExpression') {
37
+ const properties = args[0].properties;
38
+ if (properties.length === 0) {
39
+ context.report({
40
+ node: node,
41
+ messageId: 'emptyObject',
42
+ });
43
+ }
44
+ }
45
+ }
46
+ // Check for .passthrough() calls
47
+ if (callee.type === 'MemberExpression' &&
48
+ callee.property.type === 'Identifier' &&
49
+ callee.property.name === 'passthrough') {
50
+ context.report({
51
+ node: node,
52
+ messageId: 'passthrough',
53
+ });
54
+ }
55
+ // Check for .loose() calls
56
+ if (callee.type === 'MemberExpression' &&
57
+ callee.property.type === 'Identifier' &&
58
+ callee.property.name === 'loose') {
59
+ context.report({
60
+ node: node,
61
+ messageId: 'loose',
62
+ });
63
+ }
64
+ },
65
+ };
66
+ },
67
+ };
68
+ export default noEmptySchema;
69
+ //# sourceMappingURL=no-empty-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-empty-schema.js","sourceRoot":"","sources":["../../src/rules/no-empty-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,CAAC,MAAM,aAAa,GAAoB;IAC5C,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,+DAA+D;YAC5E,WAAW,EAAE,IAAI;SAClB;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,WAAW,EAAE,yEAAyE;YACtF,WAAW,EAAE,0FAA0F;YACvG,KAAK,EAAE,0EAA0E;SAClF;KACF;IAED,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,cAAc,CAAC,IAAI;gBACjB,MAAM,MAAM,GAAI,IAAuB,CAAC,MAAM,CAAC;gBAE/C,yBAAyB;gBACzB,IACE,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAClC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;oBACnC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,GAAG;oBAC1B,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,EACjC,CAAC;oBACD,MAAM,IAAI,GAAI,IAAuB,CAAC,SAAS,CAAC;oBAChD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;wBAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,UAAwB,CAAC;wBACpD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC5B,OAAO,CAAC,MAAM,CAAC;gCACb,IAAI,EAAE,IAA4B;gCAClC,SAAS,EAAE,aAAa;6BACzB,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,iCAAiC;gBACjC,IACE,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,aAAa,EACtC,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,IAA4B;wBAClC,SAAS,EAAE,aAAa;qBACzB,CAAC,CAAC;gBACL,CAAC;gBAED,2BAA2B;gBAC3B,IACE,MAAM,CAAC,IAAI,KAAK,kBAAkB;oBAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,YAAY;oBACrC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,EAChC,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,IAA4B;wBAClC,SAAS,EAAE,OAAO;qBACnB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Rule: no-impure-calls-in-core
3
+ *
4
+ * Forbid Core functions calling Shell functions.
5
+ * Core should be pure - no imports from shell/ directories.
6
+ *
7
+ * Detects:
8
+ * - Imports from ../shell/ in core/ files
9
+ * - Imports from shell/ in core/ files
10
+ */
11
+ export const noImpureCallsInCore = {
12
+ meta: {
13
+ type: 'problem',
14
+ docs: {
15
+ description: 'Forbid Core functions calling Shell functions (imports from shell/)',
16
+ recommended: true,
17
+ },
18
+ schema: [],
19
+ messages: {
20
+ shellImportInCore: 'Core file importing from Shell: "{{source}}". Core must be pure - move I/O logic to Shell or extract pure logic.',
21
+ },
22
+ },
23
+ create(context) {
24
+ const filename = context.filename || context.getFilename();
25
+ // Only check files in core/ directories
26
+ const isCore = /[/\\]core[/\\]/.test(filename);
27
+ if (!isCore) {
28
+ return {}; // Skip non-core files
29
+ }
30
+ return {
31
+ ImportDeclaration(node) {
32
+ const importNode = node;
33
+ if (importNode.source && importNode.source.type === 'Literal') {
34
+ const source = String(importNode.source.value);
35
+ // Check if importing from shell/
36
+ // Matches: ../shell/*, ../../shell/*, /shell/*, shell/*
37
+ if (/[/\\]shell[/\\]/.test(source) || /^shell[/\\]/.test(source)) {
38
+ context.report({
39
+ node: node,
40
+ messageId: 'shellImportInCore',
41
+ data: {
42
+ source: source,
43
+ },
44
+ });
45
+ }
46
+ }
47
+ },
48
+ };
49
+ },
50
+ };
51
+ export default noImpureCallsInCore;
52
+ //# sourceMappingURL=no-impure-calls-in-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-impure-calls-in-core.js","sourceRoot":"","sources":["../../src/rules/no-impure-calls-in-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,CAAC,MAAM,mBAAmB,GAAoB;IAClD,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,qEAAqE;YAClF,WAAW,EAAE,IAAI;SAClB;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,iBAAiB,EACf,kHAAkH;SACrH;KACF;IAED,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QAE3D,wCAAwC;QACxC,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC,CAAC,sBAAsB;QACnC,CAAC;QAED,OAAO;YACL,iBAAiB,CAAC,IAAI;gBACpB,MAAM,UAAU,GAAG,IAAoC,CAAC;gBAExD,IAAI,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;oBAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBAE/C,iCAAiC;oBACjC,wDAAwD;oBACxD,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;wBACjE,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI,EAAE,IAA4B;4BAClC,SAAS,EAAE,mBAAmB;4BAC9B,IAAI,EAAE;gCACJ,MAAM,EAAE,MAAM;6BACf;yBACF,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Rule: no-io-in-core
3
+ *
4
+ * Forbid I/O imports in /core/ directories.
5
+ * This enforces the Core/Shell separation pattern.
6
+ */
7
+ const IO_MODULES = new Set([
8
+ 'fs',
9
+ 'fs/promises',
10
+ 'node:fs',
11
+ 'node:fs/promises',
12
+ 'path',
13
+ 'node:path',
14
+ 'http',
15
+ 'https',
16
+ 'node:http',
17
+ 'node:https',
18
+ 'net',
19
+ 'node:net',
20
+ 'child_process',
21
+ 'node:child_process',
22
+ 'readline',
23
+ 'node:readline',
24
+ 'process',
25
+ 'node:process',
26
+ ]);
27
+ const IO_PACKAGE_PATTERNS = [
28
+ /^axios/,
29
+ /^node-fetch/,
30
+ /^got$/,
31
+ /^superagent/,
32
+ /^request/,
33
+ /^pg$/,
34
+ /^mysql/,
35
+ /^mongodb/,
36
+ /^redis/,
37
+ /^ioredis/,
38
+ /^@aws-sdk\//,
39
+ /^@vercel\//,
40
+ ];
41
+ function isIoModule(source) {
42
+ if (IO_MODULES.has(source))
43
+ return true;
44
+ return IO_PACKAGE_PATTERNS.some(pattern => pattern.test(source));
45
+ }
46
+ function isInCoreDirectory(filename) {
47
+ // Normalize to lowercase and forward slashes for consistent cross-platform matching
48
+ const normalized = filename.replace(/\\/g, '/').toLowerCase();
49
+ return normalized.includes('/core/');
50
+ }
51
+ export const noIoInCore = {
52
+ meta: {
53
+ type: 'problem',
54
+ docs: {
55
+ description: 'Forbid I/O imports in /core/ directories',
56
+ recommended: true,
57
+ },
58
+ schema: [],
59
+ messages: {
60
+ ioInCore: 'I/O module "{{module}}" is not allowed in /core/ directory. Move I/O to /shell/ or inject as parameter.',
61
+ },
62
+ },
63
+ create(context) {
64
+ const filename = context.filename || context.getFilename();
65
+ if (!isInCoreDirectory(filename)) {
66
+ return {};
67
+ }
68
+ return {
69
+ ImportDeclaration(node) {
70
+ const source = node.source.value;
71
+ if (typeof source === 'string' && isIoModule(source)) {
72
+ context.report({
73
+ node: node,
74
+ messageId: 'ioInCore',
75
+ data: { module: source },
76
+ });
77
+ }
78
+ },
79
+ CallExpression(node) {
80
+ // Check for require() calls
81
+ if (node.callee.type === 'Identifier' &&
82
+ node.callee.name === 'require' &&
83
+ node.arguments.length > 0 &&
84
+ node.arguments[0].type === 'Literal') {
85
+ const source = node.arguments[0].value;
86
+ if (typeof source === 'string' && isIoModule(source)) {
87
+ context.report({
88
+ node: node,
89
+ messageId: 'ioInCore',
90
+ data: { module: source },
91
+ });
92
+ }
93
+ }
94
+ },
95
+ };
96
+ },
97
+ };
98
+ export default noIoInCore;
99
+ //# sourceMappingURL=no-io-in-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-io-in-core.js","sourceRoot":"","sources":["../../src/rules/no-io-in-core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Rule: no-pure-logic-in-shell
3
+ *
4
+ * Warn when Shell functions contain pure logic that should be in Core.
5
+ * Shell functions should perform I/O operations, not pure computations.
6
+ *
7
+ * Heuristics for detecting pure logic:
8
+ * - No async/await usage
9
+ * - No I/O-related API calls (fs, http, fetch, db, etc.)
10
+ * - No Result type in return
11
+ * - Function body has more than 3 statements (substantial logic)
12
+ */
13
+ // I/O-related identifiers that indicate impure operations
14
+ // Note: Result/Success/Failure are NOT I/O indicators - they're just return type wrappers
15
+ // that can be used with pure logic. Only actual I/O operations should be listed here.
16
+ const IO_IDENTIFIERS = [
17
+ 'fs',
18
+ 'readFile',
19
+ 'writeFile',
20
+ 'fetch',
21
+ 'axios',
22
+ 'http',
23
+ 'https',
24
+ 'db',
25
+ 'database',
26
+ 'query',
27
+ 'execute',
28
+ 'readFileSync',
29
+ 'writeFileSync',
30
+ 'existsSync',
31
+ 'mkdir',
32
+ 'rmdir',
33
+ 'unlink',
34
+ 'readdir',
35
+ 'stat',
36
+ 'access',
37
+ 'net',
38
+ 'spawn',
39
+ 'exec',
40
+ 'execSync',
41
+ 'child_process',
42
+ 'WebSocket',
43
+ 'XMLHttpRequest',
44
+ 'request',
45
+ 'got',
46
+ 'console',
47
+ ];
48
+ export const noPureLogicInShell = {
49
+ meta: {
50
+ type: 'suggestion',
51
+ docs: {
52
+ description: 'Warn when Shell functions contain pure logic that should be in Core',
53
+ recommended: false,
54
+ },
55
+ schema: [],
56
+ messages: {
57
+ pureLogicInShell: 'Shell function "{{name}}" appears to contain pure logic. Consider moving to Core if it performs no I/O.',
58
+ },
59
+ },
60
+ create(context) {
61
+ const filename = context.filename || context.getFilename();
62
+ // Only check files in shell/ directories
63
+ const isShell = /[/\\]shell[/\\]/.test(filename);
64
+ if (!isShell) {
65
+ return {}; // Skip non-shell files
66
+ }
67
+ /**
68
+ * Check if function contains I/O indicators
69
+ */
70
+ function hasIOIndicators(node) {
71
+ let hasIO = false;
72
+ // Check if function is async
73
+ if (node.async) {
74
+ hasIO = true;
75
+ }
76
+ // Walk the function body looking for I/O-related identifiers
77
+ // Optimization: Limit depth and skip non-identifier containers
78
+ const MAX_DEPTH = 10; // Reduced from 50 for better performance
79
+ function visit(n, depth = 0) {
80
+ if (hasIO)
81
+ return; // Early return if already found
82
+ if (depth > MAX_DEPTH)
83
+ return; // Depth limit
84
+ // Performance: Check node type first
85
+ if (n.type === 'Identifier') {
86
+ if (IO_IDENTIFIERS.includes(n.name)) {
87
+ hasIO = true;
88
+ return;
89
+ }
90
+ }
91
+ // Performance: Skip node types that cannot contain identifiers
92
+ if (n.type === 'Literal' ||
93
+ n.type === 'TemplateElement' ||
94
+ n.type === 'Super' ||
95
+ n.type === 'ThisExpression') {
96
+ return; // These cannot contain identifier children
97
+ }
98
+ // Recursively visit children with depth tracking
99
+ // Only visit properties that typically contain code
100
+ const relevantKeys = ['body', 'expression', 'callee', 'object', 'property', 'left', 'right', 'test', 'consequent', 'alternate', 'arguments', 'params'];
101
+ for (const key of relevantKeys) {
102
+ const value = n[key];
103
+ if (!value)
104
+ continue;
105
+ if (typeof value === 'object') {
106
+ if (Array.isArray(value)) {
107
+ for (const item of value) {
108
+ if (item && typeof item === 'object' && 'type' in item) {
109
+ visit(item, depth + 1);
110
+ if (hasIO)
111
+ return; // Early exit
112
+ }
113
+ }
114
+ }
115
+ else if ('type' in value) {
116
+ visit(value, depth + 1);
117
+ }
118
+ }
119
+ }
120
+ }
121
+ if (node.body) {
122
+ visit(node.body);
123
+ }
124
+ return hasIO;
125
+ }
126
+ /**
127
+ * Check if function body is substantial (more than 3 statements)
128
+ */
129
+ function hasSubstantialLogic(node) {
130
+ if (!node.body || node.body.type !== 'BlockStatement') {
131
+ return false;
132
+ }
133
+ const blockBody = node.body;
134
+ return blockBody.body.length > 3;
135
+ }
136
+ /**
137
+ * Get function name with improved extraction from parent context
138
+ */
139
+ function getFunctionName(node) {
140
+ // 1. FunctionDeclaration - use direct id
141
+ if (node.type === 'FunctionDeclaration' && node.id) {
142
+ return node.id.name;
143
+ }
144
+ // 2. FunctionExpression - try id first, then parent
145
+ if (node.type === 'FunctionExpression' && node.id) {
146
+ return node.id.name;
147
+ }
148
+ // 3. For unnamed FunctionExpression or ArrowFunctionExpression,
149
+ // try to get name from parent VariableDeclarator
150
+ try {
151
+ const ancestors = context.getAncestors();
152
+ // Look for parent VariableDeclarator
153
+ for (let i = ancestors.length - 1; i >= 0; i--) {
154
+ const ancestor = ancestors[i];
155
+ if (ancestor.type === 'VariableDeclarator') {
156
+ const varDecl = ancestor;
157
+ if (varDecl.id && varDecl.id.type === 'Identifier' && varDecl.id.name) {
158
+ return varDecl.id.name;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ catch {
164
+ // If ancestor lookup fails, fall through to 'anonymous'
165
+ }
166
+ return 'anonymous';
167
+ }
168
+ function checkFunction(node) {
169
+ const functionName = getFunctionName(node);
170
+ // Skip if function name is anonymous or very short (likely helper)
171
+ if (functionName === 'anonymous' || functionName.length < 3) {
172
+ return;
173
+ }
174
+ // Skip if function has I/O indicators
175
+ if (hasIOIndicators(node)) {
176
+ return;
177
+ }
178
+ // Warn if function has substantial logic but no I/O
179
+ if (hasSubstantialLogic(node)) {
180
+ context.report({
181
+ node: node,
182
+ messageId: 'pureLogicInShell',
183
+ data: {
184
+ name: functionName,
185
+ },
186
+ });
187
+ }
188
+ }
189
+ return {
190
+ FunctionDeclaration: checkFunction,
191
+ FunctionExpression: checkFunction,
192
+ ArrowFunctionExpression: checkFunction,
193
+ };
194
+ },
195
+ };
196
+ export default noPureLogicInShell;
197
+ //# sourceMappingURL=no-pure-logic-in-shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-pure-logic-in-shell.js","sourceRoot":"","sources":["../../src/rules/no-pure-logic-in-shell.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,0DAA0D;AAC1D,0FAA0F;AAC1F,sFAAsF;AACtF,MAAM,cAAc,GAAG;IACrB,IAAI;IACJ,UAAU;IACV,WAAW;IACX,OAAO;IACP,OAAO;IACP,MAAM;IACN,OAAO;IACP,IAAI;IACJ,UAAU;IACV,OAAO;IACP,SAAS;IACT,cAAc;IACd,eAAe;IACf,YAAY;IACZ,OAAO;IACP,OAAO;IACP,QAAQ;IACR,SAAS;IACT,MAAM;IACN,QAAQ;IACR,KAAK;IACL,OAAO;IACP,MAAM;IACN,UAAU;IACV,eAAe;IACf,WAAW;IACX,gBAAgB;IAChB,SAAS;IACT,KAAK;IACL,SAAS;CACV,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAoB;IACjD,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,qEAAqE;YAClF,WAAW,EAAE,KAAK;SACnB;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,gBAAgB,EACd,yGAAyG;SAC5G;KACF;IAED,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QAE3D,yCAAyC;QACzC,MAAM,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,CAAC,CAAC,uBAAuB;QACpC,CAAC;QAED;;WAEG;QACH,SAAS,eAAe,CAAC,IAAkB;YACzC,IAAI,KAAK,GAAG,KAAK,CAAC;YAElB,6BAA6B;YAC7B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;YAED,6DAA6D;YAC7D,+DAA+D;YAC/D,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,yCAAyC;YAE/D,SAAS,KAAK,CAAC,CAAO,EAAE,QAAgB,CAAC;gBACvC,IAAI,KAAK;oBAAE,OAAO,CAAC,gCAAgC;gBACnD,IAAI,KAAK,GAAG,SAAS;oBAAE,OAAO,CAAC,cAAc;gBAE7C,qCAAqC;gBACrC,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBAC5B,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;wBACpC,KAAK,GAAG,IAAI,CAAC;wBACb,OAAO;oBACT,CAAC;gBACH,CAAC;gBAED,+DAA+D;gBAC/D,IACE,CAAC,CAAC,IAAI,KAAK,SAAS;oBACpB,CAAC,CAAC,IAAI,KAAK,iBAAiB;oBAC5B,CAAC,CAAC,IAAI,KAAK,OAAO;oBAClB,CAAC,CAAC,IAAI,KAAK,gBAAgB,EAC3B,CAAC;oBACD,OAAO,CAAC,2CAA2C;gBACrD,CAAC;gBAED,iDAAiD;gBACjD,oDAAoD;gBACpD,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;gBAEvJ,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;oBAC/B,MAAM,KAAK,GAAI,CAAwC,CAAC,GAAG,CAAC,CAAC;oBAC7D,IAAI,CAAC,KAAK;wBAAE,SAAS;oBAErB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;wBAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;4BACzB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gCACzB,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;oCACvD,KAAK,CAAC,IAAY,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;oCAC/B,IAAI,KAAK;wCAAE,OAAO,CAAC,aAAa;gCAClC,CAAC;4BACH,CAAC;wBACH,CAAC;6BAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;4BAC3B,KAAK,CAAC,KAAa,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;wBAClC,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;gBACd,KAAK,CAAC,IAAI,CAAC,IAAY,CAAC,CAAC;YAC3B,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAED;;WAEG;QACH,SAAS,mBAAmB,CAAC,IAAkB;YAC7C,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;gBACtD,OAAO,KAAK,CAAC;YACf,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,CAAC,IAAsB,CAAC;YAC9C,OAAO,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACnC,CAAC;QAED;;WAEG;QACH,SAAS,eAAe,CAAC,IAAkB;YACzC,yCAAyC;YACzC,IAAI,IAAI,CAAC,IAAI,KAAK,qBAAqB,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBACnD,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;YACtB,CAAC;YAED,oDAAoD;YACpD,IAAI,IAAI,CAAC,IAAI,KAAK,oBAAoB,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;gBAClD,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;YACtB,CAAC;YAED,gEAAgE;YAChE,oDAAoD;YACpD,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;gBAEzC,qCAAqC;gBACrC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC/C,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;oBAC9B,IAAI,QAAQ,CAAC,IAAI,KAAK,oBAAoB,EAAE,CAAC;wBAC3C,MAAM,OAAO,GAAG,QAA8D,CAAC;wBAC/E,IAAI,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,EAAE,CAAC,IAAI,KAAK,YAAY,IAAI,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;4BACtE,OAAO,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC;wBACzB,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,wDAAwD;YAC1D,CAAC;YAED,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,SAAS,aAAa,CAAC,IAAkB;YACvC,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;YAE3C,mEAAmE;YACnE,IAAI,YAAY,KAAK,WAAW,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5D,OAAO;YACT,CAAC;YAED,sCAAsC;YACtC,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,OAAO;YACT,CAAC;YAED,oDAAoD;YACpD,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,IAA4B;oBAClC,SAAS,EAAE,kBAAkB;oBAC7B,IAAI,EAAE;wBACJ,IAAI,EAAE,YAAY;qBACnB;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO;YACL,mBAAmB,EAAE,aAAa;YAClC,kBAAkB,EAAE,aAAa;YACjC,uBAAuB,EAAE,aAAa;SACvC,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Rule: no-redundant-type-schema
3
+ *
4
+ * Detect Zod schemas that only repeat TypeScript types without adding semantic constraints.
5
+ *
6
+ * Detects:
7
+ * - z.string() without .min/.max/.regex/.email/etc
8
+ * - z.number() without .int/.min/.max/.positive/etc
9
+ * - z.boolean() (almost always redundant)
10
+ */
11
+ /**
12
+ * Check if a schema call chain has any refinements
13
+ */
14
+ function hasRefinements(node, baseType) {
15
+ const refinementMethods = {
16
+ string: ['min', 'max', 'length', 'email', 'url', 'emoji', 'uuid', 'cuid', 'regex', 'startsWith', 'endsWith', 'trim', 'toLowerCase', 'toUpperCase', 'refine', 'transform'],
17
+ number: ['min', 'max', 'int', 'positive', 'negative', 'nonnegative', 'nonpositive', 'multipleOf', 'finite', 'safe', 'refine', 'transform'],
18
+ boolean: [], // boolean is always redundant
19
+ };
20
+ const allowedMethods = refinementMethods[baseType] || [];
21
+ // Walk up the AST to find any method calls on this schema
22
+ let current = node.parent;
23
+ while (current) {
24
+ if (current.type === 'CallExpression') {
25
+ const callee = current.callee;
26
+ if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {
27
+ const methodName = callee.property.name;
28
+ if (allowedMethods.includes(methodName)) {
29
+ return true; // Found a refinement
30
+ }
31
+ }
32
+ current = current.parent;
33
+ }
34
+ else if (current.type === 'VariableDeclarator' || current.type === 'Property') {
35
+ // Reached variable declaration or object property, stop searching
36
+ break;
37
+ }
38
+ else {
39
+ current = current.parent;
40
+ }
41
+ }
42
+ return false;
43
+ }
44
+ export const noRedundantTypeSchema = {
45
+ meta: {
46
+ type: 'suggestion',
47
+ docs: {
48
+ description: 'Forbid Zod schemas that only repeat TypeScript types without adding constraints',
49
+ recommended: true,
50
+ },
51
+ schema: [],
52
+ messages: {
53
+ redundantString: 'z.string() without constraints is redundant. Add .min(), .max(), .regex(), or use plain TypeScript type.',
54
+ redundantNumber: 'z.number() without constraints is redundant. Add .min(), .max(), .int(), or use plain TypeScript type.',
55
+ redundantBoolean: 'z.boolean() is almost always redundant. Use plain TypeScript boolean type unless validating external input.',
56
+ },
57
+ },
58
+ create(context) {
59
+ const sourceCode = context.sourceCode || context.getSourceCode();
60
+ return {
61
+ CallExpression(node) {
62
+ const callee = node.callee;
63
+ // Only check direct z.type() calls, not chained calls
64
+ if (callee.type === 'MemberExpression' &&
65
+ callee.object.type === 'Identifier' &&
66
+ callee.object.name === 'z' &&
67
+ callee.property.type === 'Identifier') {
68
+ const typeName = callee.property.name;
69
+ // Add parent reference for hasRefinements to work
70
+ if (!node.parent) {
71
+ const parents = sourceCode.getAncestors(node);
72
+ node.parent = parents[parents.length - 1];
73
+ }
74
+ if (typeName === 'string' && !hasRefinements(node, 'string')) {
75
+ context.report({
76
+ node: node,
77
+ messageId: 'redundantString',
78
+ });
79
+ }
80
+ if (typeName === 'number' && !hasRefinements(node, 'number')) {
81
+ context.report({
82
+ node: node,
83
+ messageId: 'redundantNumber',
84
+ });
85
+ }
86
+ if (typeName === 'boolean') {
87
+ // boolean is always redundant since TypeScript already enforces it
88
+ context.report({
89
+ node: node,
90
+ messageId: 'redundantBoolean',
91
+ });
92
+ }
93
+ }
94
+ },
95
+ };
96
+ },
97
+ };
98
+ export default noRedundantTypeSchema;
99
+ //# sourceMappingURL=no-redundant-type-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-redundant-type-schema.js","sourceRoot":"","sources":["../../src/rules/no-redundant-type-schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Rule: no-runtime-imports
3
+ *
4
+ * Forbid imports inside functions (runtime imports).
5
+ * All imports should be at module top-level for predictability and performance.
6
+ *
7
+ * Detects:
8
+ * - require() calls inside functions
9
+ * - dynamic import() calls inside functions
10
+ */
11
+ export const noRuntimeImports = {
12
+ meta: {
13
+ type: 'problem',
14
+ docs: {
15
+ description: 'Forbid imports inside functions (require runtime imports at module top-level)',
16
+ recommended: true,
17
+ },
18
+ schema: [],
19
+ messages: {
20
+ runtimeRequire: 'Runtime require() detected. Move imports to module top-level for predictability.',
21
+ runtimeImport: 'Dynamic import() detected. Move imports to module top-level for predictability.',
22
+ },
23
+ },
24
+ create(context) {
25
+ /**
26
+ * Check if node is inside a function
27
+ */
28
+ function isInsideFunction(node) {
29
+ const ancestors = context.sourceCode?.getAncestors?.(node) || context.getAncestors();
30
+ for (const ancestor of ancestors) {
31
+ if (ancestor.type === 'FunctionDeclaration' ||
32
+ ancestor.type === 'FunctionExpression' ||
33
+ ancestor.type === 'ArrowFunctionExpression') {
34
+ return true;
35
+ }
36
+ }
37
+ return false;
38
+ }
39
+ return {
40
+ CallExpression(node) {
41
+ const callNode = node;
42
+ // Check for require() calls
43
+ if (callNode.callee.type === 'Identifier' &&
44
+ callNode.callee.name === 'require') {
45
+ if (isInsideFunction(node)) {
46
+ context.report({
47
+ node: node,
48
+ messageId: 'runtimeRequire',
49
+ });
50
+ }
51
+ }
52
+ },
53
+ ImportExpression(node) {
54
+ // Check for dynamic import()
55
+ if (isInsideFunction(node)) {
56
+ context.report({
57
+ node: node,
58
+ messageId: 'runtimeImport',
59
+ });
60
+ }
61
+ },
62
+ };
63
+ },
64
+ };
65
+ export default noRuntimeImports;
66
+ //# sourceMappingURL=no-runtime-imports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-runtime-imports.js","sourceRoot":"","sources":["../../src/rules/no-runtime-imports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,MAAM,CAAC,MAAM,gBAAgB,GAAoB;IAC/C,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,+EAA+E;YAC5F,WAAW,EAAE,IAAI;SAClB;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,cAAc,EACZ,kFAAkF;YACpF,aAAa,EACX,iFAAiF;SACpF;KACF;IAED,MAAM,CAAC,OAAO;QACZ;;WAEG;QACH,SAAS,gBAAgB,CAAC,IAAe;YACvC,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;YAErF,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBACjC,IACE,QAAQ,CAAC,IAAI,KAAK,qBAAqB;oBACvC,QAAQ,CAAC,IAAI,KAAK,oBAAoB;oBACtC,QAAQ,CAAC,IAAI,KAAK,yBAAyB,EAC3C,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;YACH,CAAC;YAED,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO;YACL,cAAc,CAAC,IAAI;gBACjB,MAAM,QAAQ,GAAG,IAAiC,CAAC;gBAEnD,4BAA4B;gBAC5B,IACE,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY;oBACrC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,SAAS,EAClC,CAAC;oBACD,IAAI,gBAAgB,CAAC,IAA4B,CAAC,EAAE,CAAC;wBACnD,OAAO,CAAC,MAAM,CAAC;4BACb,IAAI,EAAE,IAA4B;4BAClC,SAAS,EAAE,gBAAgB;yBAC5B,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YAED,gBAAgB,CAAC,IAAI;gBACnB,6BAA6B;gBAC7B,IAAI,gBAAgB,CAAC,IAA4B,CAAC,EAAE,CAAC;oBACnD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,IAA4B;wBAClC,SAAS,EAAE,eAAe;qBAC3B,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,eAAe,gBAAgB,CAAC"}