@dommaker/harness 0.17.1 → 0.18.0
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/CHANGELOG.md +22 -0
- package/README.md +5 -4
- package/bin/harness.js +3 -1
- package/bin/install-precommit-hook.sh +76 -0
- package/dist/architecture/cross-project-checker.js +2 -2
- package/dist/architecture/cross-project-checker.js.map +1 -1
- package/dist/cli/commands/constraints-report.js +2 -2
- package/dist/cli/commands/constraints-report.js.map +1 -1
- package/dist/cli/commands/constraints-retire.d.ts +24 -6
- package/dist/cli/commands/constraints-retire.d.ts.map +1 -1
- package/dist/cli/commands/constraints-retire.js +96 -19
- package/dist/cli/commands/constraints-retire.js.map +1 -1
- package/dist/cli/commands/doc-freshness-check.js +1 -1
- package/dist/cli/commands/doc-freshness-check.js.map +1 -1
- package/dist/cli/commands/init.js +14 -14
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/sync-docs/index.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/index.js +14 -6
- package/dist/cli/commands/sync-docs/index.js.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.d.ts.map +1 -1
- package/dist/cli/commands/sync-docs/project-reader.js +9 -7
- package/dist/cli/commands/sync-docs/project-reader.js.map +1 -1
- package/dist/cli/commands/validate.js +3 -3
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/session-mining/text.js +1 -1
- package/dist/cli/session-mining/text.js.map +1 -1
- package/dist/core/constraints/definitions/iron-laws.js +2 -2
- package/dist/core/constraints/definitions/iron-laws.js.map +1 -1
- package/dist/core/constraints/injection-drift.d.ts +1 -1
- package/dist/core/constraints/injection-drift.d.ts.map +1 -1
- package/dist/core/constraints/injection-drift.js +1 -1
- package/dist/core/constraints/injection-drift.js.map +1 -1
- package/dist/core/effective-constraints.d.ts +2 -1
- package/dist/core/effective-constraints.d.ts.map +1 -1
- package/dist/core/effective-constraints.js +2 -1
- package/dist/core/effective-constraints.js.map +1 -1
- package/dist/core/project-config-loader.d.ts +2 -1
- package/dist/core/project-config-loader.d.ts.map +1 -1
- package/dist/core/project-config-loader.js +8 -2
- package/dist/core/project-config-loader.js.map +1 -1
- package/dist/hooks/bootstrap.js +1 -1
- package/dist/hooks/bootstrap.js.map +1 -1
- package/dist/knowledge/store.js +1 -1
- package/dist/knowledge/store.js.map +1 -1
- package/dist/knowledge/types.d.ts +2 -0
- package/dist/knowledge/types.d.ts.map +1 -1
- package/dist/knowledge/types.js.map +1 -1
- package/dist/safety/output-guardrail.js +2 -2
- package/dist/safety/output-guardrail.js.map +1 -1
- package/dist/spec/annotation-checker.js +1 -1
- package/dist/spec/annotation-checker.js.map +1 -1
- package/dist/types/project-config.d.ts +15 -0
- package/dist/types/project-config.d.ts.map +1 -1
- package/dist/utils/file-walk.d.ts +13 -1
- package/dist/utils/file-walk.d.ts.map +1 -1
- package/dist/utils/file-walk.js +16 -3
- package/dist/utils/file-walk.js.map +1 -1
- package/package.json +6 -2
- package/src/__tests__/checkpoint.test.ts +2 -2
- package/src/__tests__/clean-state-extra.test.ts +1 -1
- package/src/__tests__/constraint-doctor.test.ts +1 -1
- package/src/__tests__/doctor-extra.test.ts +0 -9
- package/src/__tests__/effective-constraints.test.ts +21 -0
- package/src/__tests__/hooks-pipeline.test.ts +1 -1
- package/src/__tests__/iron-laws.test.ts +11 -0
- package/src/__tests__/passes-gate-extension.test.ts +3 -3
- package/src/__tests__/passes-gate-extra.test.ts +1 -1
- package/src/__tests__/performance-analyzer.test.ts +0 -2
- package/src/__tests__/traces.test.ts +1 -2
- package/src/architecture/cross-project-checker.ts +2 -2
- package/src/cli/commands/CONTEXT.md +1 -1
- package/src/cli/commands/__tests__/check-drift.test.ts +1 -1
- package/src/cli/commands/__tests__/check-skip-output.test.ts +0 -2
- package/src/cli/commands/__tests__/command.test.ts +1 -1
- package/src/cli/commands/__tests__/constraints-report.test.ts +1 -1
- package/src/cli/commands/__tests__/constraints-retire.test.ts +165 -4
- package/src/cli/commands/__tests__/failure.test.ts +0 -1
- package/src/cli/commands/__tests__/init.test.ts +40 -0
- package/src/cli/commands/__tests__/status-extra.test.ts +0 -2
- package/src/cli/commands/__tests__/status.test.ts +0 -2
- package/src/cli/commands/__tests__/sync-docs.test.ts +90 -0
- package/src/cli/commands/constraints-report.ts +2 -2
- package/src/cli/commands/constraints-retire.ts +114 -21
- package/src/cli/commands/doc-freshness-check.ts +1 -1
- package/src/cli/commands/init.ts +14 -14
- package/src/cli/commands/sync-docs/index.ts +20 -7
- package/src/cli/commands/sync-docs/project-reader.ts +10 -8
- package/src/cli/commands/validate.ts +3 -3
- package/src/cli/session-mining/text.ts +1 -1
- package/src/context/__tests__/progressive-loader.test.ts +6 -6
- package/src/core/CONTEXT.md +1 -1
- package/src/core/constraints/__tests__/injection-drift.test.ts +1 -1
- package/src/core/constraints/__tests__/interceptor.test.ts +3 -3
- package/src/core/constraints/definitions/iron-laws.ts +2 -2
- package/src/core/constraints/injection-drift.ts +1 -1
- package/src/core/effective-constraints.ts +2 -1
- package/src/core/project-config-loader.ts +8 -2
- package/src/gates/__tests__/acceptance.test.ts +0 -1
- package/src/gates/__tests__/command.test.ts +1 -1
- package/src/hooks/bootstrap.ts +1 -1
- package/src/knowledge/__tests__/doctor.test.ts +2 -2
- package/src/knowledge/__tests__/ingest.test.ts +2 -2
- package/src/knowledge/__tests__/migration.test.ts +0 -6
- package/src/knowledge/__tests__/store.test.ts +14 -1
- package/src/knowledge/store.ts +1 -1
- package/src/knowledge/types.ts +2 -0
- package/src/llm/__tests__/adapter.test.ts +1 -1
- package/src/monitoring/__tests__/knowledge-doctor.test.ts +0 -1
- package/src/monitoring/__tests__/performance-collector.test.ts +1 -2
- package/src/safety/output-guardrail.ts +2 -2
- package/src/spec/__tests__/annotation-checker.test.ts +0 -1
- package/src/spec/annotation-checker.ts +1 -1
- package/src/types/project-config.ts +12 -0
- package/src/utils/__tests__/file-walk.test.ts +53 -0
- package/src/utils/file-walk.ts +23 -3
- package/src/verification/__tests__/loop.test.ts +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* CommandGate 测试
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { CommandGate,
|
|
5
|
+
import { CommandGate, isCommandAllowed, getCommandRiskLevel, DEFAULT_COMMAND_BLACKLIST } from '../command';
|
|
6
6
|
|
|
7
7
|
describe('CommandGate', () => {
|
|
8
8
|
describe('check', () => {
|
package/src/hooks/bootstrap.ts
CHANGED
|
@@ -70,7 +70,7 @@ export async function bootstrapHarness(
|
|
|
70
70
|
const resolvedPath = projectPath || process.cwd();
|
|
71
71
|
|
|
72
72
|
// 1. 异步加载配置(S9 fix)
|
|
73
|
-
const {
|
|
73
|
+
const { mergedConstraints } = await loadConfigAsync(resolvedPath);
|
|
74
74
|
|
|
75
75
|
// 2. 初始化核心组件
|
|
76
76
|
const checker = ConstraintChecker.getInstance();
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import { FileKnowledgeStore as KnowledgeStore } from '../store';
|
|
8
|
-
import { KnowledgeLinter
|
|
8
|
+
import { KnowledgeLinter } from '../lint';
|
|
9
9
|
import { ReferenceTracker } from '../reference-tracker';
|
|
10
10
|
import { KnowledgeHealthScorer } from '../doctor';
|
|
11
|
-
import type { KnowledgeEntry
|
|
11
|
+
import type { KnowledgeEntry } from '../types';
|
|
12
12
|
|
|
13
13
|
describe('KnowledgeHealthScorer', () => {
|
|
14
14
|
const tempDir = path.join(process.cwd(), 'temp-test-knowledge-doctor');
|
|
@@ -245,7 +245,7 @@ describe('KnowledgeIngest', () => {
|
|
|
245
245
|
});
|
|
246
246
|
|
|
247
247
|
// After stripping [prefix], normalizing: "api超时导致请求失败" contains "api超时导致"
|
|
248
|
-
|
|
248
|
+
ingest.ingestEntry(
|
|
249
249
|
{ title: '[Triage Fix] API 超时导致', content: 'different content but same issue', type: 'pitfall' },
|
|
250
250
|
{ source: 'test', layer: 'system' },
|
|
251
251
|
);
|
|
@@ -287,7 +287,7 @@ describe('KnowledgeIngest', () => {
|
|
|
287
287
|
|
|
288
288
|
// Keywords: prisma, 连接, 超时, 导致, api, 请求, 失败
|
|
289
289
|
// Incoming: prisma, 超时, 请求, 失败 → 4/7 overlap
|
|
290
|
-
|
|
290
|
+
ingest.ingestEntry(
|
|
291
291
|
{ title: 'Prisma 超时导致请求失败', content: 'totally different content', type: 'pitfall' },
|
|
292
292
|
{ source: 'test', layer: 'system' },
|
|
293
293
|
);
|
|
@@ -37,12 +37,6 @@ describe('migrateKnowledgeEntries', () => {
|
|
|
37
37
|
fs.writeFileSync(path.join(tempDir, filename), raw, 'utf-8');
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
function readMeta(filename: string): Record<string, unknown> {
|
|
41
|
-
const raw = fs.readFileSync(path.join(tempDir, filename), 'utf-8');
|
|
42
|
-
const match = raw.match(/^---\n([\s\S]*?)\n---/)!;
|
|
43
|
-
return JSON.parse(JSON.stringify(eval(`(${match[1].replace(/(\w+):/g, '"$1":').replace(/'/g, '"')})`)));
|
|
44
|
-
}
|
|
45
|
-
|
|
46
40
|
it('should add consumptionMode and origin to entries missing them', () => {
|
|
47
41
|
writeEntry('DEC-001.md', {
|
|
48
42
|
id: 'DEC-001', type: 'decision', title: 'Test', maturity: 'draft',
|
|
@@ -184,6 +184,19 @@ describe('KnowledgeStore', () => {
|
|
|
184
184
|
});
|
|
185
185
|
|
|
186
186
|
describe('edge cases', () => {
|
|
187
|
+
it('should round-trip sourceReferences with entryId through save/load', () => {
|
|
188
|
+
const sourceRefs = [
|
|
189
|
+
{ workflow: 'test-flow', step: 'distill', commit: 'abc1234', timestamp: '2026-05-01', entryId: 'SRC-001' },
|
|
190
|
+
{ workflow: 'test-flow', timestamp: '2026-05-02' },
|
|
191
|
+
];
|
|
192
|
+
store.save(makeEntry({ id: 'DEC-001', sourceReferences: sourceRefs }));
|
|
193
|
+
const loaded = store.get('DEC-001');
|
|
194
|
+
expect(loaded?.sourceReferences).toStrictEqual(sourceRefs);
|
|
195
|
+
// 缺省 entryId 的 ref 不落 undefined 键:原始 frontmatter 中 entryId 只出现一次
|
|
196
|
+
const raw = fs.readFileSync(path.join(tempDir, 'decision-DEC-001.md'), 'utf-8');
|
|
197
|
+
expect(raw.match(/entryId/g)).toHaveLength(1);
|
|
198
|
+
});
|
|
199
|
+
|
|
187
200
|
it('should round-trip consumptionMode and origin through save/load', () => {
|
|
188
201
|
store.save(makeEntry({
|
|
189
202
|
id: 'DEC-001',
|
|
@@ -212,7 +225,7 @@ describe('KnowledgeStore', () => {
|
|
|
212
225
|
|
|
213
226
|
it('should create directory if it does not exist', () => {
|
|
214
227
|
const newDir = path.join(process.cwd(), 'temp-test-knowledge-nested', 'sub', 'deep');
|
|
215
|
-
|
|
228
|
+
new KnowledgeStore({ baseDir: newDir });
|
|
216
229
|
expect(fs.existsSync(newDir)).toBe(true);
|
|
217
230
|
fs.rmSync(path.join(process.cwd(), 'temp-test-knowledge-nested'), { recursive: true, force: true });
|
|
218
231
|
});
|
package/src/knowledge/store.ts
CHANGED
|
@@ -68,7 +68,7 @@ export class FileKnowledgeStore implements KnowledgeStore {
|
|
|
68
68
|
list(filter?: QueryFilter): KnowledgeEntry[] {
|
|
69
69
|
const index = this.readIndex();
|
|
70
70
|
const effectiveFilter: QueryFilter = { excludeArchived: true, ...filter };
|
|
71
|
-
|
|
71
|
+
const entries = index.filter(e => this.matchesFilter(e, effectiveFilter));
|
|
72
72
|
|
|
73
73
|
return entries.map(idx => {
|
|
74
74
|
const full = this.get(idx.id);
|
package/src/knowledge/types.ts
CHANGED
|
@@ -58,6 +58,8 @@ export interface SourceRef {
|
|
|
58
58
|
step?: string;
|
|
59
59
|
commit?: string;
|
|
60
60
|
timestamp: string;
|
|
61
|
+
/** ID of the source material entry this knowledge was distilled/evolved from (entry-level back-reference) */
|
|
62
|
+
entryId?: string;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
export interface ExecutionResult {
|
|
@@ -53,7 +53,7 @@ describe('LLM Adapter', () => {
|
|
|
53
53
|
it('应该抛出未实现错误', async () => {
|
|
54
54
|
const gen = adapter.streamChat([{ role: 'user', content: 'test' }]);
|
|
55
55
|
await expect(async () => {
|
|
56
|
-
for await (const _ of gen) {
|
|
56
|
+
for await (const _ of gen) { void _; }
|
|
57
57
|
}).rejects.toThrow('LLM streamChat 未实现');
|
|
58
58
|
});
|
|
59
59
|
});
|
|
@@ -226,7 +226,6 @@ describe('KnowledgeDoctor', () => {
|
|
|
226
226
|
|
|
227
227
|
it('critical 严重度扣 10 分', () => {
|
|
228
228
|
const doctor = new KnowledgeDoctor();
|
|
229
|
-
const issue: LintIssue = { type: 'contradiction', severity: 'high', entryId: 'e1', description: 'critical issue', suggestion: 'fix' };
|
|
230
229
|
// 直接构造 critical 诊断来测试 calculateHealthScore 的 critical 分支
|
|
231
230
|
// LintIssue severity 只有 low/medium/high,所以通过 checkDecay 的 high 来测试
|
|
232
231
|
const entry = makeEntry({ maturity: 'proven', lastReferenced: '2020-01-01T00:00:00Z' });
|
|
@@ -2,10 +2,9 @@
|
|
|
2
2
|
* PerformanceCollector 测试
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { describe, it, expect, beforeEach
|
|
5
|
+
import { describe, it, expect, beforeEach } from '@jest/globals';
|
|
6
6
|
import { PerformanceCollector } from '../performance-collector';
|
|
7
7
|
import * as fs from 'fs';
|
|
8
|
-
import * as path from 'path';
|
|
9
8
|
|
|
10
9
|
// Mock fs
|
|
11
10
|
jest.mock('fs', () => ({
|
|
@@ -11,7 +11,7 @@ import type { OutputSafetyCheckResult, OutputViolation, OutputGuardrailConfig }
|
|
|
11
11
|
|
|
12
12
|
const DEFAULT_SENSITIVE_PATTERNS: RegExp[] = [
|
|
13
13
|
// API keys
|
|
14
|
-
/(?:api[_-]?key|apikey)\s*[:=]\s*['"]?([a-zA-Z0-9_
|
|
14
|
+
/(?:api[_-]?key|apikey)\s*[:=]\s*['"]?([a-zA-Z0-9_-]{20,})['"]?/gi,
|
|
15
15
|
// AWS
|
|
16
16
|
/(?:AKIA|ASIA)[A-Z0-9]{16}/g,
|
|
17
17
|
// Generic secrets
|
|
@@ -21,7 +21,7 @@ const DEFAULT_SENSITIVE_PATTERNS: RegExp[] = [
|
|
|
21
21
|
// GitHub tokens
|
|
22
22
|
/gh[ps]_[A-Za-z0-9_]{36,}/g,
|
|
23
23
|
// Bearer tokens
|
|
24
|
-
/Bearer\s+[A-Za-z0-9_
|
|
24
|
+
/Bearer\s+[A-Za-z0-9_\-.]{20,}/g,
|
|
25
25
|
// Connection strings
|
|
26
26
|
/(?:mongodb|postgres|mysql|redis):\/\/[^\s'"]+/gi,
|
|
27
27
|
];
|
|
@@ -152,7 +152,7 @@ function parseJSDoc(lines: string[], startLine: number): SpecAnnotation | null {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
// @dependencies
|
|
155
|
-
const depsMatch = content.match(/@dependencies\s+([\w\-_,\s
|
|
155
|
+
const depsMatch = content.match(/@dependencies\s+([\w\-_,\s/]+)/);
|
|
156
156
|
if (depsMatch) {
|
|
157
157
|
annotation.dependencies = depsMatch[1]
|
|
158
158
|
.split(/[,\s]+/)
|
|
@@ -45,6 +45,18 @@ export interface CustomConstraintDefinition {
|
|
|
45
45
|
|
|
46
46
|
/** 是否启用(可选,默认 true) */
|
|
47
47
|
enabled?: boolean;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 退役元数据(#82 D6 统一落点)
|
|
51
|
+
*
|
|
52
|
+
* 存在即视为已退役:不进生效集、不注入 CLAUDE.md。恢复 = 删除该段。
|
|
53
|
+
* 落点在 custom-constraints.yml 条目内(一处真相,不拆 config.yml 第二处)。
|
|
54
|
+
*/
|
|
55
|
+
retired?: {
|
|
56
|
+
at?: string;
|
|
57
|
+
reason?: string;
|
|
58
|
+
stats?: { total: number; fail: number; failRate: number };
|
|
59
|
+
};
|
|
48
60
|
}
|
|
49
61
|
|
|
50
62
|
/**
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* file-walk 工具测试
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { findTsSourceFiles } from '../file-walk';
|
|
8
|
+
|
|
9
|
+
describe('findTsSourceFiles', () => {
|
|
10
|
+
const tempDir = path.join(process.cwd(), 'temp-test-file-walk');
|
|
11
|
+
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterAll(() => {
|
|
17
|
+
try {
|
|
18
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
19
|
+
} catch {
|
|
20
|
+
// ignore
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('默认只收集 .ts(排除 .d.ts),.tsx 不进入结果', () => {
|
|
25
|
+
const dir = path.join(tempDir, 'default-ts-only');
|
|
26
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
27
|
+
fs.writeFileSync(path.join(dir, 'a.ts'), '');
|
|
28
|
+
fs.writeFileSync(path.join(dir, 'b.d.ts'), '');
|
|
29
|
+
fs.writeFileSync(path.join(dir, 'c.tsx'), '');
|
|
30
|
+
|
|
31
|
+
const names = findTsSourceFiles(dir).map(f => path.basename(f)).sort();
|
|
32
|
+
expect(names).toEqual(['a.ts']);
|
|
33
|
+
|
|
34
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('includeTsx: true 时同时收集 .tsx,skipIndex 排除 index.ts/index.tsx', () => {
|
|
38
|
+
const dir = path.join(tempDir, 'include-tsx');
|
|
39
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
40
|
+
fs.writeFileSync(path.join(dir, 'a.ts'), '');
|
|
41
|
+
fs.writeFileSync(path.join(dir, 'b.d.ts'), '');
|
|
42
|
+
fs.writeFileSync(path.join(dir, 'c.tsx'), '');
|
|
43
|
+
fs.writeFileSync(path.join(dir, 'index.ts'), '');
|
|
44
|
+
fs.writeFileSync(path.join(dir, 'index.tsx'), '');
|
|
45
|
+
|
|
46
|
+
const names = findTsSourceFiles(dir, { includeTsx: true, skipIndex: true })
|
|
47
|
+
.map(f => path.basename(f))
|
|
48
|
+
.sort();
|
|
49
|
+
expect(names).toEqual(['a.ts', 'c.tsx']);
|
|
50
|
+
|
|
51
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
52
|
+
});
|
|
53
|
+
});
|
package/src/utils/file-walk.ts
CHANGED
|
@@ -53,6 +53,8 @@ export function walkFiles(root: string, options: FileWalkOptions = {}): string[]
|
|
|
53
53
|
export interface TsSourceWalkOptions {
|
|
54
54
|
/** 是否跳过 barrel 文件 index.ts,默认 false */
|
|
55
55
|
skipIndex?: boolean;
|
|
56
|
+
/** 是否同时收集 .tsx 文件,默认 false(只收集 .ts) */
|
|
57
|
+
includeTsx?: boolean;
|
|
56
58
|
/** 跳过的目录名,默认 node_modules/__tests__/dist */
|
|
57
59
|
skipDirs?: string[];
|
|
58
60
|
/** 是否跳过 `.` 开头的条目,默认 false */
|
|
@@ -60,11 +62,30 @@ export interface TsSourceWalkOptions {
|
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
/**
|
|
63
|
-
*
|
|
65
|
+
* 文件名是否为 TypeScript 源文件(includeTsx 时含 .tsx,排除 .d.ts 与可选 barrel index)
|
|
66
|
+
*
|
|
67
|
+
* findTsSourceFiles 的过滤谓词;需要同口径判断的调用方(如 sync-docs 顶层文件分支)
|
|
68
|
+
* 复用此函数,避免扩展名规则在多处漂移。
|
|
69
|
+
*/
|
|
70
|
+
export function isTsSourceFile(
|
|
71
|
+
name: string,
|
|
72
|
+
options: { skipIndex?: boolean; includeTsx?: boolean } = {}
|
|
73
|
+
): boolean {
|
|
74
|
+
const { skipIndex = false, includeTsx = false } = options;
|
|
75
|
+
return (
|
|
76
|
+
(name.endsWith('.ts') || (includeTsx && name.endsWith('.tsx'))) &&
|
|
77
|
+
!name.endsWith('.d.ts') &&
|
|
78
|
+
(!skipIndex || (name !== 'index.ts' && name !== 'index.tsx'))
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 递归收集 TypeScript 源文件(.ts,includeTsx 时含 .tsx,排除 .d.ts)
|
|
64
84
|
*/
|
|
65
85
|
export function findTsSourceFiles(root: string, options: TsSourceWalkOptions = {}): string[] {
|
|
66
86
|
const {
|
|
67
87
|
skipIndex = false,
|
|
88
|
+
includeTsx = false,
|
|
68
89
|
skipDirs = ['node_modules', '__tests__', 'dist'],
|
|
69
90
|
skipHidden = false,
|
|
70
91
|
} = options;
|
|
@@ -72,7 +93,6 @@ export function findTsSourceFiles(root: string, options: TsSourceWalkOptions = {
|
|
|
72
93
|
return walkFiles(root, {
|
|
73
94
|
skipDirs,
|
|
74
95
|
skipHidden,
|
|
75
|
-
filter: (name) =>
|
|
76
|
-
name.endsWith('.ts') && !name.endsWith('.d.ts') && (!skipIndex || name !== 'index.ts'),
|
|
96
|
+
filter: (name) => isTsSourceFile(name, { skipIndex, includeTsx }),
|
|
77
97
|
});
|
|
78
98
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { VerificationLoop } from '../loop';
|
|
6
|
-
import type { VerificationLoopConfig, GatherState
|
|
6
|
+
import type { VerificationLoopConfig, GatherState } from '../types';
|
|
7
7
|
|
|
8
8
|
describe('VerificationLoop', () => {
|
|
9
9
|
const baseConfig: VerificationLoopConfig = {
|