prooflint 0.1.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/LICENSE +21 -0
- package/README.md +147 -0
- package/dist/cli.js +534 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +491 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +418 -0
- package/dist/index.d.ts +418 -0
- package/dist/index.js +446 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/config/loader.ts","../src/rules/types.ts","../src/rules/engine.ts","../src/parser/markdown.ts","../src/rules/pattern.ts","../src/rules/dictionary.ts","../src/parser/sentence.ts","../src/rules/structure.ts","../src/reporter/console.ts","../src/reporter/json.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { Command } from 'commander'\nimport { glob } from 'node:fs/promises'\nimport { loadConfig, findConfigFile } from './config/loader.js'\nimport { lintFile } from './rules/engine.js'\nimport { formatConsole, hasErrors } from './reporter/console.js'\nimport { formatJson } from './reporter/json.js'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst pkgPath = resolve(__dirname, '../package.json')\nconst pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version: string }\n\nconst INIT_TEMPLATE = `rules:\n # 用語の表記ゆれを統一\n - id: term-consistency\n type: dictionary\n description: \"用語の表記ゆれを統一\"\n severity: warning\n terms:\n - prefer: \"サーバー\"\n avoid: [\"サーバ\"]\n - prefer: \"ユーザー\"\n avoid: [\"ユーザ\"]\n\n # 一文の長さを制限\n - id: sentence-length\n type: structure\n description: \"一文の長さを制限\"\n severity: warning\n target: sentence\n max_chars: 120\n\n # 見出しのスタイルを統一\n - id: heading-style\n type: structure\n description: \"見出しのレベルと末尾ピリオドを制限\"\n severity: error\n target: heading\n max_level: 4\n no_period: true\n`\n\nconst program = new Command()\n\nprogram\n .name('prooflint')\n .description('Declarative text linter for Markdown — define rules in YAML')\n .version(pkg.version)\n\nprogram\n .command('init')\n .description('Create a .prooflint.yml config file in the current directory')\n .option('--force', 'Overwrite existing config file')\n .action((options: { force?: boolean }) => {\n const target = resolve(process.cwd(), '.prooflint.yml')\n if (existsSync(target) && !options.force) {\n console.error('.prooflint.yml already exists. Use --force to overwrite.')\n process.exit(1)\n }\n writeFileSync(target, INIT_TEMPLATE, 'utf-8')\n console.log(`Created ${target}`)\n })\n\nprogram\n .command('check [patterns...]')\n .description('Lint Markdown files matching the given glob patterns')\n .option('-c, --config <path>', 'Path to config file')\n .option('-f, --format <format>', 'Output format: console or json', 'console')\n .action(async (patterns: string[], options: { config?: string; format?: string }) => {\n const cwd = process.cwd()\n\n // Load config\n let config\n try {\n if (options.config) {\n config = loadConfig(resolve(cwd, options.config))\n } else {\n const configPath = findConfigFile(cwd)\n if (!configPath) {\n console.error('No .prooflint.yml found. Run `prooflint init` to create one.')\n process.exit(1)\n }\n config = loadConfig(configPath)\n }\n } catch (err) {\n console.error(err instanceof Error ? err.message : String(err))\n process.exit(1)\n }\n\n // Collect files\n const targetPatterns = patterns.length > 0 ? patterns : ['**/*.md']\n const filePaths: string[] = []\n\n for (const pattern of targetPatterns) {\n try {\n for await (const entry of glob(pattern, { cwd })) {\n const abs = resolve(cwd, entry)\n if (!filePaths.includes(abs)) filePaths.push(abs)\n }\n } catch {\n // pattern may be a direct file path\n const abs = resolve(cwd, pattern)\n if (existsSync(abs) && !filePaths.includes(abs)) filePaths.push(abs)\n }\n }\n\n if (filePaths.length === 0) {\n console.log('No files found.')\n process.exit(0)\n }\n\n // Run lint\n const results = filePaths.map((fp) => {\n try {\n return lintFile(fp, config)\n } catch (err) {\n console.error(`Error processing ${fp}: ${err instanceof Error ? err.message : String(err)}`)\n process.exit(1)\n }\n })\n\n // Output\n const format = options.format ?? 'console'\n if (format === 'json') {\n console.log(formatJson(results))\n } else {\n const output = formatConsole(results)\n console.log(output)\n }\n\n if (hasErrors(results)) {\n process.exit(1)\n }\n })\n\nprogram.parse()\n","import { readFileSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport yaml from 'js-yaml'\nimport { ConfigSchema } from '../rules/types.js'\nimport type { Config } from '../rules/types.js'\n\nconst CONFIG_FILE_NAMES = ['.prooflint.yml', '.prooflint.yaml', 'prooflint.config.yml']\n\nexport function findConfigFile(cwd: string = process.cwd()): string | null {\n for (const name of CONFIG_FILE_NAMES) {\n const candidate = resolve(cwd, name)\n try {\n readFileSync(candidate)\n return candidate\n } catch {\n // not found, try next\n }\n }\n return null\n}\n\nexport function loadConfig(configPath: string): Config {\n const raw = readFileSync(configPath, 'utf-8')\n const parsed = yaml.load(raw)\n const result = ConfigSchema.safeParse(parsed)\n\n if (!result.success) {\n const issues = result.error.issues\n .map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`)\n .join('\\n')\n throw new Error(`Invalid config at ${configPath}:\\n${issues}`)\n }\n\n return result.data\n}\n\nexport function loadConfigFromCwd(cwd: string = process.cwd()): Config {\n const configPath = findConfigFile(cwd)\n if (!configPath) {\n return ConfigSchema.parse({})\n }\n return loadConfig(configPath)\n}\n\nexport function resolveContextPaths(config: Config, configPath: string): Config {\n if (!config.context) return config\n\n const configDir = dirname(configPath)\n return {\n ...config,\n context: {\n glossary: config.context.glossary\n ? resolve(configDir, config.context.glossary)\n : undefined,\n style_guide: config.context.style_guide\n ? resolve(configDir, config.context.style_guide)\n : undefined,\n },\n }\n}\n","import { z } from 'zod'\n\n// Severity levels\nexport const SeveritySchema = z.enum(['error', 'warning', 'info'])\nexport type Severity = z.infer<typeof SeveritySchema>\n\n// Pattern rule: regex-based matching\nexport const PatternRuleSchema = z.object({\n id: z.string().min(1),\n type: z.literal('pattern'),\n description: z.string().optional(),\n severity: SeveritySchema.default('warning'),\n patterns: z.array(\n z.object({\n regex: z.string().min(1),\n message: z.string().min(1),\n flags: z.string().optional(),\n })\n ).min(1),\n})\nexport type PatternRule = z.infer<typeof PatternRuleSchema>\n\n// Dictionary rule: term consistency\nexport const DictionaryRuleSchema = z.object({\n id: z.string().min(1),\n type: z.literal('dictionary'),\n description: z.string().optional(),\n severity: SeveritySchema.default('warning'),\n terms: z.array(\n z.object({\n prefer: z.string().min(1),\n avoid: z.array(z.string().min(1)).min(1),\n })\n ).min(1),\n})\nexport type DictionaryRule = z.infer<typeof DictionaryRuleSchema>\n\n// Structure rule: sentence length, heading constraints\nexport const StructureRuleSchema = z.object({\n id: z.string().min(1),\n type: z.literal('structure'),\n description: z.string().optional(),\n severity: SeveritySchema.default('warning'),\n target: z.enum(['sentence', 'heading']).default('sentence'),\n max_chars: z.number().int().positive().optional(),\n max_level: z.number().int().min(1).max(6).optional(),\n no_period: z.boolean().optional(),\n})\nexport type StructureRule = z.infer<typeof StructureRuleSchema>\n\n// Union of all rule types\nexport const RuleSchema = z.discriminatedUnion('type', [\n PatternRuleSchema,\n DictionaryRuleSchema,\n StructureRuleSchema,\n])\nexport type Rule = z.infer<typeof RuleSchema>\n\n// Context (optional glossary/style guide files)\nexport const ContextSchema = z.object({\n glossary: z.string().optional(),\n style_guide: z.string().optional(),\n}).optional()\nexport type Context = z.infer<typeof ContextSchema>\n\n// Full config schema (.prooflint.yml)\nexport const ConfigSchema = z.object({\n rules: z.array(RuleSchema).default([]),\n context: ContextSchema,\n})\nexport type Config = z.infer<typeof ConfigSchema>\n\n// A single lint violation\nexport interface LintMessage {\n ruleId: string\n severity: Severity\n message: string\n line: number\n column: number\n source?: string\n}\n\n// Lint result for a single file\nexport interface LintResult {\n filePath: string\n messages: LintMessage[]\n errorCount: number\n warningCount: number\n infoCount: number\n}\n","import { readFileSync } from 'node:fs'\nimport { parseMarkdown } from '../parser/markdown.js'\nimport { applyPatternRule } from './pattern.js'\nimport { applyDictionaryRule } from './dictionary.js'\nimport { applyStructureRule } from './structure.js'\nimport type { Config, LintResult, LintMessage } from './types.js'\n\nexport function lintText(content: string, filePath: string, config: Config): LintResult {\n const doc = parseMarkdown(content)\n const messages: LintMessage[] = []\n\n for (const rule of config.rules) {\n switch (rule.type) {\n case 'pattern':\n messages.push(...applyPatternRule(rule, doc.textNodes))\n break\n case 'dictionary':\n messages.push(...applyDictionaryRule(rule, doc.textNodes))\n break\n case 'structure':\n messages.push(...applyStructureRule(rule, doc.textNodes))\n break\n }\n }\n\n // Sort by line then column\n messages.sort((a, b) => a.line !== b.line ? a.line - b.line : a.column - b.column)\n\n return {\n filePath,\n messages,\n errorCount: messages.filter((m) => m.severity === 'error').length,\n warningCount: messages.filter((m) => m.severity === 'warning').length,\n infoCount: messages.filter((m) => m.severity === 'info').length,\n }\n}\n\nexport function lintFile(filePath: string, config: Config): LintResult {\n const content = readFileSync(filePath, 'utf-8')\n return lintText(content, filePath, config)\n}\n\nexport function lintFiles(filePaths: string[], config: Config): LintResult[] {\n return filePaths.map((fp) => lintFile(fp, config))\n}\n","import { remark } from 'remark'\nimport type { Root, RootContent } from 'mdast'\n\nexport interface TextNode {\n text: string\n line: number\n column: number\n nodeType: 'paragraph' | 'heading' | 'listItem' | 'blockquote' | 'other'\n headingDepth?: number\n}\n\nexport interface ParsedDocument {\n textNodes: TextNode[]\n headings: TextNode[]\n raw: string\n}\n\nexport function parseMarkdown(content: string): ParsedDocument {\n const processor = remark()\n const tree = processor.parse(content) as Root\n const textNodes: TextNode[] = []\n const headings: TextNode[] = []\n\n function visit(node: RootContent): void {\n if (node.type === 'heading') {\n const text = extractText(node)\n const position = node.position\n const textNode: TextNode = {\n text,\n line: position?.start.line ?? 1,\n column: position?.start.column ?? 1,\n nodeType: 'heading',\n headingDepth: node.depth,\n }\n headings.push(textNode)\n textNodes.push(textNode)\n } else if (node.type === 'paragraph') {\n const text = extractText(node)\n const position = node.position\n textNodes.push({\n text,\n line: position?.start.line ?? 1,\n column: position?.start.column ?? 1,\n nodeType: 'paragraph',\n })\n } else if (node.type === 'listItem' || node.type === 'blockquote') {\n if ('children' in node) {\n for (const child of node.children) {\n visit(child as RootContent)\n }\n return\n }\n }\n\n if ('children' in node && node.type !== 'heading' && node.type !== 'paragraph') {\n for (const child of (node as { children: RootContent[] }).children) {\n visit(child)\n }\n }\n }\n\n for (const child of tree.children) {\n visit(child)\n }\n\n return { textNodes, headings, raw: content }\n}\n\nfunction extractText(node: RootContent): string {\n if ('value' in node && typeof node.value === 'string') {\n return node.value\n }\n if ('children' in node) {\n return (node as { children: RootContent[] }).children\n .map(extractText)\n .join('')\n }\n return ''\n}\n","import type { PatternRule, LintMessage } from './types.js'\nimport type { TextNode } from '../parser/markdown.js'\n\nexport function applyPatternRule(rule: PatternRule, nodes: TextNode[]): LintMessage[] {\n const messages: LintMessage[] = []\n\n for (const node of nodes) {\n for (const pattern of rule.patterns) {\n const flags = pattern.flags ?? 'g'\n let regex: RegExp\n try {\n regex = new RegExp(pattern.regex, flags.includes('g') ? flags : flags + 'g')\n } catch {\n throw new Error(`Rule \"${rule.id}\": invalid regex \"${pattern.regex}\"`)\n }\n\n let match: RegExpExecArray | null\n while ((match = regex.exec(node.text)) !== null) {\n const beforeMatch = node.text.slice(0, match.index)\n const newlines = (beforeMatch.match(/\\n/g) ?? []).length\n const lastNewline = beforeMatch.lastIndexOf('\\n')\n const col = lastNewline === -1\n ? node.column + match.index\n : match.index - lastNewline\n\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: pattern.message,\n line: node.line + newlines,\n column: col,\n source: match[0],\n })\n }\n }\n }\n\n return messages\n}\n","import type { DictionaryRule, LintMessage } from './types.js'\nimport type { TextNode } from '../parser/markdown.js'\n\n// Check if the character at position is part of a word continuation\n// We want to avoid matching \"サーバ\" inside \"サーバー\"\nfunction isWordBoundary(text: string, start: number, end: number): boolean {\n const charBefore = start > 0 ? text[start - 1] : null\n const charAfter = end < text.length ? text[end] : null\n\n // If the character immediately after is a katakana long vowel mark (ー),\n // it means the \"avoid\" word is part of a longer preferred word\n if (charAfter === 'ー' || charAfter === '〜') return false\n\n return true\n}\n\nexport function applyDictionaryRule(rule: DictionaryRule, nodes: TextNode[]): LintMessage[] {\n const messages: LintMessage[] = []\n\n for (const node of nodes) {\n for (const term of rule.terms) {\n for (const avoidWord of term.avoid) {\n // Check that prefer doesn't start with avoidWord (avoid is a prefix of prefer)\n // e.g. \"サーバ\" is a prefix of \"サーバー\", so we need boundary checking\n const preferStartsWithAvoid = term.prefer.startsWith(avoidWord)\n\n const escaped = avoidWord.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const regex = new RegExp(escaped, 'g')\n\n let match: RegExpExecArray | null\n while ((match = regex.exec(node.text)) !== null) {\n const matchStart = match.index\n const matchEnd = matchStart + avoidWord.length\n\n // If prefer starts with avoid, check word boundary\n if (preferStartsWithAvoid && !isWordBoundary(node.text, matchStart, matchEnd)) {\n continue\n }\n\n const beforeMatch = node.text.slice(0, matchStart)\n const newlines = (beforeMatch.match(/\\n/g) ?? []).length\n const lastNewline = beforeMatch.lastIndexOf('\\n')\n const col = lastNewline === -1\n ? node.column + matchStart\n : matchStart - lastNewline\n\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: `「${avoidWord}」→「${term.prefer}」に統一してください`,\n line: node.line + newlines,\n column: col,\n source: match[0],\n })\n }\n }\n }\n }\n\n return messages\n}\n","export interface Sentence {\n text: string\n line: number\n column: number\n}\n\n// Sentence delimiters for Japanese and Western text\nconst SENTENCE_END_PATTERN = /([。!?\\.\\!\\?]+)/g\n\n/**\n * Splits a block of text into individual sentences.\n * Handles Japanese sentence endings (。!?) and Western (. ! ?).\n * Preserves line/column tracking relative to the block's starting position.\n */\nexport function splitSentences(text: string, startLine: number, startColumn: number): Sentence[] {\n const sentences: Sentence[] = []\n const lines = text.split('\\n')\n\n let currentLine = startLine\n let currentCol = startColumn\n let buffer = ''\n let bufferLine = currentLine\n let bufferCol = currentCol\n\n for (let li = 0; li < lines.length; li++) {\n const line = lines[li] ?? ''\n let charPos = li === 0 ? startColumn - 1 : 0\n\n for (let ci = 0; ci < line.length; ci++) {\n const ch = line[ci] ?? ''\n buffer += ch\n charPos++\n\n if (isSentenceEnd(ch, line, ci)) {\n const trimmed = buffer.trim()\n if (trimmed.length > 0) {\n sentences.push({ text: trimmed, line: bufferLine, column: bufferCol })\n }\n buffer = ''\n bufferLine = currentLine\n bufferCol = charPos + 1\n }\n }\n\n if (li < lines.length - 1) {\n buffer += '\\n'\n currentLine++\n currentCol = 1\n if (buffer.trim() === '') {\n bufferLine = currentLine\n bufferCol = 1\n buffer = ''\n }\n }\n }\n\n const trimmed = buffer.trim()\n if (trimmed.length > 0) {\n sentences.push({ text: trimmed, line: bufferLine, column: bufferCol })\n }\n\n return sentences\n}\n\nfunction isSentenceEnd(ch: string, line: string, index: number): boolean {\n // Japanese terminators always end sentence\n if ('。!?'.includes(ch)) return true\n\n // Western period: end only if followed by space/end or next char is uppercase\n if (ch === '.' || ch === '!' || ch === '?') {\n const next = line[index + 1]\n if (next === undefined || next === ' ' || next === '\\t') return true\n }\n\n return false\n}\n","import type { StructureRule, LintMessage } from './types.js'\nimport type { TextNode } from '../parser/markdown.js'\nimport { splitSentences } from '../parser/sentence.js'\n\nexport function applyStructureRule(rule: StructureRule, nodes: TextNode[]): LintMessage[] {\n const messages: LintMessage[] = []\n const target = rule.target ?? 'sentence'\n\n if (target === 'heading') {\n return applyHeadingRules(rule, nodes)\n }\n\n // sentence target: check sentence length\n for (const node of nodes) {\n if (node.nodeType === 'heading') continue\n\n if (rule.max_chars !== undefined) {\n const sentences = splitSentences(node.text, node.line, node.column)\n for (const sentence of sentences) {\n if (sentence.text.length > rule.max_chars) {\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: `一文が${sentence.text.length}文字です(上限: ${rule.max_chars}文字)`,\n line: sentence.line,\n column: sentence.column,\n source: sentence.text.slice(0, 40) + (sentence.text.length > 40 ? '...' : ''),\n })\n }\n }\n }\n }\n\n return messages\n}\n\nfunction applyHeadingRules(rule: StructureRule, nodes: TextNode[]): LintMessage[] {\n const messages: LintMessage[] = []\n\n for (const node of nodes) {\n if (node.nodeType !== 'heading') continue\n\n // Check heading level\n if (rule.max_level !== undefined && node.headingDepth !== undefined) {\n if (node.headingDepth > rule.max_level) {\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: `見出しレベル${node.headingDepth}は上限(H${rule.max_level})を超えています`,\n line: node.line,\n column: node.column,\n source: node.text,\n })\n }\n }\n\n // Check trailing period in heading\n if (rule.no_period === true) {\n if (/[。..]$/.test(node.text.trim())) {\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: '見出しの末尾に句点を使わないでください',\n line: node.line,\n column: node.column,\n source: node.text,\n })\n }\n }\n }\n\n return messages\n}\n","import chalk from 'chalk'\nimport type { LintResult, LintMessage, Severity } from '../rules/types.js'\n\nfunction severityLabel(severity: Severity): string {\n switch (severity) {\n case 'error':\n return chalk.red('error')\n case 'warning':\n return chalk.yellow('warn ')\n case 'info':\n return chalk.blue('info ')\n }\n}\n\nfunction formatMessage(msg: LintMessage): string {\n const location = chalk.dim(`${String(msg.line).padStart(4)}:${String(msg.column).padEnd(4)}`)\n const sev = severityLabel(msg.severity)\n const text = msg.message\n const rule = chalk.dim(msg.ruleId)\n return ` ${location} ${sev} ${text} ${rule}`\n}\n\nexport function formatConsole(results: LintResult[]): string {\n const lines: string[] = []\n let totalErrors = 0\n let totalWarnings = 0\n let totalInfos = 0\n\n for (const result of results) {\n if (result.messages.length === 0) continue\n\n lines.push('')\n lines.push(chalk.underline(result.filePath))\n\n for (const msg of result.messages) {\n lines.push(formatMessage(msg))\n }\n\n totalErrors += result.errorCount\n totalWarnings += result.warningCount\n totalInfos += result.infoCount\n }\n\n const total = totalErrors + totalWarnings + totalInfos\n if (total === 0) {\n lines.push(chalk.green('\\n0 problems'))\n return lines.join('\\n')\n }\n\n const parts: string[] = []\n if (totalErrors > 0) parts.push(chalk.red(`${totalErrors} error${totalErrors > 1 ? 's' : ''}`))\n if (totalWarnings > 0) parts.push(chalk.yellow(`${totalWarnings} warning${totalWarnings > 1 ? 's' : ''}`))\n if (totalInfos > 0) parts.push(chalk.blue(`${totalInfos} info`))\n\n lines.push('')\n lines.push(`${total} problem${total > 1 ? 's' : ''} (${parts.join(', ')})`)\n\n return lines.join('\\n')\n}\n\nexport function hasErrors(results: LintResult[]): boolean {\n return results.some((r) => r.errorCount > 0)\n}\n","import type { LintResult } from '../rules/types.js'\n\nexport interface JsonOutput {\n results: LintResult[]\n summary: {\n totalFiles: number\n filesWithProblems: number\n totalErrors: number\n totalWarnings: number\n totalInfos: number\n }\n}\n\nexport function formatJson(results: LintResult[]): string {\n const output: JsonOutput = {\n results,\n summary: {\n totalFiles: results.length,\n filesWithProblems: results.filter((r) => r.messages.length > 0).length,\n totalErrors: results.reduce((s, r) => s + r.errorCount, 0),\n totalWarnings: results.reduce((s, r) => s + r.warningCount, 0),\n totalInfos: results.reduce((s, r) => s + r.infoCount, 0),\n },\n }\n return JSON.stringify(output, null, 2)\n}\n"],"mappings":"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","names":["readFileSync","resolve","dirname","readFileSync","trimmed","readFileSync","dirname","resolve","readFileSync"]}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
findConfigFile: () => findConfigFile,
|
|
34
|
+
formatConsole: () => formatConsole,
|
|
35
|
+
formatJson: () => formatJson,
|
|
36
|
+
hasErrors: () => hasErrors,
|
|
37
|
+
lintFile: () => lintFile,
|
|
38
|
+
lintFiles: () => lintFiles,
|
|
39
|
+
lintText: () => lintText,
|
|
40
|
+
loadConfig: () => loadConfig,
|
|
41
|
+
loadConfigFromCwd: () => loadConfigFromCwd
|
|
42
|
+
});
|
|
43
|
+
module.exports = __toCommonJS(src_exports);
|
|
44
|
+
|
|
45
|
+
// src/rules/engine.ts
|
|
46
|
+
var import_node_fs = require("fs");
|
|
47
|
+
|
|
48
|
+
// src/parser/markdown.ts
|
|
49
|
+
var import_remark = require("remark");
|
|
50
|
+
function parseMarkdown(content) {
|
|
51
|
+
const processor = (0, import_remark.remark)();
|
|
52
|
+
const tree = processor.parse(content);
|
|
53
|
+
const textNodes = [];
|
|
54
|
+
const headings = [];
|
|
55
|
+
function visit(node) {
|
|
56
|
+
if (node.type === "heading") {
|
|
57
|
+
const text = extractText(node);
|
|
58
|
+
const position = node.position;
|
|
59
|
+
const textNode = {
|
|
60
|
+
text,
|
|
61
|
+
line: position?.start.line ?? 1,
|
|
62
|
+
column: position?.start.column ?? 1,
|
|
63
|
+
nodeType: "heading",
|
|
64
|
+
headingDepth: node.depth
|
|
65
|
+
};
|
|
66
|
+
headings.push(textNode);
|
|
67
|
+
textNodes.push(textNode);
|
|
68
|
+
} else if (node.type === "paragraph") {
|
|
69
|
+
const text = extractText(node);
|
|
70
|
+
const position = node.position;
|
|
71
|
+
textNodes.push({
|
|
72
|
+
text,
|
|
73
|
+
line: position?.start.line ?? 1,
|
|
74
|
+
column: position?.start.column ?? 1,
|
|
75
|
+
nodeType: "paragraph"
|
|
76
|
+
});
|
|
77
|
+
} else if (node.type === "listItem" || node.type === "blockquote") {
|
|
78
|
+
if ("children" in node) {
|
|
79
|
+
for (const child of node.children) {
|
|
80
|
+
visit(child);
|
|
81
|
+
}
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if ("children" in node && node.type !== "heading" && node.type !== "paragraph") {
|
|
86
|
+
for (const child of node.children) {
|
|
87
|
+
visit(child);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const child of tree.children) {
|
|
92
|
+
visit(child);
|
|
93
|
+
}
|
|
94
|
+
return { textNodes, headings, raw: content };
|
|
95
|
+
}
|
|
96
|
+
function extractText(node) {
|
|
97
|
+
if ("value" in node && typeof node.value === "string") {
|
|
98
|
+
return node.value;
|
|
99
|
+
}
|
|
100
|
+
if ("children" in node) {
|
|
101
|
+
return node.children.map(extractText).join("");
|
|
102
|
+
}
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/rules/pattern.ts
|
|
107
|
+
function applyPatternRule(rule, nodes) {
|
|
108
|
+
const messages = [];
|
|
109
|
+
for (const node of nodes) {
|
|
110
|
+
for (const pattern of rule.patterns) {
|
|
111
|
+
const flags = pattern.flags ?? "g";
|
|
112
|
+
let regex;
|
|
113
|
+
try {
|
|
114
|
+
regex = new RegExp(pattern.regex, flags.includes("g") ? flags : flags + "g");
|
|
115
|
+
} catch {
|
|
116
|
+
throw new Error(`Rule "${rule.id}": invalid regex "${pattern.regex}"`);
|
|
117
|
+
}
|
|
118
|
+
let match;
|
|
119
|
+
while ((match = regex.exec(node.text)) !== null) {
|
|
120
|
+
const beforeMatch = node.text.slice(0, match.index);
|
|
121
|
+
const newlines = (beforeMatch.match(/\n/g) ?? []).length;
|
|
122
|
+
const lastNewline = beforeMatch.lastIndexOf("\n");
|
|
123
|
+
const col = lastNewline === -1 ? node.column + match.index : match.index - lastNewline;
|
|
124
|
+
messages.push({
|
|
125
|
+
ruleId: rule.id,
|
|
126
|
+
severity: rule.severity,
|
|
127
|
+
message: pattern.message,
|
|
128
|
+
line: node.line + newlines,
|
|
129
|
+
column: col,
|
|
130
|
+
source: match[0]
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return messages;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/rules/dictionary.ts
|
|
139
|
+
function isWordBoundary(text, start, end) {
|
|
140
|
+
const charBefore = start > 0 ? text[start - 1] : null;
|
|
141
|
+
const charAfter = end < text.length ? text[end] : null;
|
|
142
|
+
if (charAfter === "\u30FC" || charAfter === "\u301C") return false;
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
function applyDictionaryRule(rule, nodes) {
|
|
146
|
+
const messages = [];
|
|
147
|
+
for (const node of nodes) {
|
|
148
|
+
for (const term of rule.terms) {
|
|
149
|
+
for (const avoidWord of term.avoid) {
|
|
150
|
+
const preferStartsWithAvoid = term.prefer.startsWith(avoidWord);
|
|
151
|
+
const escaped = avoidWord.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
152
|
+
const regex = new RegExp(escaped, "g");
|
|
153
|
+
let match;
|
|
154
|
+
while ((match = regex.exec(node.text)) !== null) {
|
|
155
|
+
const matchStart = match.index;
|
|
156
|
+
const matchEnd = matchStart + avoidWord.length;
|
|
157
|
+
if (preferStartsWithAvoid && !isWordBoundary(node.text, matchStart, matchEnd)) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const beforeMatch = node.text.slice(0, matchStart);
|
|
161
|
+
const newlines = (beforeMatch.match(/\n/g) ?? []).length;
|
|
162
|
+
const lastNewline = beforeMatch.lastIndexOf("\n");
|
|
163
|
+
const col = lastNewline === -1 ? node.column + matchStart : matchStart - lastNewline;
|
|
164
|
+
messages.push({
|
|
165
|
+
ruleId: rule.id,
|
|
166
|
+
severity: rule.severity,
|
|
167
|
+
message: `\u300C${avoidWord}\u300D\u2192\u300C${term.prefer}\u300D\u306B\u7D71\u4E00\u3057\u3066\u304F\u3060\u3055\u3044`,
|
|
168
|
+
line: node.line + newlines,
|
|
169
|
+
column: col,
|
|
170
|
+
source: match[0]
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return messages;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// src/parser/sentence.ts
|
|
180
|
+
function splitSentences(text, startLine, startColumn) {
|
|
181
|
+
const sentences = [];
|
|
182
|
+
const lines = text.split("\n");
|
|
183
|
+
let currentLine = startLine;
|
|
184
|
+
let currentCol = startColumn;
|
|
185
|
+
let buffer = "";
|
|
186
|
+
let bufferLine = currentLine;
|
|
187
|
+
let bufferCol = currentCol;
|
|
188
|
+
for (let li = 0; li < lines.length; li++) {
|
|
189
|
+
const line = lines[li] ?? "";
|
|
190
|
+
let charPos = li === 0 ? startColumn - 1 : 0;
|
|
191
|
+
for (let ci = 0; ci < line.length; ci++) {
|
|
192
|
+
const ch = line[ci] ?? "";
|
|
193
|
+
buffer += ch;
|
|
194
|
+
charPos++;
|
|
195
|
+
if (isSentenceEnd(ch, line, ci)) {
|
|
196
|
+
const trimmed2 = buffer.trim();
|
|
197
|
+
if (trimmed2.length > 0) {
|
|
198
|
+
sentences.push({ text: trimmed2, line: bufferLine, column: bufferCol });
|
|
199
|
+
}
|
|
200
|
+
buffer = "";
|
|
201
|
+
bufferLine = currentLine;
|
|
202
|
+
bufferCol = charPos + 1;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (li < lines.length - 1) {
|
|
206
|
+
buffer += "\n";
|
|
207
|
+
currentLine++;
|
|
208
|
+
currentCol = 1;
|
|
209
|
+
if (buffer.trim() === "") {
|
|
210
|
+
bufferLine = currentLine;
|
|
211
|
+
bufferCol = 1;
|
|
212
|
+
buffer = "";
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const trimmed = buffer.trim();
|
|
217
|
+
if (trimmed.length > 0) {
|
|
218
|
+
sentences.push({ text: trimmed, line: bufferLine, column: bufferCol });
|
|
219
|
+
}
|
|
220
|
+
return sentences;
|
|
221
|
+
}
|
|
222
|
+
function isSentenceEnd(ch, line, index) {
|
|
223
|
+
if ("\u3002\uFF01\uFF1F".includes(ch)) return true;
|
|
224
|
+
if (ch === "." || ch === "!" || ch === "?") {
|
|
225
|
+
const next = line[index + 1];
|
|
226
|
+
if (next === void 0 || next === " " || next === " ") return true;
|
|
227
|
+
}
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/rules/structure.ts
|
|
232
|
+
function applyStructureRule(rule, nodes) {
|
|
233
|
+
const messages = [];
|
|
234
|
+
const target = rule.target ?? "sentence";
|
|
235
|
+
if (target === "heading") {
|
|
236
|
+
return applyHeadingRules(rule, nodes);
|
|
237
|
+
}
|
|
238
|
+
for (const node of nodes) {
|
|
239
|
+
if (node.nodeType === "heading") continue;
|
|
240
|
+
if (rule.max_chars !== void 0) {
|
|
241
|
+
const sentences = splitSentences(node.text, node.line, node.column);
|
|
242
|
+
for (const sentence of sentences) {
|
|
243
|
+
if (sentence.text.length > rule.max_chars) {
|
|
244
|
+
messages.push({
|
|
245
|
+
ruleId: rule.id,
|
|
246
|
+
severity: rule.severity,
|
|
247
|
+
message: `\u4E00\u6587\u304C${sentence.text.length}\u6587\u5B57\u3067\u3059\uFF08\u4E0A\u9650: ${rule.max_chars}\u6587\u5B57\uFF09`,
|
|
248
|
+
line: sentence.line,
|
|
249
|
+
column: sentence.column,
|
|
250
|
+
source: sentence.text.slice(0, 40) + (sentence.text.length > 40 ? "..." : "")
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return messages;
|
|
257
|
+
}
|
|
258
|
+
function applyHeadingRules(rule, nodes) {
|
|
259
|
+
const messages = [];
|
|
260
|
+
for (const node of nodes) {
|
|
261
|
+
if (node.nodeType !== "heading") continue;
|
|
262
|
+
if (rule.max_level !== void 0 && node.headingDepth !== void 0) {
|
|
263
|
+
if (node.headingDepth > rule.max_level) {
|
|
264
|
+
messages.push({
|
|
265
|
+
ruleId: rule.id,
|
|
266
|
+
severity: rule.severity,
|
|
267
|
+
message: `\u898B\u51FA\u3057\u30EC\u30D9\u30EB${node.headingDepth}\u306F\u4E0A\u9650\uFF08H${rule.max_level}\uFF09\u3092\u8D85\u3048\u3066\u3044\u307E\u3059`,
|
|
268
|
+
line: node.line,
|
|
269
|
+
column: node.column,
|
|
270
|
+
source: node.text
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (rule.no_period === true) {
|
|
275
|
+
if (/[。..]$/.test(node.text.trim())) {
|
|
276
|
+
messages.push({
|
|
277
|
+
ruleId: rule.id,
|
|
278
|
+
severity: rule.severity,
|
|
279
|
+
message: "\u898B\u51FA\u3057\u306E\u672B\u5C3E\u306B\u53E5\u70B9\u3092\u4F7F\u308F\u306A\u3044\u3067\u304F\u3060\u3055\u3044",
|
|
280
|
+
line: node.line,
|
|
281
|
+
column: node.column,
|
|
282
|
+
source: node.text
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return messages;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/rules/engine.ts
|
|
291
|
+
function lintText(content, filePath, config) {
|
|
292
|
+
const doc = parseMarkdown(content);
|
|
293
|
+
const messages = [];
|
|
294
|
+
for (const rule of config.rules) {
|
|
295
|
+
switch (rule.type) {
|
|
296
|
+
case "pattern":
|
|
297
|
+
messages.push(...applyPatternRule(rule, doc.textNodes));
|
|
298
|
+
break;
|
|
299
|
+
case "dictionary":
|
|
300
|
+
messages.push(...applyDictionaryRule(rule, doc.textNodes));
|
|
301
|
+
break;
|
|
302
|
+
case "structure":
|
|
303
|
+
messages.push(...applyStructureRule(rule, doc.textNodes));
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
messages.sort((a, b) => a.line !== b.line ? a.line - b.line : a.column - b.column);
|
|
308
|
+
return {
|
|
309
|
+
filePath,
|
|
310
|
+
messages,
|
|
311
|
+
errorCount: messages.filter((m) => m.severity === "error").length,
|
|
312
|
+
warningCount: messages.filter((m) => m.severity === "warning").length,
|
|
313
|
+
infoCount: messages.filter((m) => m.severity === "info").length
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function lintFile(filePath, config) {
|
|
317
|
+
const content = (0, import_node_fs.readFileSync)(filePath, "utf-8");
|
|
318
|
+
return lintText(content, filePath, config);
|
|
319
|
+
}
|
|
320
|
+
function lintFiles(filePaths, config) {
|
|
321
|
+
return filePaths.map((fp) => lintFile(fp, config));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/config/loader.ts
|
|
325
|
+
var import_node_fs2 = require("fs");
|
|
326
|
+
var import_node_path = require("path");
|
|
327
|
+
var import_js_yaml = __toESM(require("js-yaml"), 1);
|
|
328
|
+
|
|
329
|
+
// src/rules/types.ts
|
|
330
|
+
var import_zod = require("zod");
|
|
331
|
+
var SeveritySchema = import_zod.z.enum(["error", "warning", "info"]);
|
|
332
|
+
var PatternRuleSchema = import_zod.z.object({
|
|
333
|
+
id: import_zod.z.string().min(1),
|
|
334
|
+
type: import_zod.z.literal("pattern"),
|
|
335
|
+
description: import_zod.z.string().optional(),
|
|
336
|
+
severity: SeveritySchema.default("warning"),
|
|
337
|
+
patterns: import_zod.z.array(
|
|
338
|
+
import_zod.z.object({
|
|
339
|
+
regex: import_zod.z.string().min(1),
|
|
340
|
+
message: import_zod.z.string().min(1),
|
|
341
|
+
flags: import_zod.z.string().optional()
|
|
342
|
+
})
|
|
343
|
+
).min(1)
|
|
344
|
+
});
|
|
345
|
+
var DictionaryRuleSchema = import_zod.z.object({
|
|
346
|
+
id: import_zod.z.string().min(1),
|
|
347
|
+
type: import_zod.z.literal("dictionary"),
|
|
348
|
+
description: import_zod.z.string().optional(),
|
|
349
|
+
severity: SeveritySchema.default("warning"),
|
|
350
|
+
terms: import_zod.z.array(
|
|
351
|
+
import_zod.z.object({
|
|
352
|
+
prefer: import_zod.z.string().min(1),
|
|
353
|
+
avoid: import_zod.z.array(import_zod.z.string().min(1)).min(1)
|
|
354
|
+
})
|
|
355
|
+
).min(1)
|
|
356
|
+
});
|
|
357
|
+
var StructureRuleSchema = import_zod.z.object({
|
|
358
|
+
id: import_zod.z.string().min(1),
|
|
359
|
+
type: import_zod.z.literal("structure"),
|
|
360
|
+
description: import_zod.z.string().optional(),
|
|
361
|
+
severity: SeveritySchema.default("warning"),
|
|
362
|
+
target: import_zod.z.enum(["sentence", "heading"]).default("sentence"),
|
|
363
|
+
max_chars: import_zod.z.number().int().positive().optional(),
|
|
364
|
+
max_level: import_zod.z.number().int().min(1).max(6).optional(),
|
|
365
|
+
no_period: import_zod.z.boolean().optional()
|
|
366
|
+
});
|
|
367
|
+
var RuleSchema = import_zod.z.discriminatedUnion("type", [
|
|
368
|
+
PatternRuleSchema,
|
|
369
|
+
DictionaryRuleSchema,
|
|
370
|
+
StructureRuleSchema
|
|
371
|
+
]);
|
|
372
|
+
var ContextSchema = import_zod.z.object({
|
|
373
|
+
glossary: import_zod.z.string().optional(),
|
|
374
|
+
style_guide: import_zod.z.string().optional()
|
|
375
|
+
}).optional();
|
|
376
|
+
var ConfigSchema = import_zod.z.object({
|
|
377
|
+
rules: import_zod.z.array(RuleSchema).default([]),
|
|
378
|
+
context: ContextSchema
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// src/config/loader.ts
|
|
382
|
+
var CONFIG_FILE_NAMES = [".prooflint.yml", ".prooflint.yaml", "prooflint.config.yml"];
|
|
383
|
+
function findConfigFile(cwd = process.cwd()) {
|
|
384
|
+
for (const name of CONFIG_FILE_NAMES) {
|
|
385
|
+
const candidate = (0, import_node_path.resolve)(cwd, name);
|
|
386
|
+
try {
|
|
387
|
+
(0, import_node_fs2.readFileSync)(candidate);
|
|
388
|
+
return candidate;
|
|
389
|
+
} catch {
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
function loadConfig(configPath) {
|
|
395
|
+
const raw = (0, import_node_fs2.readFileSync)(configPath, "utf-8");
|
|
396
|
+
const parsed = import_js_yaml.default.load(raw);
|
|
397
|
+
const result = ConfigSchema.safeParse(parsed);
|
|
398
|
+
if (!result.success) {
|
|
399
|
+
const issues = result.error.issues.map((issue) => ` - ${issue.path.join(".")}: ${issue.message}`).join("\n");
|
|
400
|
+
throw new Error(`Invalid config at ${configPath}:
|
|
401
|
+
${issues}`);
|
|
402
|
+
}
|
|
403
|
+
return result.data;
|
|
404
|
+
}
|
|
405
|
+
function loadConfigFromCwd(cwd = process.cwd()) {
|
|
406
|
+
const configPath = findConfigFile(cwd);
|
|
407
|
+
if (!configPath) {
|
|
408
|
+
return ConfigSchema.parse({});
|
|
409
|
+
}
|
|
410
|
+
return loadConfig(configPath);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// src/reporter/console.ts
|
|
414
|
+
var import_chalk = __toESM(require("chalk"), 1);
|
|
415
|
+
function severityLabel(severity) {
|
|
416
|
+
switch (severity) {
|
|
417
|
+
case "error":
|
|
418
|
+
return import_chalk.default.red("error");
|
|
419
|
+
case "warning":
|
|
420
|
+
return import_chalk.default.yellow("warn ");
|
|
421
|
+
case "info":
|
|
422
|
+
return import_chalk.default.blue("info ");
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function formatMessage(msg) {
|
|
426
|
+
const location = import_chalk.default.dim(`${String(msg.line).padStart(4)}:${String(msg.column).padEnd(4)}`);
|
|
427
|
+
const sev = severityLabel(msg.severity);
|
|
428
|
+
const text = msg.message;
|
|
429
|
+
const rule = import_chalk.default.dim(msg.ruleId);
|
|
430
|
+
return ` ${location} ${sev} ${text} ${rule}`;
|
|
431
|
+
}
|
|
432
|
+
function formatConsole(results) {
|
|
433
|
+
const lines = [];
|
|
434
|
+
let totalErrors = 0;
|
|
435
|
+
let totalWarnings = 0;
|
|
436
|
+
let totalInfos = 0;
|
|
437
|
+
for (const result of results) {
|
|
438
|
+
if (result.messages.length === 0) continue;
|
|
439
|
+
lines.push("");
|
|
440
|
+
lines.push(import_chalk.default.underline(result.filePath));
|
|
441
|
+
for (const msg of result.messages) {
|
|
442
|
+
lines.push(formatMessage(msg));
|
|
443
|
+
}
|
|
444
|
+
totalErrors += result.errorCount;
|
|
445
|
+
totalWarnings += result.warningCount;
|
|
446
|
+
totalInfos += result.infoCount;
|
|
447
|
+
}
|
|
448
|
+
const total = totalErrors + totalWarnings + totalInfos;
|
|
449
|
+
if (total === 0) {
|
|
450
|
+
lines.push(import_chalk.default.green("\n0 problems"));
|
|
451
|
+
return lines.join("\n");
|
|
452
|
+
}
|
|
453
|
+
const parts = [];
|
|
454
|
+
if (totalErrors > 0) parts.push(import_chalk.default.red(`${totalErrors} error${totalErrors > 1 ? "s" : ""}`));
|
|
455
|
+
if (totalWarnings > 0) parts.push(import_chalk.default.yellow(`${totalWarnings} warning${totalWarnings > 1 ? "s" : ""}`));
|
|
456
|
+
if (totalInfos > 0) parts.push(import_chalk.default.blue(`${totalInfos} info`));
|
|
457
|
+
lines.push("");
|
|
458
|
+
lines.push(`${total} problem${total > 1 ? "s" : ""} (${parts.join(", ")})`);
|
|
459
|
+
return lines.join("\n");
|
|
460
|
+
}
|
|
461
|
+
function hasErrors(results) {
|
|
462
|
+
return results.some((r) => r.errorCount > 0);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// src/reporter/json.ts
|
|
466
|
+
function formatJson(results) {
|
|
467
|
+
const output = {
|
|
468
|
+
results,
|
|
469
|
+
summary: {
|
|
470
|
+
totalFiles: results.length,
|
|
471
|
+
filesWithProblems: results.filter((r) => r.messages.length > 0).length,
|
|
472
|
+
totalErrors: results.reduce((s, r) => s + r.errorCount, 0),
|
|
473
|
+
totalWarnings: results.reduce((s, r) => s + r.warningCount, 0),
|
|
474
|
+
totalInfos: results.reduce((s, r) => s + r.infoCount, 0)
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
return JSON.stringify(output, null, 2);
|
|
478
|
+
}
|
|
479
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
480
|
+
0 && (module.exports = {
|
|
481
|
+
findConfigFile,
|
|
482
|
+
formatConsole,
|
|
483
|
+
formatJson,
|
|
484
|
+
hasErrors,
|
|
485
|
+
lintFile,
|
|
486
|
+
lintFiles,
|
|
487
|
+
lintText,
|
|
488
|
+
loadConfig,
|
|
489
|
+
loadConfigFromCwd
|
|
490
|
+
});
|
|
491
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/rules/engine.ts","../src/parser/markdown.ts","../src/rules/pattern.ts","../src/rules/dictionary.ts","../src/parser/sentence.ts","../src/rules/structure.ts","../src/config/loader.ts","../src/rules/types.ts","../src/reporter/console.ts","../src/reporter/json.ts"],"sourcesContent":["export { lintText, lintFile, lintFiles } from './rules/engine.js'\nexport { loadConfig, loadConfigFromCwd, findConfigFile } from './config/loader.js'\nexport { formatConsole, hasErrors } from './reporter/console.js'\nexport { formatJson } from './reporter/json.js'\nexport type {\n Config,\n Rule,\n PatternRule,\n DictionaryRule,\n StructureRule,\n LintResult,\n LintMessage,\n Severity,\n} from './rules/types.js'\n","import { readFileSync } from 'node:fs'\nimport { parseMarkdown } from '../parser/markdown.js'\nimport { applyPatternRule } from './pattern.js'\nimport { applyDictionaryRule } from './dictionary.js'\nimport { applyStructureRule } from './structure.js'\nimport type { Config, LintResult, LintMessage } from './types.js'\n\nexport function lintText(content: string, filePath: string, config: Config): LintResult {\n const doc = parseMarkdown(content)\n const messages: LintMessage[] = []\n\n for (const rule of config.rules) {\n switch (rule.type) {\n case 'pattern':\n messages.push(...applyPatternRule(rule, doc.textNodes))\n break\n case 'dictionary':\n messages.push(...applyDictionaryRule(rule, doc.textNodes))\n break\n case 'structure':\n messages.push(...applyStructureRule(rule, doc.textNodes))\n break\n }\n }\n\n // Sort by line then column\n messages.sort((a, b) => a.line !== b.line ? a.line - b.line : a.column - b.column)\n\n return {\n filePath,\n messages,\n errorCount: messages.filter((m) => m.severity === 'error').length,\n warningCount: messages.filter((m) => m.severity === 'warning').length,\n infoCount: messages.filter((m) => m.severity === 'info').length,\n }\n}\n\nexport function lintFile(filePath: string, config: Config): LintResult {\n const content = readFileSync(filePath, 'utf-8')\n return lintText(content, filePath, config)\n}\n\nexport function lintFiles(filePaths: string[], config: Config): LintResult[] {\n return filePaths.map((fp) => lintFile(fp, config))\n}\n","import { remark } from 'remark'\nimport type { Root, RootContent } from 'mdast'\n\nexport interface TextNode {\n text: string\n line: number\n column: number\n nodeType: 'paragraph' | 'heading' | 'listItem' | 'blockquote' | 'other'\n headingDepth?: number\n}\n\nexport interface ParsedDocument {\n textNodes: TextNode[]\n headings: TextNode[]\n raw: string\n}\n\nexport function parseMarkdown(content: string): ParsedDocument {\n const processor = remark()\n const tree = processor.parse(content) as Root\n const textNodes: TextNode[] = []\n const headings: TextNode[] = []\n\n function visit(node: RootContent): void {\n if (node.type === 'heading') {\n const text = extractText(node)\n const position = node.position\n const textNode: TextNode = {\n text,\n line: position?.start.line ?? 1,\n column: position?.start.column ?? 1,\n nodeType: 'heading',\n headingDepth: node.depth,\n }\n headings.push(textNode)\n textNodes.push(textNode)\n } else if (node.type === 'paragraph') {\n const text = extractText(node)\n const position = node.position\n textNodes.push({\n text,\n line: position?.start.line ?? 1,\n column: position?.start.column ?? 1,\n nodeType: 'paragraph',\n })\n } else if (node.type === 'listItem' || node.type === 'blockquote') {\n if ('children' in node) {\n for (const child of node.children) {\n visit(child as RootContent)\n }\n return\n }\n }\n\n if ('children' in node && node.type !== 'heading' && node.type !== 'paragraph') {\n for (const child of (node as { children: RootContent[] }).children) {\n visit(child)\n }\n }\n }\n\n for (const child of tree.children) {\n visit(child)\n }\n\n return { textNodes, headings, raw: content }\n}\n\nfunction extractText(node: RootContent): string {\n if ('value' in node && typeof node.value === 'string') {\n return node.value\n }\n if ('children' in node) {\n return (node as { children: RootContent[] }).children\n .map(extractText)\n .join('')\n }\n return ''\n}\n","import type { PatternRule, LintMessage } from './types.js'\nimport type { TextNode } from '../parser/markdown.js'\n\nexport function applyPatternRule(rule: PatternRule, nodes: TextNode[]): LintMessage[] {\n const messages: LintMessage[] = []\n\n for (const node of nodes) {\n for (const pattern of rule.patterns) {\n const flags = pattern.flags ?? 'g'\n let regex: RegExp\n try {\n regex = new RegExp(pattern.regex, flags.includes('g') ? flags : flags + 'g')\n } catch {\n throw new Error(`Rule \"${rule.id}\": invalid regex \"${pattern.regex}\"`)\n }\n\n let match: RegExpExecArray | null\n while ((match = regex.exec(node.text)) !== null) {\n const beforeMatch = node.text.slice(0, match.index)\n const newlines = (beforeMatch.match(/\\n/g) ?? []).length\n const lastNewline = beforeMatch.lastIndexOf('\\n')\n const col = lastNewline === -1\n ? node.column + match.index\n : match.index - lastNewline\n\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: pattern.message,\n line: node.line + newlines,\n column: col,\n source: match[0],\n })\n }\n }\n }\n\n return messages\n}\n","import type { DictionaryRule, LintMessage } from './types.js'\nimport type { TextNode } from '../parser/markdown.js'\n\n// Check if the character at position is part of a word continuation\n// We want to avoid matching \"サーバ\" inside \"サーバー\"\nfunction isWordBoundary(text: string, start: number, end: number): boolean {\n const charBefore = start > 0 ? text[start - 1] : null\n const charAfter = end < text.length ? text[end] : null\n\n // If the character immediately after is a katakana long vowel mark (ー),\n // it means the \"avoid\" word is part of a longer preferred word\n if (charAfter === 'ー' || charAfter === '〜') return false\n\n return true\n}\n\nexport function applyDictionaryRule(rule: DictionaryRule, nodes: TextNode[]): LintMessage[] {\n const messages: LintMessage[] = []\n\n for (const node of nodes) {\n for (const term of rule.terms) {\n for (const avoidWord of term.avoid) {\n // Check that prefer doesn't start with avoidWord (avoid is a prefix of prefer)\n // e.g. \"サーバ\" is a prefix of \"サーバー\", so we need boundary checking\n const preferStartsWithAvoid = term.prefer.startsWith(avoidWord)\n\n const escaped = avoidWord.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n const regex = new RegExp(escaped, 'g')\n\n let match: RegExpExecArray | null\n while ((match = regex.exec(node.text)) !== null) {\n const matchStart = match.index\n const matchEnd = matchStart + avoidWord.length\n\n // If prefer starts with avoid, check word boundary\n if (preferStartsWithAvoid && !isWordBoundary(node.text, matchStart, matchEnd)) {\n continue\n }\n\n const beforeMatch = node.text.slice(0, matchStart)\n const newlines = (beforeMatch.match(/\\n/g) ?? []).length\n const lastNewline = beforeMatch.lastIndexOf('\\n')\n const col = lastNewline === -1\n ? node.column + matchStart\n : matchStart - lastNewline\n\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: `「${avoidWord}」→「${term.prefer}」に統一してください`,\n line: node.line + newlines,\n column: col,\n source: match[0],\n })\n }\n }\n }\n }\n\n return messages\n}\n","export interface Sentence {\n text: string\n line: number\n column: number\n}\n\n// Sentence delimiters for Japanese and Western text\nconst SENTENCE_END_PATTERN = /([。!?\\.\\!\\?]+)/g\n\n/**\n * Splits a block of text into individual sentences.\n * Handles Japanese sentence endings (。!?) and Western (. ! ?).\n * Preserves line/column tracking relative to the block's starting position.\n */\nexport function splitSentences(text: string, startLine: number, startColumn: number): Sentence[] {\n const sentences: Sentence[] = []\n const lines = text.split('\\n')\n\n let currentLine = startLine\n let currentCol = startColumn\n let buffer = ''\n let bufferLine = currentLine\n let bufferCol = currentCol\n\n for (let li = 0; li < lines.length; li++) {\n const line = lines[li] ?? ''\n let charPos = li === 0 ? startColumn - 1 : 0\n\n for (let ci = 0; ci < line.length; ci++) {\n const ch = line[ci] ?? ''\n buffer += ch\n charPos++\n\n if (isSentenceEnd(ch, line, ci)) {\n const trimmed = buffer.trim()\n if (trimmed.length > 0) {\n sentences.push({ text: trimmed, line: bufferLine, column: bufferCol })\n }\n buffer = ''\n bufferLine = currentLine\n bufferCol = charPos + 1\n }\n }\n\n if (li < lines.length - 1) {\n buffer += '\\n'\n currentLine++\n currentCol = 1\n if (buffer.trim() === '') {\n bufferLine = currentLine\n bufferCol = 1\n buffer = ''\n }\n }\n }\n\n const trimmed = buffer.trim()\n if (trimmed.length > 0) {\n sentences.push({ text: trimmed, line: bufferLine, column: bufferCol })\n }\n\n return sentences\n}\n\nfunction isSentenceEnd(ch: string, line: string, index: number): boolean {\n // Japanese terminators always end sentence\n if ('。!?'.includes(ch)) return true\n\n // Western period: end only if followed by space/end or next char is uppercase\n if (ch === '.' || ch === '!' || ch === '?') {\n const next = line[index + 1]\n if (next === undefined || next === ' ' || next === '\\t') return true\n }\n\n return false\n}\n","import type { StructureRule, LintMessage } from './types.js'\nimport type { TextNode } from '../parser/markdown.js'\nimport { splitSentences } from '../parser/sentence.js'\n\nexport function applyStructureRule(rule: StructureRule, nodes: TextNode[]): LintMessage[] {\n const messages: LintMessage[] = []\n const target = rule.target ?? 'sentence'\n\n if (target === 'heading') {\n return applyHeadingRules(rule, nodes)\n }\n\n // sentence target: check sentence length\n for (const node of nodes) {\n if (node.nodeType === 'heading') continue\n\n if (rule.max_chars !== undefined) {\n const sentences = splitSentences(node.text, node.line, node.column)\n for (const sentence of sentences) {\n if (sentence.text.length > rule.max_chars) {\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: `一文が${sentence.text.length}文字です(上限: ${rule.max_chars}文字)`,\n line: sentence.line,\n column: sentence.column,\n source: sentence.text.slice(0, 40) + (sentence.text.length > 40 ? '...' : ''),\n })\n }\n }\n }\n }\n\n return messages\n}\n\nfunction applyHeadingRules(rule: StructureRule, nodes: TextNode[]): LintMessage[] {\n const messages: LintMessage[] = []\n\n for (const node of nodes) {\n if (node.nodeType !== 'heading') continue\n\n // Check heading level\n if (rule.max_level !== undefined && node.headingDepth !== undefined) {\n if (node.headingDepth > rule.max_level) {\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: `見出しレベル${node.headingDepth}は上限(H${rule.max_level})を超えています`,\n line: node.line,\n column: node.column,\n source: node.text,\n })\n }\n }\n\n // Check trailing period in heading\n if (rule.no_period === true) {\n if (/[。..]$/.test(node.text.trim())) {\n messages.push({\n ruleId: rule.id,\n severity: rule.severity,\n message: '見出しの末尾に句点を使わないでください',\n line: node.line,\n column: node.column,\n source: node.text,\n })\n }\n }\n }\n\n return messages\n}\n","import { readFileSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport yaml from 'js-yaml'\nimport { ConfigSchema } from '../rules/types.js'\nimport type { Config } from '../rules/types.js'\n\nconst CONFIG_FILE_NAMES = ['.prooflint.yml', '.prooflint.yaml', 'prooflint.config.yml']\n\nexport function findConfigFile(cwd: string = process.cwd()): string | null {\n for (const name of CONFIG_FILE_NAMES) {\n const candidate = resolve(cwd, name)\n try {\n readFileSync(candidate)\n return candidate\n } catch {\n // not found, try next\n }\n }\n return null\n}\n\nexport function loadConfig(configPath: string): Config {\n const raw = readFileSync(configPath, 'utf-8')\n const parsed = yaml.load(raw)\n const result = ConfigSchema.safeParse(parsed)\n\n if (!result.success) {\n const issues = result.error.issues\n .map((issue) => ` - ${issue.path.join('.')}: ${issue.message}`)\n .join('\\n')\n throw new Error(`Invalid config at ${configPath}:\\n${issues}`)\n }\n\n return result.data\n}\n\nexport function loadConfigFromCwd(cwd: string = process.cwd()): Config {\n const configPath = findConfigFile(cwd)\n if (!configPath) {\n return ConfigSchema.parse({})\n }\n return loadConfig(configPath)\n}\n\nexport function resolveContextPaths(config: Config, configPath: string): Config {\n if (!config.context) return config\n\n const configDir = dirname(configPath)\n return {\n ...config,\n context: {\n glossary: config.context.glossary\n ? resolve(configDir, config.context.glossary)\n : undefined,\n style_guide: config.context.style_guide\n ? resolve(configDir, config.context.style_guide)\n : undefined,\n },\n }\n}\n","import { z } from 'zod'\n\n// Severity levels\nexport const SeveritySchema = z.enum(['error', 'warning', 'info'])\nexport type Severity = z.infer<typeof SeveritySchema>\n\n// Pattern rule: regex-based matching\nexport const PatternRuleSchema = z.object({\n id: z.string().min(1),\n type: z.literal('pattern'),\n description: z.string().optional(),\n severity: SeveritySchema.default('warning'),\n patterns: z.array(\n z.object({\n regex: z.string().min(1),\n message: z.string().min(1),\n flags: z.string().optional(),\n })\n ).min(1),\n})\nexport type PatternRule = z.infer<typeof PatternRuleSchema>\n\n// Dictionary rule: term consistency\nexport const DictionaryRuleSchema = z.object({\n id: z.string().min(1),\n type: z.literal('dictionary'),\n description: z.string().optional(),\n severity: SeveritySchema.default('warning'),\n terms: z.array(\n z.object({\n prefer: z.string().min(1),\n avoid: z.array(z.string().min(1)).min(1),\n })\n ).min(1),\n})\nexport type DictionaryRule = z.infer<typeof DictionaryRuleSchema>\n\n// Structure rule: sentence length, heading constraints\nexport const StructureRuleSchema = z.object({\n id: z.string().min(1),\n type: z.literal('structure'),\n description: z.string().optional(),\n severity: SeveritySchema.default('warning'),\n target: z.enum(['sentence', 'heading']).default('sentence'),\n max_chars: z.number().int().positive().optional(),\n max_level: z.number().int().min(1).max(6).optional(),\n no_period: z.boolean().optional(),\n})\nexport type StructureRule = z.infer<typeof StructureRuleSchema>\n\n// Union of all rule types\nexport const RuleSchema = z.discriminatedUnion('type', [\n PatternRuleSchema,\n DictionaryRuleSchema,\n StructureRuleSchema,\n])\nexport type Rule = z.infer<typeof RuleSchema>\n\n// Context (optional glossary/style guide files)\nexport const ContextSchema = z.object({\n glossary: z.string().optional(),\n style_guide: z.string().optional(),\n}).optional()\nexport type Context = z.infer<typeof ContextSchema>\n\n// Full config schema (.prooflint.yml)\nexport const ConfigSchema = z.object({\n rules: z.array(RuleSchema).default([]),\n context: ContextSchema,\n})\nexport type Config = z.infer<typeof ConfigSchema>\n\n// A single lint violation\nexport interface LintMessage {\n ruleId: string\n severity: Severity\n message: string\n line: number\n column: number\n source?: string\n}\n\n// Lint result for a single file\nexport interface LintResult {\n filePath: string\n messages: LintMessage[]\n errorCount: number\n warningCount: number\n infoCount: number\n}\n","import chalk from 'chalk'\nimport type { LintResult, LintMessage, Severity } from '../rules/types.js'\n\nfunction severityLabel(severity: Severity): string {\n switch (severity) {\n case 'error':\n return chalk.red('error')\n case 'warning':\n return chalk.yellow('warn ')\n case 'info':\n return chalk.blue('info ')\n }\n}\n\nfunction formatMessage(msg: LintMessage): string {\n const location = chalk.dim(`${String(msg.line).padStart(4)}:${String(msg.column).padEnd(4)}`)\n const sev = severityLabel(msg.severity)\n const text = msg.message\n const rule = chalk.dim(msg.ruleId)\n return ` ${location} ${sev} ${text} ${rule}`\n}\n\nexport function formatConsole(results: LintResult[]): string {\n const lines: string[] = []\n let totalErrors = 0\n let totalWarnings = 0\n let totalInfos = 0\n\n for (const result of results) {\n if (result.messages.length === 0) continue\n\n lines.push('')\n lines.push(chalk.underline(result.filePath))\n\n for (const msg of result.messages) {\n lines.push(formatMessage(msg))\n }\n\n totalErrors += result.errorCount\n totalWarnings += result.warningCount\n totalInfos += result.infoCount\n }\n\n const total = totalErrors + totalWarnings + totalInfos\n if (total === 0) {\n lines.push(chalk.green('\\n0 problems'))\n return lines.join('\\n')\n }\n\n const parts: string[] = []\n if (totalErrors > 0) parts.push(chalk.red(`${totalErrors} error${totalErrors > 1 ? 's' : ''}`))\n if (totalWarnings > 0) parts.push(chalk.yellow(`${totalWarnings} warning${totalWarnings > 1 ? 's' : ''}`))\n if (totalInfos > 0) parts.push(chalk.blue(`${totalInfos} info`))\n\n lines.push('')\n lines.push(`${total} problem${total > 1 ? 's' : ''} (${parts.join(', ')})`)\n\n return lines.join('\\n')\n}\n\nexport function hasErrors(results: LintResult[]): boolean {\n return results.some((r) => r.errorCount > 0)\n}\n","import type { LintResult } from '../rules/types.js'\n\nexport interface JsonOutput {\n results: LintResult[]\n summary: {\n totalFiles: number\n filesWithProblems: number\n totalErrors: number\n totalWarnings: number\n totalInfos: number\n }\n}\n\nexport function formatJson(results: LintResult[]): string {\n const output: JsonOutput = {\n results,\n summary: {\n totalFiles: results.length,\n filesWithProblems: results.filter((r) => r.messages.length > 0).length,\n totalErrors: results.reduce((s, r) => s + r.errorCount, 0),\n totalWarnings: results.reduce((s, r) => s + r.warningCount, 0),\n totalInfos: results.reduce((s, r) => s + r.infoCount, 0),\n },\n }\n return JSON.stringify(output, null, 2)\n}\n"],"mappings":"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","names":["trimmed","import_node_fs","yaml","chalk"]}
|