@opensip-cli/checks-universal 0.1.9 → 0.1.11
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 +4 -2
- package/dist/__tests__/all-checks-execute.test.d.ts.map +1 -1
- package/dist/__tests__/all-checks-execute.test.js +0 -1
- package/dist/__tests__/all-checks-execute.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-10.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-10.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-10.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-11.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-11.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-11.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-12.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-12.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-12.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-2.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-2.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-2.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-3.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-3.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-3.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-4.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-4.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-4.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-5.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-5.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-5.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-6.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-6.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-6.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-7.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-7.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-7.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-8.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-8.test.js +2 -3
- package/dist/__tests__/behavior-fixtures-8.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures-9.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures-9.test.js +0 -1
- package/dist/__tests__/behavior-fixtures-9.test.js.map +1 -1
- package/dist/__tests__/behavior-fixtures.test.d.ts.map +1 -1
- package/dist/__tests__/behavior-fixtures.test.js +10 -9
- package/dist/__tests__/behavior-fixtures.test.js.map +1 -1
- package/dist/__tests__/file-length-limit.test.js +12 -1
- package/dist/__tests__/file-length-limit.test.js.map +1 -1
- package/dist/checks/architecture/__tests__/tool-identity-single-source.test.d.ts +2 -0
- package/dist/checks/architecture/__tests__/tool-identity-single-source.test.d.ts.map +1 -0
- package/dist/checks/architecture/__tests__/tool-identity-single-source.test.js +61 -0
- package/dist/checks/architecture/__tests__/tool-identity-single-source.test.js.map +1 -0
- package/dist/checks/architecture/docker-best-practices-analyze.d.ts +7 -0
- package/dist/checks/architecture/docker-best-practices-analyze.d.ts.map +1 -0
- package/dist/checks/architecture/docker-best-practices-analyze.js +301 -0
- package/dist/checks/architecture/docker-best-practices-analyze.js.map +1 -0
- package/dist/checks/architecture/docker-best-practices-patterns.d.ts +50 -0
- package/dist/checks/architecture/docker-best-practices-patterns.d.ts.map +1 -0
- package/dist/checks/architecture/docker-best-practices-patterns.js +51 -0
- package/dist/checks/architecture/docker-best-practices-patterns.js.map +1 -0
- package/dist/checks/architecture/docker-best-practices.d.ts.map +1 -1
- package/dist/checks/architecture/docker-best-practices.js +1 -367
- package/dist/checks/architecture/docker-best-practices.js.map +1 -1
- package/dist/checks/architecture/docker-ignore-validation.d.ts.map +1 -1
- package/dist/checks/architecture/docker-ignore-validation.js +0 -1
- package/dist/checks/architecture/docker-ignore-validation.js.map +1 -1
- package/dist/checks/architecture/docker-version-sync.d.ts.map +1 -1
- package/dist/checks/architecture/docker-version-sync.js +0 -1
- package/dist/checks/architecture/docker-version-sync.js.map +1 -1
- package/dist/checks/architecture/heavy-import-detection.d.ts.map +1 -1
- package/dist/checks/architecture/heavy-import-detection.js +1 -0
- package/dist/checks/architecture/heavy-import-detection.js.map +1 -1
- package/dist/checks/architecture/index.d.ts +1 -0
- package/dist/checks/architecture/index.d.ts.map +1 -1
- package/dist/checks/architecture/index.js +1 -0
- package/dist/checks/architecture/index.js.map +1 -1
- package/dist/checks/architecture/modules/empty-package-detection.d.ts.map +1 -1
- package/dist/checks/architecture/modules/empty-package-detection.js +0 -1
- package/dist/checks/architecture/modules/empty-package-detection.js.map +1 -1
- package/dist/checks/architecture/modules/interface-implementation-consistency-constants.d.ts +16 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency-constants.d.ts.map +1 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency-constants.js +182 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency-constants.js.map +1 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency-parse.d.ts +23 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency-parse.d.ts.map +1 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency-parse.js +235 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency-parse.js.map +1 -0
- package/dist/checks/architecture/modules/interface-implementation-consistency.d.ts.map +1 -1
- package/dist/checks/architecture/modules/interface-implementation-consistency.js +4 -462
- package/dist/checks/architecture/modules/interface-implementation-consistency.js.map +1 -1
- package/dist/checks/architecture/node-version-consistency.d.ts.map +1 -1
- package/dist/checks/architecture/node-version-consistency.js +0 -2
- package/dist/checks/architecture/node-version-consistency.js.map +1 -1
- package/dist/checks/architecture/stale-build-artifacts.d.ts.map +1 -1
- package/dist/checks/architecture/stale-build-artifacts.js +0 -1
- package/dist/checks/architecture/stale-build-artifacts.js.map +1 -1
- package/dist/checks/architecture/tool-has-manifest.d.ts.map +1 -1
- package/dist/checks/architecture/tool-has-manifest.js +0 -1
- package/dist/checks/architecture/tool-has-manifest.js.map +1 -1
- package/dist/checks/architecture/tool-identity-single-source.d.ts +23 -0
- package/dist/checks/architecture/tool-identity-single-source.d.ts.map +1 -0
- package/dist/checks/architecture/tool-identity-single-source.js +126 -0
- package/dist/checks/architecture/tool-identity-single-source.js.map +1 -0
- package/dist/checks/documentation/_public-api-graph.d.ts +3 -26
- package/dist/checks/documentation/_public-api-graph.d.ts.map +1 -1
- package/dist/checks/documentation/_public-api-graph.js +3 -300
- package/dist/checks/documentation/_public-api-graph.js.map +1 -1
- package/dist/checks/documentation/directive-audit.d.ts.map +1 -1
- package/dist/checks/documentation/directive-audit.js +0 -1
- package/dist/checks/documentation/directive-audit.js.map +1 -1
- package/dist/checks/file-length-limit.d.ts +7 -0
- package/dist/checks/file-length-limit.d.ts.map +1 -1
- package/dist/checks/file-length-limit.js +14 -2
- package/dist/checks/file-length-limit.js.map +1 -1
- package/dist/checks/quality/code-structure/dead-code.d.ts.map +1 -1
- package/dist/checks/quality/code-structure/dead-code.js +0 -1
- package/dist/checks/quality/code-structure/dead-code.js.map +1 -1
- package/dist/checks/quality/dependency-version-consistency.d.ts.map +1 -1
- package/dist/checks/quality/dependency-version-consistency.js +0 -2
- package/dist/checks/quality/dependency-version-consistency.js.map +1 -1
- package/dist/checks/quality/frontend/navigation-typing.d.ts.map +1 -1
- package/dist/checks/quality/frontend/navigation-typing.js +0 -1
- package/dist/checks/quality/frontend/navigation-typing.js.map +1 -1
- package/dist/checks/quality/index.d.ts +1 -0
- package/dist/checks/quality/index.d.ts.map +1 -1
- package/dist/checks/quality/index.js +1 -0
- package/dist/checks/quality/index.js.map +1 -1
- package/dist/checks/quality/linting/eslint-justifications.d.ts.map +1 -1
- package/dist/checks/quality/linting/eslint-justifications.js +0 -1
- package/dist/checks/quality/linting/eslint-justifications.js.map +1 -1
- package/dist/checks/quality/no-raw-regex-on-code.d.ts.map +1 -1
- package/dist/checks/quality/no-raw-regex-on-code.js +2 -3
- package/dist/checks/quality/no-raw-regex-on-code.js.map +1 -1
- package/dist/checks/quality/patterns/__tests__/performance-anti-patterns-fp.test.d.ts +5 -0
- package/dist/checks/quality/patterns/__tests__/performance-anti-patterns-fp.test.d.ts.map +1 -0
- package/dist/checks/quality/patterns/__tests__/performance-anti-patterns-fp.test.js +66 -0
- package/dist/checks/quality/patterns/__tests__/performance-anti-patterns-fp.test.js.map +1 -0
- package/dist/checks/quality/patterns/performance-anti-patterns.d.ts +3 -0
- package/dist/checks/quality/patterns/performance-anti-patterns.d.ts.map +1 -1
- package/dist/checks/quality/patterns/performance-anti-patterns.js +47 -30
- package/dist/checks/quality/patterns/performance-anti-patterns.js.map +1 -1
- package/dist/checks/quality/yagni-ignore-hygiene.d.ts +10 -0
- package/dist/checks/quality/yagni-ignore-hygiene.d.ts.map +1 -0
- package/dist/checks/quality/yagni-ignore-hygiene.js +87 -0
- package/dist/checks/quality/yagni-ignore-hygiene.js.map +1 -0
- package/dist/checks/quality/yagni-ignore-hygiene.test.d.ts +5 -0
- package/dist/checks/quality/yagni-ignore-hygiene.test.d.ts.map +1 -0
- package/dist/checks/quality/yagni-ignore-hygiene.test.js +37 -0
- package/dist/checks/quality/yagni-ignore-hygiene.test.js.map +1 -0
- package/dist/checks/resilience/batch-operation-limits.d.ts +13 -0
- package/dist/checks/resilience/batch-operation-limits.d.ts.map +1 -0
- package/dist/checks/resilience/batch-operation-limits.js +160 -0
- package/dist/checks/resilience/batch-operation-limits.js.map +1 -0
- package/dist/checks/resilience/batch-operations.d.ts +2 -21
- package/dist/checks/resilience/batch-operations.d.ts.map +1 -1
- package/dist/checks/resilience/batch-operations.js +2 -420
- package/dist/checks/resilience/batch-operations.js.map +1 -1
- package/dist/checks/resilience/dangerous-config-defaults.d.ts.map +1 -1
- package/dist/checks/resilience/dangerous-config-defaults.js +0 -1
- package/dist/checks/resilience/dangerous-config-defaults.js.map +1 -1
- package/dist/checks/resilience/exit-code-correctness.d.ts.map +1 -1
- package/dist/checks/resilience/exit-code-correctness.js +0 -1
- package/dist/checks/resilience/exit-code-correctness.js.map +1 -1
- package/dist/checks/resilience/no-process-exit-in-finally.d.ts.map +1 -1
- package/dist/checks/resilience/no-process-exit-in-finally.js +0 -1
- package/dist/checks/resilience/no-process-exit-in-finally.js.map +1 -1
- package/dist/checks/resilience/readline-cleanup.d.ts.map +1 -1
- package/dist/checks/resilience/readline-cleanup.js +0 -1
- package/dist/checks/resilience/readline-cleanup.js.map +1 -1
- package/dist/checks/resilience/reentrancy-guard.d.ts.map +1 -1
- package/dist/checks/resilience/reentrancy-guard.js +0 -1
- package/dist/checks/resilience/reentrancy-guard.js.map +1 -1
- package/dist/checks/resilience/service-patterns.d.ts.map +1 -1
- package/dist/checks/resilience/service-patterns.js +0 -1
- package/dist/checks/resilience/service-patterns.js.map +1 -1
- package/dist/checks/resilience/unbounded-memory.d.ts +13 -0
- package/dist/checks/resilience/unbounded-memory.d.ts.map +1 -0
- package/dist/checks/resilience/unbounded-memory.js +229 -0
- package/dist/checks/resilience/unbounded-memory.js.map +1 -0
- package/dist/checks/security/csp-headers.d.ts.map +1 -1
- package/dist/checks/security/csp-headers.js +0 -1
- package/dist/checks/security/csp-headers.js.map +1 -1
- package/dist/checks/security/hasura-production-config.d.ts.map +1 -1
- package/dist/checks/security/hasura-production-config.js +0 -1
- package/dist/checks/security/hasura-production-config.js.map +1 -1
- package/dist/checks/security/jwt-validation.d.ts.map +1 -1
- package/dist/checks/security/jwt-validation.js +0 -2
- package/dist/checks/security/jwt-validation.js.map +1 -1
- package/dist/checks/security/package-supply-chain-policy.d.ts.map +1 -1
- package/dist/checks/security/package-supply-chain-policy.js +9 -15
- package/dist/checks/security/package-supply-chain-policy.js.map +1 -1
- package/dist/checks/security/semgrep-scan.d.ts.map +1 -1
- package/dist/checks/security/semgrep-scan.js +0 -1
- package/dist/checks/security/semgrep-scan.js.map +1 -1
- package/dist/checks/security/use-centralized-crypto.d.ts.map +1 -1
- package/dist/checks/security/use-centralized-crypto.js +2 -3
- package/dist/checks/security/use-centralized-crypto.js.map +1 -1
- package/dist/checks/testing/test-convention-consistency.d.ts.map +1 -1
- package/dist/checks/testing/test-convention-consistency.js +0 -1
- package/dist/checks/testing/test-convention-consistency.js.map +1 -1
- package/dist/checks/testing/test-file-pairing.js +3 -6
- package/dist/checks/testing/test-file-pairing.js.map +1 -1
- package/dist/display/architecture.d.ts.map +1 -1
- package/dist/display/architecture.js +1 -0
- package/dist/display/architecture.js.map +1 -1
- package/dist/display/quality.d.ts.map +1 -1
- package/dist/display/quality.js +1 -0
- package/dist/display/quality.js.map +1 -1
- package/dist/display/types.d.ts.map +1 -1
- package/dist/display/types.js +0 -1
- package/dist/display/types.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage for the `yagni-ignore-hygiene` check (ADR-0014).
|
|
3
|
+
*/
|
|
4
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
import { makeFitnessTestScope, withScope } from '@opensip-cli/test-support';
|
|
8
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
9
|
+
import { yagniIgnoreHygiene } from './yagni-ignore-hygiene.js';
|
|
10
|
+
let root;
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
root = await mkdtemp(join(tmpdir(), 'yagni-hygiene-'));
|
|
13
|
+
});
|
|
14
|
+
afterEach(async () => {
|
|
15
|
+
await rm(root, { recursive: true, force: true });
|
|
16
|
+
});
|
|
17
|
+
async function violationTypes(name, content) {
|
|
18
|
+
const filePath = join(root, name);
|
|
19
|
+
await writeFile(filePath, content, 'utf8');
|
|
20
|
+
const result = await withScope(makeFitnessTestScope(), () => yagniIgnoreHygiene.run(root, { targetFiles: [filePath] }));
|
|
21
|
+
return result.signals.map((s) => s.metadata.type);
|
|
22
|
+
}
|
|
23
|
+
describe('yagni-ignore-hygiene', () => {
|
|
24
|
+
it('flags a directive missing a -- reason as ignore-without-reason', async () => {
|
|
25
|
+
const types = await violationTypes('a.ts', '// @yagni-ignore-next-line unused-config-surface\nconst x = 1;\n');
|
|
26
|
+
expect(types).toContain('ignore-without-reason');
|
|
27
|
+
});
|
|
28
|
+
it('flags an invalid detector slug as invalid-ignore-slug', async () => {
|
|
29
|
+
const types = await violationTypes('b.ts', '// @yagni-ignore-next-line Bad_Slug -- has a reason\nconst x = 1;\n');
|
|
30
|
+
expect(types).toContain('invalid-ignore-slug');
|
|
31
|
+
});
|
|
32
|
+
it('accepts valid directives with reasons', async () => {
|
|
33
|
+
const types = await violationTypes('c.ts', '// @yagni-ignore-file unused-config-surface -- fixture intentionally unused\n');
|
|
34
|
+
expect(types).toHaveLength(0);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=yagni-ignore-hygiene.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"yagni-ignore-hygiene.test.js","sourceRoot":"","sources":["../../../src/checks/quality/yagni-ignore-hygiene.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAE/D,IAAI,IAAY,CAAC;AAEjB,UAAU,CAAC,KAAK,IAAI,EAAE;IACpB,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC;AACzD,CAAC,CAAC,CAAC;AAEH,SAAS,CAAC,KAAK,IAAI,EAAE;IACnB,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,KAAK,UAAU,cAAc,CAAC,IAAY,EAAE,OAAe;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAClC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,oBAAoB,EAAE,EAAE,GAAG,EAAE,CAC1D,kBAAkB,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAC1D,CAAC;IACF,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,IAA0B,CAAC,CAAC;AAC1E,CAAC;AAED,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,KAAK,GAAG,MAAM,cAAc,CAChC,MAAM,EACN,kEAAkE,CACnE,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,KAAK,IAAI,EAAE;QACrE,MAAM,KAAK,GAAG,MAAM,cAAc,CAChC,MAAM,EACN,qEAAqE,CACtE,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,KAAK,GAAG,MAAM,cAAc,CAChC,MAAM,EACN,+EAA+E,CAChF,CAAC;QACF,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Batch operation limits check
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check: resilience/batch-operation-limits
|
|
6
|
+
*
|
|
7
|
+
* Detects batch operations that may process unbounded data:
|
|
8
|
+
* - Array operations on potentially large datasets without pagination
|
|
9
|
+
* - Async operations without concurrency limits
|
|
10
|
+
* - Database queries without LIMIT clauses
|
|
11
|
+
*/
|
|
12
|
+
export declare const batchOperationLimits: import("@opensip-cli/fitness").Check;
|
|
13
|
+
//# sourceMappingURL=batch-operation-limits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-operation-limits.d.ts","sourceRoot":"","sources":["../../../src/checks/resilience/batch-operation-limits.ts"],"names":[],"mappings":"AAAA;;GAEG;AA0GH;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,sCAkF/B,CAAC"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Batch operation limits check
|
|
3
|
+
*/
|
|
4
|
+
import { logger } from '@opensip-cli/core';
|
|
5
|
+
import { defineCheck, isCheckAuthoringSource, isTestFile, getLineNumber, } from '@opensip-cli/fitness';
|
|
6
|
+
const UNBOUNDED_BATCH_PATTERNS = [
|
|
7
|
+
{ pattern: '.map', type: 'async' },
|
|
8
|
+
{ pattern: '.forEach', type: 'async' },
|
|
9
|
+
{ pattern: 'for', type: 'forOf' },
|
|
10
|
+
];
|
|
11
|
+
function findUnboundedBatchMatch(content, patternDef, startIndex) {
|
|
12
|
+
logger.debug({
|
|
13
|
+
evt: 'fitness.checks.batch_operations.find_unbounded_batch_match',
|
|
14
|
+
msg: 'Finding unbounded batch pattern match at position in content',
|
|
15
|
+
});
|
|
16
|
+
const idx = content.indexOf(patternDef.pattern, startIndex);
|
|
17
|
+
if (idx === -1)
|
|
18
|
+
return null;
|
|
19
|
+
if (patternDef.type === 'async') {
|
|
20
|
+
const afterPattern = content.slice(idx + patternDef.pattern.length, idx + patternDef.pattern.length + 20);
|
|
21
|
+
const asyncMatch = /^\s*\(\s*async/.exec(afterPattern);
|
|
22
|
+
if (asyncMatch) {
|
|
23
|
+
return { index: idx, match: patternDef.pattern + asyncMatch[0] };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const afterFor = content.slice(idx, idx + 50);
|
|
28
|
+
const forOfMatch = /^for\s*\(\s*const\s+\w+\s+of/.exec(afterFor);
|
|
29
|
+
if (forOfMatch) {
|
|
30
|
+
return { index: idx, match: forOfMatch[0] };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const BOUNDED_KEYWORDS = [
|
|
36
|
+
'batch',
|
|
37
|
+
'chunk',
|
|
38
|
+
'page',
|
|
39
|
+
'limit',
|
|
40
|
+
'take',
|
|
41
|
+
'skip',
|
|
42
|
+
'offset',
|
|
43
|
+
'slice',
|
|
44
|
+
];
|
|
45
|
+
function hasBoundedKeyword(content) {
|
|
46
|
+
const lowerContent = content.toLowerCase();
|
|
47
|
+
return BOUNDED_KEYWORDS.some((keyword) => lowerContent.includes(keyword));
|
|
48
|
+
}
|
|
49
|
+
function findUnboundedQueryCalls(content) {
|
|
50
|
+
logger.debug({
|
|
51
|
+
evt: 'fitness.checks.batch_operations.find_unbounded_query_calls',
|
|
52
|
+
msg: 'Finding unbounded query calls like findAll, getAll, findMany with empty args',
|
|
53
|
+
});
|
|
54
|
+
const results = [];
|
|
55
|
+
const methods = ['findAll', 'getAll', 'findMany'];
|
|
56
|
+
for (const method of methods) {
|
|
57
|
+
const pattern = `.${method}`;
|
|
58
|
+
let searchStart = 0;
|
|
59
|
+
while (searchStart < content.length) {
|
|
60
|
+
const idx = content.indexOf(pattern, searchStart);
|
|
61
|
+
if (idx === -1)
|
|
62
|
+
break;
|
|
63
|
+
const afterMethod = content.slice(idx + pattern.length, idx + pattern.length + 10);
|
|
64
|
+
const emptyArgsMatch = /^\s*\(\s*\)/.exec(afterMethod);
|
|
65
|
+
if (emptyArgsMatch) {
|
|
66
|
+
results.push({
|
|
67
|
+
index: idx,
|
|
68
|
+
methodName: method,
|
|
69
|
+
match: pattern + emptyArgsMatch[0],
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
searchStart = idx + pattern.length;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return results;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Check: resilience/batch-operation-limits
|
|
79
|
+
*
|
|
80
|
+
* Detects batch operations that may process unbounded data:
|
|
81
|
+
* - Array operations on potentially large datasets without pagination
|
|
82
|
+
* - Async operations without concurrency limits
|
|
83
|
+
* - Database queries without LIMIT clauses
|
|
84
|
+
*/
|
|
85
|
+
export const batchOperationLimits = defineCheck({
|
|
86
|
+
id: 'c4d9b853-147e-4c29-9702-f392b1f51056',
|
|
87
|
+
slug: 'batch-operation-limits',
|
|
88
|
+
scope: { languages: ['typescript'], concerns: ['backend', 'frontend', 'cli'] },
|
|
89
|
+
contentFilter: 'strip-strings',
|
|
90
|
+
confidence: 'medium',
|
|
91
|
+
description: 'Detect batch operations that may process unbounded data',
|
|
92
|
+
longDescription: `**Purpose:** Prevents batch operations from processing arbitrarily large datasets without pagination or concurrency controls.
|
|
93
|
+
|
|
94
|
+
**Detects:**
|
|
95
|
+
- Unbounded query calls: \`.findAll()\`, \`.getAll()\`, \`.findMany()\` with empty parentheses
|
|
96
|
+
- Async callbacks in \`.map(\` and \`.forEach(\` without nearby batching keywords
|
|
97
|
+
- \`for (const x of\` loops without pagination indicators
|
|
98
|
+
- Skips files containing bounded keywords: \`batch\`, \`chunk\`, \`page\`, \`limit\`, \`take\`, \`skip\`, \`offset\`, \`slice\`
|
|
99
|
+
|
|
100
|
+
**Why it matters:** Processing unbounded datasets can exhaust memory and starve other operations of resources.
|
|
101
|
+
|
|
102
|
+
**Scope:** General best practice. Analyzes each file individually via string matching.`,
|
|
103
|
+
tags: ['resilience', 'performance', 'memory'],
|
|
104
|
+
fileTypes: ['ts'],
|
|
105
|
+
analyze(content, filePath) {
|
|
106
|
+
if (isTestFile(filePath))
|
|
107
|
+
return [];
|
|
108
|
+
if (isCheckAuthoringSource(filePath))
|
|
109
|
+
return [];
|
|
110
|
+
logger.debug({
|
|
111
|
+
evt: 'fitness.checks.batch_operations.analyze_unbounded_batch',
|
|
112
|
+
msg: 'Analyzing file for unbounded batch operations that may process excessive data',
|
|
113
|
+
});
|
|
114
|
+
const violations = [];
|
|
115
|
+
if (hasBoundedKeyword(content)) {
|
|
116
|
+
return violations;
|
|
117
|
+
}
|
|
118
|
+
const unboundedQueries = findUnboundedQueryCalls(content);
|
|
119
|
+
for (const query of unboundedQueries) {
|
|
120
|
+
const lineNumber = getLineNumber(content, query.index);
|
|
121
|
+
violations.push({
|
|
122
|
+
line: lineNumber,
|
|
123
|
+
column: 0,
|
|
124
|
+
message: `Unbounded ${query.methodName}() call may load excessive data`,
|
|
125
|
+
severity: 'warning',
|
|
126
|
+
suggestion: `Add pagination with limit/offset or use cursor-based pagination. Example: ${query.methodName}({ take: 100, skip: offset }) or use a cursor-based approach for large datasets.`,
|
|
127
|
+
match: query.match,
|
|
128
|
+
type: 'unbounded-query',
|
|
129
|
+
filePath,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
for (const patternDef of UNBOUNDED_BATCH_PATTERNS) {
|
|
133
|
+
let searchStart = 0;
|
|
134
|
+
while (searchStart < content.length) {
|
|
135
|
+
const matchResult = findUnboundedBatchMatch(content, patternDef, searchStart);
|
|
136
|
+
if (!matchResult)
|
|
137
|
+
break;
|
|
138
|
+
const start = Math.max(0, matchResult.index - 300);
|
|
139
|
+
const end = Math.min(content.length, matchResult.index + 300);
|
|
140
|
+
const context = content.slice(start, end);
|
|
141
|
+
if (!hasBoundedKeyword(context)) {
|
|
142
|
+
const lineNumber = getLineNumber(content, matchResult.index);
|
|
143
|
+
violations.push({
|
|
144
|
+
line: lineNumber,
|
|
145
|
+
column: 0,
|
|
146
|
+
message: 'Async operation in loop without batching may exhaust resources',
|
|
147
|
+
severity: 'warning',
|
|
148
|
+
suggestion: 'Add batch processing or concurrency limits. Use chunk() to process in batches or pLimit() to limit concurrent operations.',
|
|
149
|
+
match: matchResult.match,
|
|
150
|
+
type: 'unbounded-async-loop',
|
|
151
|
+
filePath,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
searchStart = matchResult.index + 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return violations;
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
//# sourceMappingURL=batch-operation-limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch-operation-limits.js","sourceRoot":"","sources":["../../../src/checks/resilience/batch-operation-limits.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Check: resilience/batch-operation-limits
|
|
6
|
-
*
|
|
7
|
-
* Detects batch operations that may process unbounded data:
|
|
8
|
-
* - Array operations on potentially large datasets without pagination
|
|
9
|
-
* - Async operations without concurrency limits
|
|
10
|
-
* - Database queries without LIMIT clauses
|
|
11
|
-
*/
|
|
12
|
-
export declare const batchOperationLimits: import("@opensip-cli/fitness").Check;
|
|
13
|
-
/**
|
|
14
|
-
* Check: resilience/unbounded-memory
|
|
15
|
-
*
|
|
16
|
-
* Detects potential memory leaks and OOM risks:
|
|
17
|
-
* - Maps/Sets/Arrays in classes without eviction logic
|
|
18
|
-
* - File reads without prior size checks
|
|
19
|
-
* - Growing buffers without backpressure
|
|
20
|
-
*/
|
|
21
|
-
export declare const unboundedMemory: import("@opensip-cli/fitness").Check;
|
|
1
|
+
export { batchOperationLimits } from './batch-operation-limits.js';
|
|
2
|
+
export { unboundedMemory } from './unbounded-memory.js';
|
|
22
3
|
//# sourceMappingURL=batch-operations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-operations.d.ts","sourceRoot":"","sources":["../../../src/checks/resilience/batch-operations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"batch-operations.d.ts","sourceRoot":"","sources":["../../../src/checks/resilience/batch-operations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|