- 适配器 i18n 接入(eslint/pmd/sql-lint/stylelint) - Provider 动态注册机制(registry.ts + providers.json + factory 重构) - SetupView 全面重构(setupView.ts 新增 600+ 行) - i18n 消息扩展(messages.ts +210 行) - 规则导入流程优化(import-service / prompt-builder) - 新增 PMD jars 依赖及测试用例
474 lines
27 KiB
TypeScript
474 lines
27 KiB
TypeScript
import staticRules from '../static-rules.json';
|
||
import type { CustomRule } from '../../types';
|
||
import { getLanguage } from '../../i18n/messages';
|
||
|
||
export type PromptInputType = 'freeform' | 'spreadsheet';
|
||
|
||
type Lang = 'zh-CN' | 'en' | 'ja';
|
||
|
||
interface PromptStrings {
|
||
role: (inputDesc: string) => string;
|
||
inputToleranceTitle: string;
|
||
inputToleranceLines: string[];
|
||
nonRuleFilterTitle: string;
|
||
nonRuleFilterLines: string[];
|
||
fieldDefsTitle: string;
|
||
fieldDefsLines: string[];
|
||
languageRulesTitle: string;
|
||
languageRulesLines: string[];
|
||
exampleTitle: string;
|
||
example1Input: string;
|
||
example1Output: string;
|
||
example2Input: string;
|
||
example2Output: string;
|
||
staticAnalysisTitle: string;
|
||
staticAnalysisLines: string[];
|
||
finalInstruction: string;
|
||
dedupHeader: string;
|
||
dedupLinterLabel: (name: string, count: number) => string;
|
||
dedupCustomLabel: (count: number) => string;
|
||
dedupFooter: string;
|
||
outputLang: string;
|
||
}
|
||
|
||
const p: Record<Lang, PromptStrings> = {
|
||
'zh-CN': {
|
||
role: (inputDesc) => `你是一个代码审查规则转换器。将用户提供的${inputDesc},转换为结构化的 YAML 格式,用于代码审查工具。`,
|
||
inputToleranceTitle: '## 输入容忍说明',
|
||
inputToleranceLines: [
|
||
'用户输入可能有多种形态,你必须接受并处理以下任一形式:',
|
||
'- 自然语言段落(一段或多段话描述规则)',
|
||
'- 无序列表(每条规则一行或一段)',
|
||
'- 表格(列名不固定,从语义推断)',
|
||
'- 混合形式(段落 + 列表 + 表格组合)',
|
||
'',
|
||
'不得因输入格式非标准而拒绝转换。应主动从松散描述中提取规则语义。',
|
||
'',
|
||
'- 按输入文档的段落或列表项顺序处理,保持原文顺序输出',
|
||
'- 不要合并或拆分原文中已是独立条目的规则',
|
||
'- 一个段落包含多条规则时才拆分,单条规则不要拆成多条',
|
||
],
|
||
nonRuleFilterTitle: '## 非规则内容过滤',
|
||
nonRuleFilterLines: [
|
||
'用户输入中可能混入项目介绍、背景说明、代码示例、章节标题等非规则内容。你必须:',
|
||
'- 识别并跳过非规则内容,仅将真正的编码规则转为 YAML 条目',
|
||
'- 代码示例、项目介绍等仅作为理解规则语义的上下文,自身不输出为规则',
|
||
'- 若某段内容无法判断为规则(既无规则意图也无违反提示),直接忽略,不强行转换',
|
||
],
|
||
fieldDefsTitle: '## 字段定义',
|
||
fieldDefsLines: [
|
||
'每条规则需要包含以下字段:',
|
||
'- id: 规则唯一标识(kebab-case 英文,语义化、简短,如 no-console-log、avoid-magic-number)',
|
||
' **必须**基于规则描述内容自动生成语义化的 id',
|
||
' 即使输入中无显式 id 标识,也必须根据 description/message 的语义推断出合适的 id',
|
||
' 多条规则之间 id 不得重复',
|
||
' id 只能使用 description/message 中已有的英文单词或短语,转换为 kebab-case',
|
||
' 不要自行创造原文中没有的英文词汇',
|
||
' 如果输入全中文,从语义提取核心关键词翻译为简短英文(2-4 个词)',
|
||
'- severity: 严重级别(error / warning / info)',
|
||
' **必须**输出。按规则语义推断:',
|
||
' error: 会导致 bug / 安全问题 / 数据损坏',
|
||
' warning: 潜在问题 / 不良实践',
|
||
' info: 风格 / 可读性建议',
|
||
' 即使输入中无显式严重级别,也必须根据规则后果的严重程度推断',
|
||
' 如果无法从输入中确定严重级别,默认填 warning',
|
||
' 只有明确涉及安全、数据泄露、崩溃风险时才填 error',
|
||
'- description: 规则简短描述',
|
||
' **必须**输出。若输入中不明显,从 message 的内容反向推导出简短描述',
|
||
'- message: 违反时的提示消息',
|
||
' **必须**输出。若输入中不明显,从 description 的内容推导出违反提示',
|
||
' description 与 message 语义可相近,无需强行区分口吻,但两者都必须填写',
|
||
'- languages: 适用语言数组(可选,如 [javascript, typescript])',
|
||
'- excludeLanguages: 明确排除的语言数组(可选,如 [css, sql])',
|
||
'- duplicateOf: 重复的规则 ID(linter 如 eslint/no-console;自定义如 custom/my-rule)',
|
||
'- duplicateLevel: 重复程度(exact / overlap / none)',
|
||
'- duplicateReason: 重复/重叠原因说明(overlap 档必填)',
|
||
],
|
||
languageRulesTitle: '## 语言字段规则(严格遵守)',
|
||
languageRulesLines: [
|
||
'对于每条规则的 languages 字段:',
|
||
'1. 规则描述中含明确语言关键词(如 "Java"、"JavaScript"、"CSS")→ 使用 languages 白名单',
|
||
'2. 规则适用于大多数语言,只有少数不适用 → 使用 excludeLanguages 黑名单',
|
||
'3. 无法确定适用语言,或规则为通用规范 → languages 与 excludeLanguages 均留空',
|
||
'4. languages 和 excludeLanguages 不可同时非空',
|
||
'5. 语言名使用小写:java, javascript, typescript, css, sql, plsql, jsp',
|
||
'6. 严禁猜测。留空比猜测错误更安全。',
|
||
],
|
||
exampleTitle: '## 输入输出示例',
|
||
example1Input: '不要用 console.log,生产环境会泄露信息。还有不要留下未使用的变量,看着乱。',
|
||
example1Output: [
|
||
'- id: no-console-log',
|
||
' severity: warning',
|
||
' description: 禁止使用 console.log',
|
||
' message: 请使用 logger 工具替代 console.log',
|
||
' duplicateLevel: none',
|
||
'- id: no-unused-vars',
|
||
' severity: warning',
|
||
' description: 禁止未使用的变量',
|
||
' message: 未使用的变量应删除或注释',
|
||
' duplicateOf: eslint/no-unused-vars',
|
||
' duplicateLevel: exact',
|
||
].join('\n'),
|
||
example2Input: [
|
||
'本项目是一个电商后台管理系统,主要使用 Java + Spring Boot 开发。',
|
||
'代码规范要求:Service 层方法必须有日志记录,方便排查问题。',
|
||
'示例代码:',
|
||
' public void createOrder(Order order) { ... }',
|
||
'另外,Controller 层返回值统一用 Result 包装,不要直接返回 Map。',
|
||
].join('\n'),
|
||
example2Output: [
|
||
'- id: require-service-logging',
|
||
' severity: warning',
|
||
' description: Service 层方法必须有日志记录',
|
||
' message: Service 方法缺少日志记录,请补充以便排查问题',
|
||
' languages: [java]',
|
||
' duplicateLevel: none',
|
||
'- id: require-result-wrapper',
|
||
' severity: warning',
|
||
' description: Controller 返回值必须用 Result 包装',
|
||
' message: 请用 Result 包装返回值,不要直接返回 Map',
|
||
' languages: [java]',
|
||
' duplicateLevel: none',
|
||
].join('\n'),
|
||
staticAnalysisTitle: '## 静态分析重复检测',
|
||
staticAnalysisLines: [
|
||
'对于每条规则,判断其检测目标与触发条件是否与上述某个 linter 规则或自定义规则重复:',
|
||
'',
|
||
'- **exact**:检测目标与触发条件完全一致(会报出同样的问题行)→ 输出 duplicateOf + duplicateLevel: exact',
|
||
'- **overlap**:检测目标相同,但本规则有额外要求或更窄范围 → 输出 duplicateOf + duplicateLevel: overlap + duplicateReason',
|
||
'- **none**:检测目标不同 → 输出 duplicateLevel: none',
|
||
'',
|
||
'仅"话题相似"不算重复。例如:',
|
||
'- "未使用变量应删除" → exact(重复 eslint/no-unused-vars)',
|
||
'- "禁止在 console.log 中输出敏感信息" → none(检测目标不同)',
|
||
'',
|
||
'仅输出 YAML,不要额外说明。',
|
||
],
|
||
finalInstruction: '只输出 YAML 内容,不要输出 markdown 代码块标记,不要输出解释性文字',
|
||
dedupHeader: '## 已知规则清单(用于重复检测)',
|
||
dedupLinterLabel: (name, count) => `### ${name} (${count} 条)`,
|
||
dedupCustomLabel: (count) => `### 已导入的自定义规则 (${count} 条)`,
|
||
dedupFooter: '判定时请精确匹配上述规则 ID,而非模糊匹配分类。',
|
||
outputLang: '输出语言:zh-CN',
|
||
},
|
||
|
||
en: {
|
||
role: (inputDesc) => `You are a code review rule converter. Convert the ${inputDesc} provided by the user into structured YAML format for a code review tool. All descriptions and messages must be in English.`,
|
||
inputToleranceTitle: '## Input Tolerance',
|
||
inputToleranceLines: [
|
||
'User input may come in various forms. You must accept and process any of the following:',
|
||
'- Natural language paragraphs (one or more paragraphs describing rules)',
|
||
'- Unordered lists (one rule per line or paragraph)',
|
||
'- Tables (column names may vary; infer from semantics)',
|
||
'- Mixed forms (paragraphs + lists + tables)',
|
||
'',
|
||
'Do not reject conversion due to non-standard input format. Actively extract rule semantics from loose descriptions.',
|
||
'',
|
||
'- Process in the order of the input document paragraphs or list items, preserving original order',
|
||
'- Do not merge or split entries that are already independent rules in the original text',
|
||
'- Only split when a single paragraph contains multiple rules; do not split a single rule into multiple',
|
||
],
|
||
nonRuleFilterTitle: '## Non-Rule Content Filtering',
|
||
nonRuleFilterLines: [
|
||
'User input may contain project introductions, background info, code examples, section titles, etc. You must:',
|
||
'- Identify and skip non-rule content; only convert actual coding rules into YAML entries',
|
||
'- Code examples, project descriptions etc. serve only as context for understanding rule semantics; do not output them as rules',
|
||
'- If content cannot be identified as a rule (no rule intent or violation hint), ignore it; do not force conversion',
|
||
],
|
||
fieldDefsTitle: '## Field Definitions',
|
||
fieldDefsLines: [
|
||
'Each rule must include the following fields:',
|
||
'- id: Unique rule identifier (kebab-case English, semantic and concise, e.g., no-console-log, avoid-magic-number)',
|
||
' **Must** generate a semantic id based on the rule description content',
|
||
' Even if no explicit id is present in the input, infer a suitable id from the description/message semantics',
|
||
' IDs must not be duplicated across rules',
|
||
' id must use only English words or phrases already present in description/message, converted to kebab-case',
|
||
' Do not invent English words not found in the original text',
|
||
' If input is entirely in Chinese, extract core semantic keywords and translate to short English (2-4 words)',
|
||
'- severity: Severity level (error / warning / info)',
|
||
' **Must** output. Infer based on rule semantics:',
|
||
' error: causes bugs / security issues / data corruption',
|
||
' warning: potential issues / bad practices',
|
||
' info: style / readability suggestions',
|
||
' Even if no explicit severity is given, infer from the rule\'s impact',
|
||
' If severity cannot be determined from input, default to warning',
|
||
' Only use error when the rule clearly involves security, data leakage, or crash risk',
|
||
'- description: Short rule description',
|
||
' **Must** output. If not obvious from input, derive from message content',
|
||
'- message: Violation message',
|
||
' **Must** output. If not obvious from input, derive from description content',
|
||
' description and message may be semantically similar; no need to force different tones, but both must be filled',
|
||
'- languages: Applicable language array (optional, e.g., [javascript, typescript])',
|
||
'- excludeLanguages: Explicitly excluded language array (optional, e.g., [css, sql])',
|
||
'- duplicateOf: Duplicate rule ID (linter e.g., eslint/no-console; custom e.g., custom/my-rule)',
|
||
'- duplicateLevel: Duplicate level (exact / overlap / none)',
|
||
'- duplicateReason: Duplicate/overlap reason (required for overlap)',
|
||
],
|
||
languageRulesTitle: '## Language Field Rules (Strict)',
|
||
languageRulesLines: [
|
||
'For each rule\'s languages field:',
|
||
'1. If rule description mentions specific languages (e.g., "Java", "JavaScript", "CSS") → use languages whitelist',
|
||
'2. If rule applies to most languages, with few exceptions → use excludeLanguages blacklist',
|
||
'3. If applicable language cannot be determined, or rule is general → leave both languages and excludeLanguages empty',
|
||
'4. languages and excludeLanguages must not both be non-empty simultaneously',
|
||
'5. Use lowercase language names: java, javascript, typescript, css, sql, plsql, jsp',
|
||
'6. Never guess. Leaving empty is safer than guessing incorrectly.',
|
||
],
|
||
exampleTitle: '## Input/Output Examples',
|
||
example1Input: 'Do not use console.log, it leaks information in production. Also do not leave unused variables, they look messy.',
|
||
example1Output: [
|
||
'- id: no-console-log',
|
||
' severity: warning',
|
||
' description: Forbid using console.log',
|
||
' message: Use a logger tool instead of console.log',
|
||
' duplicateLevel: none',
|
||
'- id: no-unused-vars',
|
||
' severity: warning',
|
||
' description: Forbid unused variables',
|
||
' message: Unused variables should be deleted or commented out',
|
||
' duplicateOf: eslint/no-unused-vars',
|
||
' duplicateLevel: exact',
|
||
].join('\n'),
|
||
example2Input: [
|
||
'This project is an e-commerce backend, mainly using Java + Spring Boot.',
|
||
'Coding rules: Service layer methods must have logging for debugging.',
|
||
'Example code:',
|
||
' public void createOrder(Order order) { ... }',
|
||
'Also, Controller layer return values should use Result wrapper, do not return Map directly.',
|
||
].join('\n'),
|
||
example2Output: [
|
||
'- id: require-service-logging',
|
||
' severity: warning',
|
||
' description: Service layer methods must have logging',
|
||
' message: Service method missing logging, add for debugging',
|
||
' languages: [java]',
|
||
' duplicateLevel: none',
|
||
'- id: require-result-wrapper',
|
||
' severity: warning',
|
||
' description: Controller return values must use Result wrapper',
|
||
' message: Use Result wrapper for return values, do not return Map directly',
|
||
' languages: [java]',
|
||
' duplicateLevel: none',
|
||
].join('\n'),
|
||
staticAnalysisTitle: '## Static Analysis Duplicate Detection',
|
||
staticAnalysisLines: [
|
||
'For each rule, determine whether its detection target and trigger conditions duplicate any linter rule or custom rule above:',
|
||
'',
|
||
'- **exact**: Detection target and trigger conditions are completely identical (would flag the same line) → output duplicateOf + duplicateLevel: exact',
|
||
'- **overlap**: Same detection target but this rule has additional requirements or narrower scope → output duplicateOf + duplicateLevel: overlap + duplicateReason',
|
||
'- **none**: Different detection targets → output duplicateLevel: none',
|
||
'',
|
||
'"Same topic" alone does not count as duplicate. For example:',
|
||
'- "Unused variables should be deleted" → exact (duplicate of eslint/no-unused-vars)',
|
||
'- "Do not output sensitive info in console.log" → none (different detection target)',
|
||
'',
|
||
'Output YAML only, no extra explanation.',
|
||
],
|
||
finalInstruction: 'All descriptions and messages must be written in English.\nOutput YAML only, no markdown code fences, no explanatory text',
|
||
dedupHeader: '## Known Rules (for duplicate detection)',
|
||
dedupLinterLabel: (name, count) => `### ${name} (${count} rules)`,
|
||
dedupCustomLabel: (count) => `### Imported custom rules (${count} rules)`,
|
||
dedupFooter: 'Match exactly by rule ID above, not by fuzzy category matching.',
|
||
outputLang: 'Output language: en',
|
||
},
|
||
|
||
ja: {
|
||
role: (inputDesc) => `あなたはコードレビュールール変換ツールです。ユーザーが提供した${inputDesc}を、コードレビューツール用の構造化YAML形式に変換してください。すべての説明とメッセージは日本語で出力してください。`,
|
||
inputToleranceTitle: '## 入力許容について',
|
||
inputToleranceLines: [
|
||
'ユーザー入力は様々な形式である可能性があります。以下の形式を受け入れ、処理する必要があります:',
|
||
'- 自然言語の段落(1つ以上の段落でルールを記述)',
|
||
'- 順不同リスト(各ルールが1行または1段落)',
|
||
'- テーブル(列名は固定されていません。意味から推測してください)',
|
||
'- 混合形式(段落 + リスト + テーブルの組み込み)',
|
||
'',
|
||
'非標準的な入力形式であっても変換を拒否してはいけません。緩やかな記述からルールの意味を積極的に抽出してください。',
|
||
'',
|
||
'- 入力ドキュメントの段落またはリスト項目の順序で処理し、原文の順序を保持する',
|
||
'- 原文ですでに独立したエントリであるルールを結合または分割しない',
|
||
'- 単一の段落に複数のルールが含まれる場合のみ分割し、単一ルールを複数に分割しない',
|
||
],
|
||
nonRuleFilterTitle: '## 非ルールコンテンツのフィルタリング',
|
||
nonRuleFilterLines: [
|
||
'ユーザー入力には、プロジェクト紹介、背景説明、コード例、セクションタイトルなどの非ルールコンテンツが混入している可能性があります。以下を行う必要があります:',
|
||
'- 非ルールコンテンツを識別してスキップし、実際のコーディングルールのみをYAMLエントリに変換する',
|
||
'- コード例やプロジェクト紹介などはルール意味理解のコンテキストとしてのみ使用し、これら自体をルールとして出力しない',
|
||
'- ルールと判断できない内容(ルール意図も違反のヒントもない場合)は無視し、無理に変換しない',
|
||
],
|
||
fieldDefsTitle: '## フィールド定義',
|
||
fieldDefsLines: [
|
||
'各ルールには以下のフィールドが必要です:',
|
||
'- id: ルールの一意識別子(kebab-caseの英語、意味的で簡潔、例:no-console-log、avoid-magic-number)',
|
||
' **必須** ルール説明内容に基づいて意味的なidを自動生成する',
|
||
' 入力に明示的なidがない場合でも、description/messageの意味から適切なidを推測する',
|
||
' 複数ルール間でidが重複してはいけない',
|
||
' idはdescription/messageにすでに存在する英単語またはフレーズのみを使用し、kebab-caseに変換する',
|
||
' 原文にない英単語を独自に作成しない',
|
||
' 入力がすべて日本語の場合は、セマンティクスから核心キーワードを抽出し、短い英語(2〜4語)に翻訳する',
|
||
'- severity: 重大度(error / warning / info)',
|
||
' **必須**で出力。ルールの意味に従って推測:',
|
||
' error: バグ/セキュリティ問題/データ破損を引き起こす',
|
||
' warning: 潜在的な問題/悪い慣行',
|
||
' info: スタイル/可読性の提案',
|
||
' 入力に明示的な重大度がない場合でも、ルールの影響の重大さから推測する',
|
||
' 入力から重大度を判断できない場合は、デフォルトでwarningとする',
|
||
' セキュリティ、データ漏洩、クラッシュリスクに明確に関連する場合のみerrorとする',
|
||
'- description: ルールの簡単な説明',
|
||
' **必須**で出力。入力で不明確な場合、messageの内容から逆算して短い説明を導出',
|
||
'- message: 違反時のメッセージ',
|
||
' **必須**で出力。入力で不明確な場合、descriptionの内容から違反メッセージを導出',
|
||
' descriptionとmessageは意味的に近くても構いません。口調を無理に区別する必要はありませんが、両方とも必須です',
|
||
'- languages: 対象言語配列(オプション、例:[javascript, typescript])',
|
||
'- excludeLanguages: 明示的に除外する言語配列(オプション、例:[css, sql])',
|
||
'- duplicateOf: 重複するルールID(リンター例:eslint/no-console、カスタム例:custom/my-rule)',
|
||
'- duplicateLevel: 重複レベル(exact / overlap / none)',
|
||
'- duplicateReason: 重複/重複理由の説明(overlapの場合は必須)',
|
||
],
|
||
languageRulesTitle: '## 言語フィールドルール(厳守)',
|
||
languageRulesLines: [
|
||
'各ルールのlanguagesフィールドについて:',
|
||
'1. ルール説明に明確な言語キーワードがある場合(例:「Java」「JavaScript」「CSS」)→ languagesにホワイトリストを使用',
|
||
'2. ルールがほとんどの言語に適用され、一部のみ適用外の場合 → excludeLanguagesにブラックリストを使用',
|
||
'3. 適用言語が判断できない場合、またはルールが汎用の場合 → languagesとexcludeLanguagesの両方を空にする',
|
||
'4. languagesとexcludeLanguagesは同時に空であってはいけない',
|
||
'5. 言語名は小文字を使用:java, javascript, typescript, css, sql, plsql, jsp',
|
||
'6. 推測は厳禁。空のままにする方が誤った推測より安全です。',
|
||
],
|
||
exampleTitle: '## 入出力例',
|
||
example1Input: 'console.logは本番環境で情報漏洩するため使用しないでください。また、未使用の変数は残さないでください。散らかって見えます。',
|
||
example1Output: [
|
||
'- id: no-console-log',
|
||
' severity: warning',
|
||
' description: console.logの使用禁止',
|
||
' message: loggerツールを使用してconsole.logを代替してください',
|
||
' duplicateLevel: none',
|
||
'- id: no-unused-vars',
|
||
' severity: warning',
|
||
' description: 未使用変数の禁止',
|
||
' message: 未使用の変数は削除またはコメントアウトしてください',
|
||
' duplicateOf: eslint/no-unused-vars',
|
||
' duplicateLevel: exact',
|
||
].join('\n'),
|
||
example2Input: [
|
||
'本プロジェクトはECサイト管理システムで、主にJava + Spring Bootを使用しています。',
|
||
'コード規約:Service層のメソッドには必ずログ記録が必要です。問題調査のためです。',
|
||
'コード例:',
|
||
' public void createOrder(Order order) { ... }',
|
||
'また、Controller層の戻り値は統一してResultでラップし、Mapを直接返さないでください。',
|
||
].join('\n'),
|
||
example2Output: [
|
||
'- id: require-service-logging',
|
||
' severity: warning',
|
||
' description: Service層メソッドにはログ記録が必須',
|
||
' message: Serviceメソッドにログ記録がありません。問題調査のため追加してください',
|
||
' languages: [java]',
|
||
' duplicateLevel: none',
|
||
'- id: require-result-wrapper',
|
||
' severity: warning',
|
||
' description: Controllerの戻り値はResultでラップすること',
|
||
' message: Resultで戻り値をラップし、Mapを直接返さないでください',
|
||
' languages: [java]',
|
||
' duplicateLevel: none',
|
||
].join('\n'),
|
||
staticAnalysisTitle: '## 静的解析重複検出',
|
||
staticAnalysisLines: [
|
||
'各ルールについて、その検出対象とトリガー条件が上記のリンタールールまたはカスタムルールと重複するか判断:',
|
||
'',
|
||
'- **exact**: 検出対象とトリガー条件が完全に一致(同じ問題行を報告する)→ duplicateOf + duplicateLevel: exact を出力',
|
||
'- **overlap**: 検出対象は同じだが、このルールに追加要件やより狭い範囲がある → duplicateOf + duplicateLevel: overlap + duplicateReason を出力',
|
||
'- **none**: 検出対象が異なる → duplicateLevel: none を出力',
|
||
'',
|
||
'単に「トピックが類似している」だけでは重複とみなされません。例:',
|
||
'- 「未使用変数は削除すべき」→ exact(eslint/no-unused-varsと重複)',
|
||
'- 「console.logで機密情報を出力しない」→ none(検出対象が異なる)',
|
||
'',
|
||
'YAMLのみを出力し、追加説明は不要です。',
|
||
],
|
||
finalInstruction: 'すべてのdescriptionとmessageは日本語で出力してください。\nYAML のみ出力、マークダウンコードブロックなし、説明テキストなし',
|
||
dedupHeader: '## 既知ルール一覧(重複検出用)',
|
||
dedupLinterLabel: (name, count) => `### ${name}(${count} 件)`,
|
||
dedupCustomLabel: (count) => `### インポート済みカスタムルール(${count} 件)`,
|
||
dedupFooter: '上記ルールIDで正確にマッチングしてください。曖昧なカテゴリマッチングは避けてください。',
|
||
outputLang: '出力言語:ja',
|
||
},
|
||
};
|
||
|
||
function getLang(): Lang {
|
||
const lang = getLanguage();
|
||
if (lang === 'en' || lang === 'ja') { return lang; }
|
||
return 'zh-CN';
|
||
}
|
||
|
||
function buildDedupPromptSection(existingCustomRules?: CustomRule[], lang?: Lang): string {
|
||
const l = lang ?? getLang();
|
||
const s = p[l];
|
||
const lines: string[] = [s.dedupHeader];
|
||
|
||
for (const [linter, rules] of Object.entries(staticRules.rules)) {
|
||
lines.push(s.dedupLinterLabel(linter, rules.length));
|
||
for (const rule of rules) {
|
||
lines.push(`- ${rule.id}: ${rule.description}`);
|
||
}
|
||
lines.push('');
|
||
}
|
||
|
||
if (existingCustomRules && existingCustomRules.length > 0) {
|
||
lines.push(s.dedupCustomLabel(existingCustomRules.length));
|
||
for (const rule of existingCustomRules) {
|
||
lines.push(`- custom/${rule.id}: ${rule.description}`);
|
||
}
|
||
lines.push('');
|
||
}
|
||
|
||
lines.push(s.dedupFooter);
|
||
|
||
return lines.join('\n');
|
||
}
|
||
|
||
export function buildSystemPrompt(inputType: PromptInputType, existingRules?: CustomRule[]): string {
|
||
const lang = getLang();
|
||
const s = p[lang];
|
||
|
||
const inputDesc = inputType === 'spreadsheet'
|
||
? (lang === 'zh-CN' ? '表格规则数据' : lang === 'ja' ? '表形式のルールデータ' : 'spreadsheet rule data')
|
||
: (lang === 'zh-CN' ? '自然语言规则描述' : lang === 'ja' ? '自然言語のルール記述' : 'natural language rule description');
|
||
|
||
const parts: string[] = [
|
||
s.role(inputDesc),
|
||
'',
|
||
s.inputToleranceTitle,
|
||
...s.inputToleranceLines,
|
||
'',
|
||
s.nonRuleFilterTitle,
|
||
...s.nonRuleFilterLines,
|
||
'',
|
||
s.fieldDefsTitle,
|
||
...s.fieldDefsLines,
|
||
'',
|
||
s.languageRulesTitle,
|
||
...s.languageRulesLines,
|
||
'',
|
||
s.exampleTitle,
|
||
'',
|
||
`${lang === 'zh-CN' ? '示例 1 — 松散段落输入:' : lang === 'ja' ? '例1 — 緩やかな段落入力:' : 'Example 1 — Loose paragraph input:'}`,
|
||
`${lang === 'zh-CN' ? '输入' : lang === 'ja' ? '入力' : 'Input'}:${s.example1Input}`,
|
||
`${lang === 'zh-CN' ? '输出' : lang === 'ja' ? '出力' : 'Output'}:`,
|
||
s.example1Output,
|
||
'',
|
||
`${lang === 'zh-CN' ? '示例 2 — 含非规则内容的混合输入:' : lang === 'ja' ? '例2 — 非ルールコンテンツを含む混合入力:' : 'Example 2 — Mixed input with non-rule content:'}`,
|
||
`${lang === 'zh-CN' ? '输入' : lang === 'ja' ? '入力' : 'Input'}:${s.example2Input}`,
|
||
`${lang === 'zh-CN' ? '输出' : lang === 'ja' ? '出力' : 'Output'}:`,
|
||
s.example2Output,
|
||
'',
|
||
buildDedupPromptSection(existingRules, lang),
|
||
'',
|
||
s.staticAnalysisTitle,
|
||
...s.staticAnalysisLines,
|
||
'',
|
||
s.finalInstruction,
|
||
s.outputLang,
|
||
];
|
||
|
||
return parts.join('\n');
|
||
}
|