persona-harness 0.3.0-alpha.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/.persona/harness.jsonc +9 -0
- package/.persona/rules/backend/gradle-bootstrap.md +27 -0
- package/.persona/rules/backend/java-backend-bootstrap.md +28 -0
- package/.persona/rules/backend/java-common.md +22 -0
- package/.persona/rules/backend/layered-architecture.md +19 -0
- package/.persona/rules/backend/package-structure.md +21 -0
- package/.persona/rules/backend/spring-controller.md +19 -0
- package/.persona/rules/backend/spring-dto.md +21 -0
- package/.persona/rules/backend/spring-entity.md +22 -0
- package/.persona/rules/backend/spring-repository.md +22 -0
- package/.persona/rules/backend/spring-service.md +23 -0
- package/.persona/rules/backend/spring-test.md +32 -0
- package/.persona/rules/backend/step1-api-contract.md +29 -0
- package/.persona/rules/backend/step2-3-api-contract.md +24 -0
- package/.persona/rules/backend/validation-exception.md +18 -0
- package/.persona/rules/clean-code/abstraction.md +18 -0
- package/.persona/rules/clean-code/common.md +21 -0
- package/.persona/rules/clean-code/method-design.md +20 -0
- package/.persona/rules/clean-code/naming.md +19 -0
- package/.persona/rules/clean-code/oop.md +18 -0
- package/.persona/rules/clean-code/testability.md +19 -0
- package/CHANGELOG.md +40 -0
- package/LICENSE +201 -0
- package/README.ja.md +95 -0
- package/README.ko.md +95 -0
- package/README.md +125 -0
- package/README.zh-cn.md +95 -0
- package/dist/cli/bearshell.d.ts +12 -0
- package/dist/cli/bearshell.js +189 -0
- package/dist/cli/bearshell.js.map +1 -0
- package/dist/cli/history.d.ts +15 -0
- package/dist/cli/history.js +156 -0
- package/dist/cli/history.js.map +1 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.js +117 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +21 -0
- package/dist/cli/init.js +194 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/intake-profile.d.ts +52 -0
- package/dist/cli/intake-profile.js +167 -0
- package/dist/cli/intake-profile.js.map +1 -0
- package/dist/cli/intake.d.ts +14 -0
- package/dist/cli/intake.js +209 -0
- package/dist/cli/intake.js.map +1 -0
- package/dist/cli/plan-command.d.ts +4 -0
- package/dist/cli/plan-command.js +130 -0
- package/dist/cli/plan-command.js.map +1 -0
- package/dist/cli/plan-status.d.ts +11 -0
- package/dist/cli/plan-status.js +41 -0
- package/dist/cli/plan-status.js.map +1 -0
- package/dist/cli/plan.d.ts +10 -0
- package/dist/cli/plan.js +199 -0
- package/dist/cli/plan.js.map +1 -0
- package/dist/cli/policy.d.ts +7 -0
- package/dist/cli/policy.js +139 -0
- package/dist/cli/policy.js.map +1 -0
- package/dist/cli/report-status.d.ts +13 -0
- package/dist/cli/report-status.js +40 -0
- package/dist/cli/report-status.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/phase0/drift-detector.d.ts +24 -0
- package/dist/phase0/drift-detector.js +334 -0
- package/dist/phase0/drift-detector.js.map +1 -0
- package/dist/phase0/evidence.d.ts +9 -0
- package/dist/phase0/evidence.js +36 -0
- package/dist/phase0/evidence.js.map +1 -0
- package/dist/phase0/file-role.d.ts +5 -0
- package/dist/phase0/file-role.js +55 -0
- package/dist/phase0/file-role.js.map +1 -0
- package/dist/phase0/harness-config.d.ts +12 -0
- package/dist/phase0/harness-config.js +115 -0
- package/dist/phase0/harness-config.js.map +1 -0
- package/dist/phase0/hooks.d.ts +8 -0
- package/dist/phase0/hooks.js +127 -0
- package/dist/phase0/hooks.js.map +1 -0
- package/dist/phase0/injection.d.ts +2 -0
- package/dist/phase0/injection.js +77 -0
- package/dist/phase0/injection.js.map +1 -0
- package/dist/phase0/java-role-discovery.d.ts +6 -0
- package/dist/phase0/java-role-discovery.js +90 -0
- package/dist/phase0/java-role-discovery.js.map +1 -0
- package/dist/phase0/messages.d.ts +2 -0
- package/dist/phase0/messages.js +30 -0
- package/dist/phase0/messages.js.map +1 -0
- package/dist/phase0/policy-overlay.d.ts +12 -0
- package/dist/phase0/policy-overlay.js +171 -0
- package/dist/phase0/policy-overlay.js.map +1 -0
- package/dist/phase0/project-profile.d.ts +1 -0
- package/dist/phase0/project-profile.js +148 -0
- package/dist/phase0/project-profile.js.map +1 -0
- package/dist/phase0/rule-catalog.d.ts +14 -0
- package/dist/phase0/rule-catalog.js +77 -0
- package/dist/phase0/rule-catalog.js.map +1 -0
- package/dist/phase0/rule-diagnostics-report.d.ts +17 -0
- package/dist/phase0/rule-diagnostics-report.js +51 -0
- package/dist/phase0/rule-diagnostics-report.js.map +1 -0
- package/dist/phase0/rule-frontmatter-diagnostics.d.ts +19 -0
- package/dist/phase0/rule-frontmatter-diagnostics.js +65 -0
- package/dist/phase0/rule-frontmatter-diagnostics.js.map +1 -0
- package/dist/phase0/rule-frontmatter.d.ts +23 -0
- package/dist/phase0/rule-frontmatter.js +172 -0
- package/dist/phase0/rule-frontmatter.js.map +1 -0
- package/dist/phase0/rule-glob.d.ts +2 -0
- package/dist/phase0/rule-glob.js +38 -0
- package/dist/phase0/rule-glob.js.map +1 -0
- package/dist/phase0/rule-loader.d.ts +13 -0
- package/dist/phase0/rule-loader.js +143 -0
- package/dist/phase0/rule-loader.js.map +1 -0
- package/dist/phase0/shared-skill-router.d.ts +14 -0
- package/dist/phase0/shared-skill-router.js +85 -0
- package/dist/phase0/shared-skill-router.js.map +1 -0
- package/dist/phase0/store.d.ts +6 -0
- package/dist/phase0/store.js +14 -0
- package/dist/phase0/store.js.map +1 -0
- package/dist/phase0/target-file.d.ts +2 -0
- package/dist/phase0/target-file.js +41 -0
- package/dist/phase0/target-file.js.map +1 -0
- package/dist/phase0/types.d.ts +38 -0
- package/dist/phase0/types.js +2 -0
- package/dist/phase0/types.js.map +1 -0
- package/dist/phase1/observer/controller-repository-observer.d.ts +17 -0
- package/dist/phase1/observer/controller-repository-observer.js +210 -0
- package/dist/phase1/observer/controller-repository-observer.js.map +1 -0
- package/dist/phase1/observer/controller-sql-observer.d.ts +20 -0
- package/dist/phase1/observer/controller-sql-observer.js +148 -0
- package/dist/phase1/observer/controller-sql-observer.js.map +1 -0
- package/dist/phase1/observer/java-source.d.ts +9 -0
- package/dist/phase1/observer/java-source.js +88 -0
- package/dist/phase1/observer/java-source.js.map +1 -0
- package/dist/phase1/observer/report.d.ts +52 -0
- package/dist/phase1/observer/report.js +173 -0
- package/dist/phase1/observer/report.js.map +1 -0
- package/dist/phase1/observer/service-storage-observer.d.ts +20 -0
- package/dist/phase1/observer/service-storage-observer.js +155 -0
- package/dist/phase1/observer/service-storage-observer.js.map +1 -0
- package/dist/phase1/observer/test-contract-anchor-matchers.d.ts +10 -0
- package/dist/phase1/observer/test-contract-anchor-matchers.js +198 -0
- package/dist/phase1/observer/test-contract-anchor-matchers.js.map +1 -0
- package/dist/phase1/observer/test-contract-observer.d.ts +21 -0
- package/dist/phase1/observer/test-contract-observer.js +70 -0
- package/dist/phase1/observer/test-contract-observer.js.map +1 -0
- package/docs/README.md +34 -0
- package/docs/current/README.md +35 -0
- package/docs/current/java-backend-mvp-install-guide.md +160 -0
- package/docs/current/persona-harness-detailed-usage.md +782 -0
- package/docs/current/release/README.md +6 -0
- package/docs/current/release/release-checklist.md +113 -0
- package/docs/current/release/release-notes-template.md +68 -0
- package/docs/current/v0.3.0-alpha-publish-readiness.md +185 -0
- package/docs/current/v0.3.0-external-tester-feedback-template.md +214 -0
- package/docs/current/v0.3.0-external-tester-guide.md +217 -0
- package/docs/current/v0.3.0-gradle-spring-build-guidance.md +100 -0
- package/package.json +87 -0
- package/packages/shared-skills/skills/programming/SKILL.md +490 -0
- package/packages/shared-skills/skills/programming/references/java/README.md +193 -0
- package/packages/shared-skills/skills/programming/references/java/anti-patterns.md +85 -0
- package/packages/shared-skills/skills/programming/references/java/application-layer.md +200 -0
- package/packages/shared-skills/skills/programming/references/java/architecture.md +152 -0
- package/packages/shared-skills/skills/programming/references/java/backend.md +152 -0
- package/packages/shared-skills/skills/programming/references/java/code-quality-refactoring.md +146 -0
- package/packages/shared-skills/skills/programming/references/java/concurrency-discipline.md +98 -0
- package/packages/shared-skills/skills/programming/references/java/domain-model.md +214 -0
- package/packages/shared-skills/skills/programming/references/java/error-handling.md +179 -0
- package/packages/shared-skills/skills/programming/references/java/foundations.md +49 -0
- package/packages/shared-skills/skills/programming/references/java/java-idioms.md +108 -0
- package/packages/shared-skills/skills/programming/references/java/language-core.md +96 -0
- package/packages/shared-skills/skills/programming/references/java/method-and-naming.md +164 -0
- package/packages/shared-skills/skills/programming/references/java/object-collaboration.md +140 -0
- package/packages/shared-skills/skills/programming/references/java/performance-discipline.md +115 -0
- package/packages/shared-skills/skills/programming/references/java/repository-pattern.md +181 -0
- package/packages/shared-skills/skills/programming/references/java/technology-seams.md +92 -0
- package/packages/shared-skills/skills/programming/references/java/test-design.md +149 -0
- package/packages/shared-skills/skills/programming/references/java/testing.md +188 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const POLICY_OVERLAY_PATH = ".persona/policies/overlay.jsonc";
|
|
4
|
+
const SUPPORTED_SCHEMA = "persona.policy-overlay.v1";
|
|
5
|
+
const SUPPORTED_ROLE = "backend";
|
|
6
|
+
const SUPPORTED_MVP = "java-spring-clean-code";
|
|
7
|
+
const DEFAULT_MAX_BULLETS_PER_SOURCE = 5;
|
|
8
|
+
function inactiveOverlay(diagnostics = []) {
|
|
9
|
+
return {
|
|
10
|
+
summaryLines: [],
|
|
11
|
+
metadata: {
|
|
12
|
+
enabled: false,
|
|
13
|
+
sources: [],
|
|
14
|
+
diagnostics,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function stripJsonComments(input) {
|
|
19
|
+
let output = "";
|
|
20
|
+
let index = 0;
|
|
21
|
+
let inString = false;
|
|
22
|
+
let escaped = false;
|
|
23
|
+
while (index < input.length) {
|
|
24
|
+
const current = input[index];
|
|
25
|
+
const next = input[index + 1];
|
|
26
|
+
if (inString) {
|
|
27
|
+
output += current;
|
|
28
|
+
if (escaped) {
|
|
29
|
+
escaped = false;
|
|
30
|
+
}
|
|
31
|
+
else if (current === "\\") {
|
|
32
|
+
escaped = true;
|
|
33
|
+
}
|
|
34
|
+
else if (current === "\"") {
|
|
35
|
+
inString = false;
|
|
36
|
+
}
|
|
37
|
+
index += 1;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (current === "\"") {
|
|
41
|
+
inString = true;
|
|
42
|
+
output += current;
|
|
43
|
+
index += 1;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (current === "/" && next === "/") {
|
|
47
|
+
while (index < input.length && input[index] !== "\n") {
|
|
48
|
+
index += 1;
|
|
49
|
+
}
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (current === "/" && next === "*") {
|
|
53
|
+
index += 2;
|
|
54
|
+
while (index < input.length && !(input[index] === "*" && input[index + 1] === "/")) {
|
|
55
|
+
index += 1;
|
|
56
|
+
}
|
|
57
|
+
index += 2;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
output += current;
|
|
61
|
+
index += 1;
|
|
62
|
+
}
|
|
63
|
+
return output;
|
|
64
|
+
}
|
|
65
|
+
function isRecord(value) {
|
|
66
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
67
|
+
}
|
|
68
|
+
function maxBulletsPerSource(value) {
|
|
69
|
+
if (!isRecord(value) || !isRecord(value.limits)) {
|
|
70
|
+
return DEFAULT_MAX_BULLETS_PER_SOURCE;
|
|
71
|
+
}
|
|
72
|
+
const maxBullets = value.limits.maxBulletsPerSource;
|
|
73
|
+
return typeof maxBullets === "number" && Number.isInteger(maxBullets) && maxBullets > 0
|
|
74
|
+
? maxBullets
|
|
75
|
+
: DEFAULT_MAX_BULLETS_PER_SOURCE;
|
|
76
|
+
}
|
|
77
|
+
function isSupportedOverlay(value) {
|
|
78
|
+
if (!isRecord(value) || value.schema !== SUPPORTED_SCHEMA || !isRecord(value.scope)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return value.scope.role === SUPPORTED_ROLE && value.scope.mvp === SUPPORTED_MVP && value.scope.productized === false;
|
|
82
|
+
}
|
|
83
|
+
function readSourcePath(value, sourceName) {
|
|
84
|
+
if (!isRecord(value) || !isRecord(value.sources)) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
const sourcePath = value.sources[sourceName];
|
|
88
|
+
return typeof sourcePath === "string" && sourcePath.trim().length > 0 ? sourcePath.trim() : undefined;
|
|
89
|
+
}
|
|
90
|
+
function extractBullets(markdown, maxBullets) {
|
|
91
|
+
const bullets = [];
|
|
92
|
+
for (const line of markdown.split(/\r?\n/)) {
|
|
93
|
+
const match = line.match(/^\s*-\s+(.+?)\s*$/);
|
|
94
|
+
const bullet = match?.[1]?.trim();
|
|
95
|
+
if (bullet === undefined || bullet.length === 0) {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
bullets.push(`- ${bullet}`);
|
|
99
|
+
if (bullets.length >= maxBullets) {
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return bullets;
|
|
104
|
+
}
|
|
105
|
+
function readPolicySource(projectDir, overlay, name, heading, maxBullets) {
|
|
106
|
+
const sourcePath = readSourcePath(overlay, name);
|
|
107
|
+
if (sourcePath === undefined) {
|
|
108
|
+
return { diagnostics: [`missing ${name} policy source`] };
|
|
109
|
+
}
|
|
110
|
+
const absolutePath = join(projectDir, sourcePath);
|
|
111
|
+
if (!existsSync(absolutePath)) {
|
|
112
|
+
return { diagnostics: [`missing ${name} policy file: ${sourcePath}`] };
|
|
113
|
+
}
|
|
114
|
+
const bullets = extractBullets(readFileSync(absolutePath, "utf8"), maxBullets);
|
|
115
|
+
return bullets.length > 0
|
|
116
|
+
? { source: { name, heading, path: sourcePath, bullets }, diagnostics: [] }
|
|
117
|
+
: { diagnostics: [`empty ${name} policy file: ${sourcePath}`] };
|
|
118
|
+
}
|
|
119
|
+
function formatSummary(sources) {
|
|
120
|
+
return [
|
|
121
|
+
"정책/철학 오버레이:",
|
|
122
|
+
"우선순위: company > personal > Clean Code baseline",
|
|
123
|
+
"",
|
|
124
|
+
...sources.flatMap((source) => [source.heading, ...source.bullets, ""]),
|
|
125
|
+
"오버레이 사용 원칙:",
|
|
126
|
+
"- README, 현재 사용자 지시, accepted plan의 기능 요구사항이 우선한다.",
|
|
127
|
+
"- company policy는 personal philosophy보다 우선한다.",
|
|
128
|
+
"- 이 오버레이는 rule enforcement나 product-quality 보증이 아니다.",
|
|
129
|
+
];
|
|
130
|
+
}
|
|
131
|
+
export function loadBackendPolicyOverlay(projectDir) {
|
|
132
|
+
const overlayPath = join(projectDir, POLICY_OVERLAY_PATH);
|
|
133
|
+
if (!existsSync(overlayPath)) {
|
|
134
|
+
return inactiveOverlay();
|
|
135
|
+
}
|
|
136
|
+
let parsed;
|
|
137
|
+
try {
|
|
138
|
+
parsed = JSON.parse(stripJsonComments(readFileSync(overlayPath, "utf8")));
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (error instanceof SyntaxError) {
|
|
142
|
+
return inactiveOverlay(["malformed overlay.jsonc"]);
|
|
143
|
+
}
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
if (!isRecord(parsed)) {
|
|
147
|
+
return inactiveOverlay(["overlay.jsonc must contain an object"]);
|
|
148
|
+
}
|
|
149
|
+
if (parsed.enabled === false) {
|
|
150
|
+
return inactiveOverlay();
|
|
151
|
+
}
|
|
152
|
+
if (!isSupportedOverlay(parsed)) {
|
|
153
|
+
return inactiveOverlay(["unsupported policy overlay scope"]);
|
|
154
|
+
}
|
|
155
|
+
const maxBullets = maxBulletsPerSource(parsed);
|
|
156
|
+
const company = readPolicySource(projectDir, parsed, "company", "Company policy:", maxBullets);
|
|
157
|
+
const personal = readPolicySource(projectDir, parsed, "personal", "Personal philosophy:", maxBullets);
|
|
158
|
+
const sources = [company.source, personal.source].filter((source) => source !== undefined);
|
|
159
|
+
const diagnostics = [...company.diagnostics, ...personal.diagnostics];
|
|
160
|
+
return sources.length > 0
|
|
161
|
+
? {
|
|
162
|
+
summaryLines: formatSummary(sources),
|
|
163
|
+
metadata: {
|
|
164
|
+
enabled: true,
|
|
165
|
+
sources: sources.map((source) => source.name),
|
|
166
|
+
diagnostics,
|
|
167
|
+
},
|
|
168
|
+
}
|
|
169
|
+
: inactiveOverlay(diagnostics);
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=policy-overlay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-overlay.js","sourceRoot":"","sources":["../../src/phase0/policy-overlay.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function loadBackendProjectProfileSummary(projectDir: string): readonly string[];
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
const PROFILE_PATH = ".persona/project-profile.jsonc";
|
|
4
|
+
const SUPPORTED_SCHEMA = "persona.project-profile.v1";
|
|
5
|
+
const SUPPORTED_ROLE = "backend";
|
|
6
|
+
const SUPPORTED_MVP = "java-spring-clean-code";
|
|
7
|
+
const SUMMARY_ORDER = [
|
|
8
|
+
"project-context",
|
|
9
|
+
"project-goal",
|
|
10
|
+
"project-scale",
|
|
11
|
+
"application-type",
|
|
12
|
+
"storage",
|
|
13
|
+
"persistence-technology",
|
|
14
|
+
"migration-style",
|
|
15
|
+
"package-style",
|
|
16
|
+
"architecture-style",
|
|
17
|
+
"boundary-strictness",
|
|
18
|
+
];
|
|
19
|
+
function stripJsonComments(input) {
|
|
20
|
+
let output = "";
|
|
21
|
+
let index = 0;
|
|
22
|
+
let inString = false;
|
|
23
|
+
let escaped = false;
|
|
24
|
+
while (index < input.length) {
|
|
25
|
+
const current = input[index];
|
|
26
|
+
const next = input[index + 1];
|
|
27
|
+
if (inString) {
|
|
28
|
+
output += current;
|
|
29
|
+
if (escaped) {
|
|
30
|
+
escaped = false;
|
|
31
|
+
}
|
|
32
|
+
else if (current === "\\") {
|
|
33
|
+
escaped = true;
|
|
34
|
+
}
|
|
35
|
+
else if (current === "\"") {
|
|
36
|
+
inString = false;
|
|
37
|
+
}
|
|
38
|
+
index += 1;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (current === "\"") {
|
|
42
|
+
inString = true;
|
|
43
|
+
output += current;
|
|
44
|
+
index += 1;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (current === "/" && next === "/") {
|
|
48
|
+
while (index < input.length && input[index] !== "\n") {
|
|
49
|
+
index += 1;
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (current === "/" && next === "*") {
|
|
54
|
+
index += 2;
|
|
55
|
+
while (index < input.length && !(input[index] === "*" && input[index + 1] === "/")) {
|
|
56
|
+
index += 1;
|
|
57
|
+
}
|
|
58
|
+
index += 2;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
output += current;
|
|
62
|
+
index += 1;
|
|
63
|
+
}
|
|
64
|
+
return output;
|
|
65
|
+
}
|
|
66
|
+
function isRecord(value) {
|
|
67
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
68
|
+
}
|
|
69
|
+
function readQuestion(value) {
|
|
70
|
+
if (!isRecord(value) || typeof value.id !== "string") {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
if (typeof value.answer === "string" && value.answer.trim() !== "") {
|
|
74
|
+
return { id: value.id, answer: value.answer.trim() };
|
|
75
|
+
}
|
|
76
|
+
if (value.answer === null) {
|
|
77
|
+
return { id: value.id, answer: null };
|
|
78
|
+
}
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
function readQuestions(value) {
|
|
82
|
+
if (!Array.isArray(value)) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
return value.flatMap((item) => {
|
|
86
|
+
const question = readQuestion(item);
|
|
87
|
+
return question === undefined ? [] : [question];
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function isSupportedBackendProfile(value) {
|
|
91
|
+
if (!isRecord(value) || value.schema !== SUPPORTED_SCHEMA || !isRecord(value.scope)) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return value.scope.role === SUPPORTED_ROLE && value.scope.mvp === SUPPORTED_MVP;
|
|
95
|
+
}
|
|
96
|
+
function answeredQuestionMap(questions) {
|
|
97
|
+
const answers = new Map();
|
|
98
|
+
for (const question of questions) {
|
|
99
|
+
if (question.answer !== null) {
|
|
100
|
+
answers.set(question.id, question.answer);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return answers;
|
|
104
|
+
}
|
|
105
|
+
function readProjectNote(value) {
|
|
106
|
+
if (!isRecord(value) || !isRecord(value.notes) || typeof value.notes.project !== "string") {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const note = value.notes.project.trim();
|
|
110
|
+
return note.length > 0 ? note : undefined;
|
|
111
|
+
}
|
|
112
|
+
function formatSummaryLines(answers, projectNote) {
|
|
113
|
+
const answerLines = SUMMARY_ORDER.flatMap((id) => {
|
|
114
|
+
const answer = answers.get(id);
|
|
115
|
+
return answer === undefined ? [] : [`- ${id}: ${answer}`];
|
|
116
|
+
});
|
|
117
|
+
const noteLines = projectNote === undefined ? [] : [`- notes.project: ${projectNote}`];
|
|
118
|
+
return [
|
|
119
|
+
"프로젝트 프로필 요약:",
|
|
120
|
+
...(answerLines.length > 0 || noteLines.length > 0 ? [...answerLines, ...noteLines] : ["- 응답된 항목 없음"]),
|
|
121
|
+
"",
|
|
122
|
+
"프로필 사용 원칙:",
|
|
123
|
+
"- 이 요약은 구현 전 architecture/technology plan 참고용이다.",
|
|
124
|
+
"- 사용자의 README/요구사항과 명시 지시가 우선한다.",
|
|
125
|
+
"- 이 요약은 rule enforcement나 product-quality 보증이 아니다.",
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
export function loadBackendProjectProfileSummary(projectDir) {
|
|
129
|
+
const profilePath = join(projectDir, PROFILE_PATH);
|
|
130
|
+
if (!existsSync(profilePath)) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
let parsed;
|
|
134
|
+
try {
|
|
135
|
+
parsed = JSON.parse(stripJsonComments(readFileSync(profilePath, "utf8")));
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
if (error instanceof SyntaxError) {
|
|
139
|
+
return [];
|
|
140
|
+
}
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
if (!isSupportedBackendProfile(parsed)) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
return formatSummaryLines(answeredQuestionMap(readQuestions(parsed.questions)), readProjectNote(parsed));
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=project-profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-profile.js","sourceRoot":"","sources":["../../src/phase0/project-profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FileRole } from "./types.js";
|
|
2
|
+
import { type Phase0Scenario, type RuleMetadata } from "./rule-frontmatter.js";
|
|
3
|
+
import type { RuleFrontmatterDiagnostic } from "./rule-frontmatter-diagnostics.js";
|
|
4
|
+
export type { Phase0Scenario } from "./rule-frontmatter.js";
|
|
5
|
+
export type RuleCatalogEntry = {
|
|
6
|
+
readonly path: string;
|
|
7
|
+
readonly absolutePath: string;
|
|
8
|
+
readonly metadata: RuleMetadata;
|
|
9
|
+
readonly diagnostics: readonly RuleFrontmatterDiagnostic[];
|
|
10
|
+
readonly policies: readonly string[];
|
|
11
|
+
};
|
|
12
|
+
export declare function loadRuleCatalog(projectDir: string): RuleCatalogEntry[];
|
|
13
|
+
export declare function targetPathForMatching(projectDir: string, fileRole: FileRole, targetFile?: string): string;
|
|
14
|
+
export declare function isRuleEligibleForTarget(entry: RuleCatalogEntry, fileRole: FileRole, scenario: Phase0Scenario, targetPath: string): boolean;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, join, relative, sep } from "node:path";
|
|
3
|
+
import { loadHarnessConfig, resolveConfiguredPath } from "./harness-config.js";
|
|
4
|
+
import { matchesAnyGlob, normalizePath } from "./rule-glob.js";
|
|
5
|
+
import { extractBulletPolicies, parseRuleFrontmatter, } from "./rule-frontmatter.js";
|
|
6
|
+
function listMarkdownFiles(directory) {
|
|
7
|
+
return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
8
|
+
const path = join(directory, entry.name);
|
|
9
|
+
if (entry.isDirectory()) {
|
|
10
|
+
return listMarkdownFiles(path);
|
|
11
|
+
}
|
|
12
|
+
return entry.isFile() && entry.name.endsWith(".md") ? [path] : [];
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export function loadRuleCatalog(projectDir) {
|
|
16
|
+
const config = loadHarnessConfig(projectDir);
|
|
17
|
+
const rulesDir = resolveConfiguredPath(projectDir, config.rulesDir);
|
|
18
|
+
if (!existsSync(rulesDir)) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
return listMarkdownFiles(rulesDir)
|
|
22
|
+
.sort()
|
|
23
|
+
.map((absolutePath) => {
|
|
24
|
+
const rulePath = normalizePath(relative(rulesDir, absolutePath).split(sep).join("/"));
|
|
25
|
+
const markdown = readFileSync(absolutePath, "utf8");
|
|
26
|
+
const frontmatter = parseRuleFrontmatter(rulePath, markdown);
|
|
27
|
+
return {
|
|
28
|
+
path: rulePath,
|
|
29
|
+
absolutePath,
|
|
30
|
+
metadata: frontmatter.metadata,
|
|
31
|
+
diagnostics: frontmatter.diagnostics,
|
|
32
|
+
policies: extractBulletPolicies(markdown),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function syntheticTargetForRole(fileRole) {
|
|
37
|
+
if (fileRole === "controller")
|
|
38
|
+
return "src/main/java/com/example/ReservationController.java";
|
|
39
|
+
if (fileRole === "service")
|
|
40
|
+
return "src/main/java/com/example/ReservationService.java";
|
|
41
|
+
if (fileRole === "repository")
|
|
42
|
+
return "src/main/java/com/example/ReservationRepository.java";
|
|
43
|
+
if (fileRole === "entity")
|
|
44
|
+
return "src/main/java/com/example/ReservationEntity.java";
|
|
45
|
+
if (fileRole === "domain")
|
|
46
|
+
return "src/main/java/com/example/domain/Reservation.java";
|
|
47
|
+
if (fileRole === "request-dto")
|
|
48
|
+
return "src/main/java/com/example/ReservationRequest.java";
|
|
49
|
+
if (fileRole === "response-dto")
|
|
50
|
+
return "src/main/java/com/example/ReservationResponse.java";
|
|
51
|
+
if (fileRole === "exception")
|
|
52
|
+
return "src/main/java/com/example/ReservationException.java";
|
|
53
|
+
if (fileRole === "test")
|
|
54
|
+
return "src/test/java/com/example/ReservationTest.java";
|
|
55
|
+
return "src/main/java/com/example/Reservation.java";
|
|
56
|
+
}
|
|
57
|
+
export function targetPathForMatching(projectDir, fileRole, targetFile) {
|
|
58
|
+
if (targetFile === undefined) {
|
|
59
|
+
return syntheticTargetForRole(fileRole);
|
|
60
|
+
}
|
|
61
|
+
const normalizedTarget = normalizePath(targetFile);
|
|
62
|
+
if (!isAbsolute(targetFile)) {
|
|
63
|
+
return normalizedTarget;
|
|
64
|
+
}
|
|
65
|
+
const relativeTarget = normalizePath(relative(projectDir, targetFile));
|
|
66
|
+
return relativeTarget.startsWith("..") ? normalizedTarget : relativeTarget;
|
|
67
|
+
}
|
|
68
|
+
function matchesRuleGlob(entry, targetPath) {
|
|
69
|
+
return matchesAnyGlob(entry.metadata.globs, targetPath);
|
|
70
|
+
}
|
|
71
|
+
function matchesRuleScenario(entry, scenario) {
|
|
72
|
+
return entry.metadata.scenario === "all" || entry.metadata.scenario === scenario;
|
|
73
|
+
}
|
|
74
|
+
export function isRuleEligibleForTarget(entry, fileRole, scenario, targetPath) {
|
|
75
|
+
return matchesRuleGlob(entry, targetPath) && matchesRuleScenario(entry, scenario);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=rule-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-catalog.js","sourceRoot":"","sources":["../../src/phase0/rule-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RuleFrontmatterDiagnostic } from "./rule-frontmatter-diagnostics.js";
|
|
2
|
+
export type RuleDiagnosticsFinding = "PASS" | "WARN";
|
|
3
|
+
export type RuleDiagnosticReportItem = {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly diagnostic: RuleFrontmatterDiagnostic;
|
|
6
|
+
};
|
|
7
|
+
export type RuleDiagnosticsSummary = {
|
|
8
|
+
readonly projectDir: string;
|
|
9
|
+
readonly finding: RuleDiagnosticsFinding;
|
|
10
|
+
readonly ruleCount: number;
|
|
11
|
+
readonly diagnosticCount: number;
|
|
12
|
+
readonly diagnostics: readonly RuleDiagnosticReportItem[];
|
|
13
|
+
};
|
|
14
|
+
export declare function defaultRuleDiagnosticsReportPath(projectDir: string): string;
|
|
15
|
+
export declare function summarizeRuleDiagnostics(projectDir: string): RuleDiagnosticsSummary;
|
|
16
|
+
export declare function renderRuleDiagnosticsReport(summary: RuleDiagnosticsSummary): string;
|
|
17
|
+
export declare function writeRuleDiagnosticsReport(projectDir: string, outputPath: string): RuleDiagnosticsSummary;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { loadHarnessConfig, resolveConfiguredPath } from "./harness-config.js";
|
|
4
|
+
import { loadRuleCatalog } from "./rule-catalog.js";
|
|
5
|
+
export function defaultRuleDiagnosticsReportPath(projectDir) {
|
|
6
|
+
const config = loadHarnessConfig(projectDir);
|
|
7
|
+
return join(resolveConfiguredPath(projectDir, config.evidenceDir), "phase-next", "rule-diagnostics-report.md");
|
|
8
|
+
}
|
|
9
|
+
export function summarizeRuleDiagnostics(projectDir) {
|
|
10
|
+
const catalog = loadRuleCatalog(projectDir);
|
|
11
|
+
const diagnostics = catalog.flatMap((entry) => entry.diagnostics.map((diagnostic) => ({
|
|
12
|
+
path: entry.path,
|
|
13
|
+
diagnostic,
|
|
14
|
+
})));
|
|
15
|
+
return {
|
|
16
|
+
projectDir,
|
|
17
|
+
finding: diagnostics.length === 0 ? "PASS" : "WARN",
|
|
18
|
+
ruleCount: catalog.length,
|
|
19
|
+
diagnosticCount: diagnostics.length,
|
|
20
|
+
diagnostics,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function diagnosticField(diagnostic) {
|
|
24
|
+
return diagnostic.field ?? "-";
|
|
25
|
+
}
|
|
26
|
+
export function renderRuleDiagnosticsReport(summary) {
|
|
27
|
+
const lines = [
|
|
28
|
+
"# PersonaHarnessRule Diagnostics Report",
|
|
29
|
+
"",
|
|
30
|
+
`Project: ${summary.projectDir}`,
|
|
31
|
+
`Finding: ${summary.finding}`,
|
|
32
|
+
`Rules: ${summary.ruleCount}`,
|
|
33
|
+
`Diagnostics: ${summary.diagnosticCount}`,
|
|
34
|
+
"",
|
|
35
|
+
"## Diagnostics",
|
|
36
|
+
"",
|
|
37
|
+
];
|
|
38
|
+
if (summary.diagnostics.length === 0) {
|
|
39
|
+
return `${lines.concat("No rule frontmatter diagnostics found.", "").join("\n")}`;
|
|
40
|
+
}
|
|
41
|
+
return `${lines
|
|
42
|
+
.concat("| Rule | Code | Field | Message |", "| --- | --- | --- | --- |", ...summary.diagnostics.map((item) => `| ${item.path} | ${item.diagnostic.code} | ${diagnosticField(item.diagnostic)} | ${item.diagnostic.message} |`), "", "## Decision", "", "Diagnostics are report-only. They do not block rule loading, rule selection, tests, typecheck, build, or injection.", "")
|
|
43
|
+
.join("\n")}`;
|
|
44
|
+
}
|
|
45
|
+
export function writeRuleDiagnosticsReport(projectDir, outputPath) {
|
|
46
|
+
const summary = summarizeRuleDiagnostics(projectDir);
|
|
47
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
48
|
+
writeFileSync(outputPath, `${renderRuleDiagnosticsReport(summary)}\n`);
|
|
49
|
+
return summary;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=rule-diagnostics-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-diagnostics-report.js","sourceRoot":"","sources":["../../src/phase0/rule-diagnostics-report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEzC,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAC9E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAkBnD,MAAM,UAAU,gCAAgC,CAAC,UAAkB;IACjE,MAAM,MAAM,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAC5C,OAAO,IAAI,CAAC,qBAAqB,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,YAAY,EAAE,4BAA4B,CAAC,CAAA;AAChH,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,UAAkB;IACzD,MAAM,OAAO,GAAG,eAAe,CAAC,UAAU,CAAC,CAAA;IAC3C,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE,CAC5C,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,UAAU;KACX,CAAC,CAAC,CACJ,CAAA;IAED,OAAO;QACL,UAAU;QACV,OAAO,EAAE,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QACnD,SAAS,EAAE,OAAO,CAAC,MAAM;QACzB,eAAe,EAAE,WAAW,CAAC,MAAM;QACnC,WAAW;KACZ,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAC,UAAqC;IAC5D,OAAO,UAAU,CAAC,KAAK,IAAI,GAAG,CAAA;AAChC,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,OAA+B;IACzE,MAAM,KAAK,GAAG;QACZ,yCAAyC;QACzC,EAAE;QACF,YAAY,OAAO,CAAC,UAAU,EAAE;QAChC,YAAY,OAAO,CAAC,OAAO,EAAE;QAC7B,UAAU,OAAO,CAAC,SAAS,EAAE;QAC7B,gBAAgB,OAAO,CAAC,eAAe,EAAE;QACzC,EAAE;QACF,gBAAgB;QAChB,EAAE;KACH,CAAA;IAED,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,wCAAwC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;IACnF,CAAC;IAED,OAAO,GAAG,KAAK;SACZ,MAAM,CACL,mCAAmC,EACnC,2BAA2B,EAC3B,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CACxB,CAAC,IAAI,EAAE,EAAE,CACP,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,MAAM,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,IAAI,CAClH,EACD,EAAE,EACF,aAAa,EACb,EAAE,EACF,qHAAqH,EACrH,EAAE,CACH;SACA,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,UAAkB,EAAE,UAAkB;IAC/E,MAAM,OAAO,GAAG,wBAAwB,CAAC,UAAU,CAAC,CAAA;IACpD,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACnD,aAAa,CAAC,UAAU,EAAE,GAAG,2BAA2B,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACtE,OAAO,OAAO,CAAA;AAChB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type RuleFrontmatterDiagnosticCode = "missing_required_field" | "invalid_enum_value" | "malformed_frontmatter";
|
|
2
|
+
export type RuleFrontmatterDiagnostic = {
|
|
3
|
+
readonly code: RuleFrontmatterDiagnosticCode;
|
|
4
|
+
readonly field?: string;
|
|
5
|
+
readonly message: string;
|
|
6
|
+
};
|
|
7
|
+
export type RuleFrontmatterValidationInput = {
|
|
8
|
+
readonly id?: string;
|
|
9
|
+
readonly source?: string;
|
|
10
|
+
readonly domain?: string;
|
|
11
|
+
readonly topic?: string;
|
|
12
|
+
readonly globs: readonly string[];
|
|
13
|
+
readonly scenario?: string;
|
|
14
|
+
readonly severity?: string;
|
|
15
|
+
readonly enforcement?: string;
|
|
16
|
+
readonly malformedMessages: readonly string[];
|
|
17
|
+
};
|
|
18
|
+
export declare function malformedFrontmatter(message: string): RuleFrontmatterDiagnostic;
|
|
19
|
+
export declare function validateRuleFrontmatter(input: RuleFrontmatterValidationInput): readonly RuleFrontmatterDiagnostic[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const SOURCE_VALUES = ["clean-code", "backend-policy"];
|
|
2
|
+
const DOMAIN_VALUES = ["common", "backend"];
|
|
3
|
+
const SCENARIO_VALUES = ["step1", "step2-3", "all"];
|
|
4
|
+
const SEVERITY_VALUES = ["must", "should", "prefer"];
|
|
5
|
+
const ENFORCEMENT_VALUES = ["inject_only"];
|
|
6
|
+
export function malformedFrontmatter(message) {
|
|
7
|
+
return {
|
|
8
|
+
code: "malformed_frontmatter",
|
|
9
|
+
message,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function missingRequiredField(field) {
|
|
13
|
+
return {
|
|
14
|
+
code: "missing_required_field",
|
|
15
|
+
field,
|
|
16
|
+
message: `Required frontmatter field '${field}' is missing.`,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function invalidEnumValue(field, value) {
|
|
20
|
+
return {
|
|
21
|
+
code: "invalid_enum_value",
|
|
22
|
+
field,
|
|
23
|
+
message: `Unsupported frontmatter value for '${field}': ${value}.`,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function hasValue(value) {
|
|
27
|
+
return value !== undefined && value !== "";
|
|
28
|
+
}
|
|
29
|
+
function isKnownValue(value, values) {
|
|
30
|
+
return value !== undefined && values.includes(value);
|
|
31
|
+
}
|
|
32
|
+
export function validateRuleFrontmatter(input) {
|
|
33
|
+
const diagnostics = input.malformedMessages.map(malformedFrontmatter);
|
|
34
|
+
if (!hasValue(input.id))
|
|
35
|
+
diagnostics.push(missingRequiredField("id"));
|
|
36
|
+
if (!hasValue(input.source))
|
|
37
|
+
diagnostics.push(missingRequiredField("source"));
|
|
38
|
+
if (!hasValue(input.domain))
|
|
39
|
+
diagnostics.push(missingRequiredField("domain"));
|
|
40
|
+
if (!hasValue(input.topic))
|
|
41
|
+
diagnostics.push(missingRequiredField("topic"));
|
|
42
|
+
if (input.globs.length === 0)
|
|
43
|
+
diagnostics.push(missingRequiredField("globs"));
|
|
44
|
+
if (!hasValue(input.severity))
|
|
45
|
+
diagnostics.push(missingRequiredField("severity"));
|
|
46
|
+
if (!hasValue(input.enforcement))
|
|
47
|
+
diagnostics.push(missingRequiredField("enforcement"));
|
|
48
|
+
if (hasValue(input.source) && !isKnownValue(input.source, SOURCE_VALUES)) {
|
|
49
|
+
diagnostics.push(invalidEnumValue("source", input.source));
|
|
50
|
+
}
|
|
51
|
+
if (hasValue(input.domain) && !isKnownValue(input.domain, DOMAIN_VALUES)) {
|
|
52
|
+
diagnostics.push(invalidEnumValue("domain", input.domain));
|
|
53
|
+
}
|
|
54
|
+
if (hasValue(input.scenario) && !isKnownValue(input.scenario, SCENARIO_VALUES)) {
|
|
55
|
+
diagnostics.push(invalidEnumValue("scenario", input.scenario));
|
|
56
|
+
}
|
|
57
|
+
if (hasValue(input.severity) && !isKnownValue(input.severity, SEVERITY_VALUES)) {
|
|
58
|
+
diagnostics.push(invalidEnumValue("severity", input.severity));
|
|
59
|
+
}
|
|
60
|
+
if (hasValue(input.enforcement) && !isKnownValue(input.enforcement, ENFORCEMENT_VALUES)) {
|
|
61
|
+
diagnostics.push(invalidEnumValue("enforcement", input.enforcement));
|
|
62
|
+
}
|
|
63
|
+
return diagnostics;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=rule-frontmatter-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-frontmatter-diagnostics.js","sourceRoot":"","sources":["../../src/phase0/rule-frontmatter-diagnostics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type RuleFrontmatterDiagnostic } from "./rule-frontmatter-diagnostics.js";
|
|
2
|
+
export type Phase0Scenario = "step1" | "step2-3";
|
|
3
|
+
export type RuleScenario = Phase0Scenario | "all";
|
|
4
|
+
export type RuleSeverity = "must" | "should" | "prefer";
|
|
5
|
+
export type RuleMetadata = {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly source?: string;
|
|
8
|
+
readonly domain?: string;
|
|
9
|
+
readonly topic?: string;
|
|
10
|
+
readonly globs: readonly string[];
|
|
11
|
+
readonly scenario: RuleScenario;
|
|
12
|
+
readonly severity?: RuleSeverity;
|
|
13
|
+
readonly maxBullets?: number;
|
|
14
|
+
readonly enforcement?: string;
|
|
15
|
+
};
|
|
16
|
+
export type RuleFrontmatterParseResult = {
|
|
17
|
+
readonly metadata: RuleMetadata;
|
|
18
|
+
readonly diagnostics: readonly RuleFrontmatterDiagnostic[];
|
|
19
|
+
};
|
|
20
|
+
export declare function extractBulletPolicies(markdown: string): string[];
|
|
21
|
+
export declare function fallbackRuleMetadata(rulePath: string): RuleMetadata;
|
|
22
|
+
export declare function parseRuleFrontmatter(rulePath: string, markdown: string): RuleFrontmatterParseResult;
|
|
23
|
+
export declare function parseRuleMetadata(rulePath: string, markdown: string): RuleMetadata;
|