chaffjs 0.8.0 → 0.9.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/dist/address-chain.d.ts +9 -0
- package/dist/address-chain.d.ts.map +1 -0
- package/dist/address-chain.js +105 -0
- package/dist/address-chain.js.map +1 -0
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +1 -1
- package/dist/cli-args.js.map +1 -1
- package/dist/cli-text.d.ts.map +1 -1
- package/dist/cli-text.js +4 -0
- package/dist/cli-text.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +2 -1
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/feedback.d.ts +35 -0
- package/dist/commands/feedback.d.ts.map +1 -0
- package/dist/commands/feedback.js +157 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/test.d.ts.map +1 -1
- package/dist/commands/test.js +3 -2
- package/dist/commands/test.js.map +1 -1
- package/dist/commands/tree.d.ts.map +1 -1
- package/dist/commands/tree.js +3 -1
- package/dist/commands/tree.js.map +1 -1
- package/dist/config/by-path.d.ts +5 -1
- package/dist/config/by-path.d.ts.map +1 -1
- package/dist/config/by-path.js +1 -4
- package/dist/config/by-path.js.map +1 -1
- package/dist/config/load.d.ts +2 -0
- package/dist/config/load.d.ts.map +1 -1
- package/dist/config/load.js +3 -1
- package/dist/config/load.js.map +1 -1
- package/dist/detectors/char-shape.d.ts.map +1 -1
- package/dist/detectors/char-shape.js +3 -2
- package/dist/detectors/char-shape.js.map +1 -1
- package/dist/document.d.ts +2 -2
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +4 -2
- package/dist/document.js.map +1 -1
- package/dist/feedback/draft.d.ts +28 -0
- package/dist/feedback/draft.d.ts.map +1 -0
- package/dist/feedback/draft.js +66 -0
- package/dist/feedback/draft.js.map +1 -0
- package/dist/feedback/excerpt.d.ts +10 -0
- package/dist/feedback/excerpt.d.ts.map +1 -0
- package/dist/feedback/excerpt.js +20 -0
- package/dist/feedback/excerpt.js.map +1 -0
- package/dist/legal-address.d.ts +2 -0
- package/dist/legal-address.d.ts.map +1 -0
- package/dist/legal-address.js +16 -0
- package/dist/legal-address.js.map +1 -0
- package/dist/orthography.d.ts.map +1 -1
- package/dist/orthography.js +15 -0
- package/dist/orthography.js.map +1 -1
- package/dist/plugin.d.ts +88 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/profile/for-file.d.ts +7 -0
- package/dist/profile/for-file.d.ts.map +1 -0
- package/dist/profile/for-file.js +6 -0
- package/dist/profile/for-file.js.map +1 -0
- package/dist/profile/load.d.ts +4 -0
- package/dist/profile/load.d.ts.map +1 -0
- package/dist/profile/load.js +25 -0
- package/dist/profile/load.js.map +1 -0
- package/dist/profile/parse.d.ts +19 -0
- package/dist/profile/parse.d.ts.map +1 -0
- package/dist/profile/parse.js +82 -0
- package/dist/profile/parse.js.map +1 -0
- package/dist/profile/select.d.ts +22 -0
- package/dist/profile/select.d.ts.map +1 -0
- package/dist/profile/select.js +21 -0
- package/dist/profile/select.js.map +1 -0
- package/dist/reasons.d.ts +1 -0
- package/dist/reasons.d.ts.map +1 -1
- package/dist/reasons.js +2 -0
- package/dist/reasons.js.map +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +24 -3
- package/dist/run.js.map +1 -1
- package/dist/structure/build.d.ts +2 -1
- package/dist/structure/build.d.ts.map +1 -1
- package/dist/structure/build.js +94 -7
- package/dist/structure/build.js.map +1 -1
- package/dist/structure/issues.d.ts.map +1 -1
- package/dist/structure/issues.js +9 -2
- package/dist/structure/issues.js.map +1 -1
- package/dist/structure/of.d.ts +2 -1
- package/dist/structure/of.d.ts.map +1 -1
- package/dist/structure/of.js +7 -1
- package/dist/structure/of.js.map +1 -1
- package/dist/structure/relative-find.d.ts +6 -0
- package/dist/structure/relative-find.d.ts.map +1 -0
- package/dist/structure/relative-find.js +179 -0
- package/dist/structure/relative-find.js.map +1 -0
- package/dist/structure/relative-resolve.d.ts +3 -0
- package/dist/structure/relative-resolve.d.ts.map +1 -0
- package/dist/structure/relative-resolve.js +175 -0
- package/dist/structure/relative-resolve.js.map +1 -0
- package/dist/structure/unread.d.ts +8 -0
- package/dist/structure/unread.d.ts.map +1 -0
- package/dist/structure/unread.js +34 -0
- package/dist/structure/unread.js.map +1 -0
- package/package.json +4 -3
- package/profiles/statute.yaml +62 -0
- package/skills/chaff/SKILL.md +24 -4
- package/src/address-chain.ts +113 -0
- package/src/cli-args.ts +1 -1
- package/src/cli-text.ts +4 -0
- package/src/cli.ts +20 -1
- package/src/commands/eval.ts +2 -1
- package/src/commands/feedback.ts +210 -0
- package/src/commands/test.ts +3 -2
- package/src/commands/tree.ts +3 -1
- package/src/config/by-path.ts +11 -3
- package/src/config/load.ts +5 -1
- package/src/detectors/char-shape.ts +5 -4
- package/src/document.ts +11 -3
- package/src/feedback/draft.ts +102 -0
- package/src/feedback/excerpt.ts +23 -0
- package/src/orthography.ts +15 -0
- package/src/plugin.ts +82 -0
- package/src/profile/for-file.ts +11 -0
- package/src/profile/load.ts +26 -0
- package/src/profile/parse.ts +106 -0
- package/src/profile/select.ts +35 -0
- package/src/reasons.ts +5 -0
- package/src/run.ts +25 -3
- package/src/structure/build.ts +118 -10
- package/src/structure/issues.ts +10 -2
- package/src/structure/of.ts +15 -3
- package/src/structure/relative-find.ts +224 -0
- package/src/structure/relative-resolve.ts +209 -0
- package/src/structure/unread.ts +39 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
const NUMBERED = new Set(["chapter", "article", "item"]);
|
|
2
|
+
const placeOf = (node) => NUMBERED.has(node.kind) && node.level !== undefined ? { address: node.address, level: node.level, range: node.ordinalTo !== undefined } : undefined;
|
|
3
|
+
/** 番号の付いた子。Markdown の見出し(section)は番号の外なので、その中まで見る。 */
|
|
4
|
+
const numberedChildren = (node, level) => node.children.flatMap((child) => {
|
|
5
|
+
if (NUMBERED.has(child.kind))
|
|
6
|
+
return child.level === level ? [child] : [];
|
|
7
|
+
return child.kind === "section" ? numberedChildren(child, level) : [];
|
|
8
|
+
});
|
|
9
|
+
/** 同じ親の下で同じ深さのもの。番号の無い最初のもの(法令の第 1 項)があるなら、それを先頭に足す。 */
|
|
10
|
+
const siblingsUnder = (parent, level, implicitLevel) => {
|
|
11
|
+
const children = numberedChildren(parent, level);
|
|
12
|
+
const explicit = children.flatMap((child) => {
|
|
13
|
+
const place = placeOf(child);
|
|
14
|
+
return place === undefined ? [] : [place];
|
|
15
|
+
});
|
|
16
|
+
const firstOrdinal = children[0]?.ordinal;
|
|
17
|
+
const implicit = level === implicitLevel && parent.level === level - 1 && firstOrdinal !== 1;
|
|
18
|
+
return implicit ? [{ address: `${parent.address}.1`, level }, ...explicit] : explicit;
|
|
19
|
+
};
|
|
20
|
+
/** 書いた場所を含む、その深さのまとまり。第 1 項の本文にいて項が開いていなければ、番号の無い第 1 項。 */
|
|
21
|
+
const anchorAt = (path, level, context) => {
|
|
22
|
+
const index = path.findLastIndex((node) => NUMBERED.has(node.kind) && node.level === level);
|
|
23
|
+
const node = path[index];
|
|
24
|
+
if (node !== undefined) {
|
|
25
|
+
const place = placeOf(node);
|
|
26
|
+
// 親は番号の付いた一つ上のまとまり。あいだの Markdown の見出しは飛ばす。無ければ文書(条より外のまとまり)。
|
|
27
|
+
const parent = path.slice(0, index).findLast((candidate) => NUMBERED.has(candidate.kind) && (candidate.level ?? 0) < level) ?? path[0];
|
|
28
|
+
if (place === undefined || parent === undefined)
|
|
29
|
+
return undefined;
|
|
30
|
+
return { place, siblings: node.kind === "article" ? context.articles : siblingsUnder(parent, level, context.implicitLevel) };
|
|
31
|
+
}
|
|
32
|
+
const parent = path.findLast((candidate) => NUMBERED.has(candidate.kind) && candidate.level === level - 1);
|
|
33
|
+
if (level !== context.implicitLevel || parent === undefined)
|
|
34
|
+
return undefined;
|
|
35
|
+
const siblings = siblingsUnder(parent, level, context.implicitLevel);
|
|
36
|
+
const first = siblings[0];
|
|
37
|
+
return first === undefined ? undefined : { place: first, siblings };
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* by だけ前後にずらす。範囲の行(第四十三条から第五十五条まで 削除)は中の条を一つずつ持たないので、数えてまたげば行き先がずれる。
|
|
41
|
+
* 前に数えて範囲をまたぐか範囲に当たる、後ろに数えて範囲をまたぐなら決めない。後ろに数えて範囲に当たるのは、その最初の条なので正しい。
|
|
42
|
+
*/
|
|
43
|
+
const shifted = (anchor, by) => {
|
|
44
|
+
const index = anchor.siblings.findIndex((place) => place.address === anchor.place.address);
|
|
45
|
+
if (index === -1)
|
|
46
|
+
return undefined;
|
|
47
|
+
const crossed = by > 0 ? anchor.siblings.slice(index + 1, index + by) : anchor.siblings.slice(Math.max(0, index + by), index);
|
|
48
|
+
return crossed.some((place) => place.range === true) ? undefined : anchor.siblings[index + by];
|
|
49
|
+
};
|
|
50
|
+
/** 前の全部(前各項)は、前に一つでもあれば最初のもの。 */
|
|
51
|
+
const allBefore = (anchor) => (shifted(anchor, -1) === undefined ? undefined : anchor.siblings[0]);
|
|
52
|
+
/**
|
|
53
|
+
* 前・次・本で決まる場所。「各」(count 0)は前の全部なので、最初のものを指す。
|
|
54
|
+
*/
|
|
55
|
+
const byPosition = (way, count, anchor) => {
|
|
56
|
+
if (way === "current")
|
|
57
|
+
return anchor.place;
|
|
58
|
+
if (way === "after")
|
|
59
|
+
return shifted(anchor, Math.max(count, 1));
|
|
60
|
+
return count === 0 ? allBefore(anchor) : shifted(anchor, -count);
|
|
61
|
+
};
|
|
62
|
+
/** 同: その前の参照の番地を、この深さまで切る。条より外のまとまりは番地の形が違うので扱わない。 */
|
|
63
|
+
const bySame = (level, last) => (last === undefined ? undefined : { address: last.target, level });
|
|
64
|
+
/** 並びの続き: 元の参照の番地を、この深さまで切る。元の参照の番地が決まらなければ決めない。 */
|
|
65
|
+
const continued = (level, node, context) => {
|
|
66
|
+
const origin = context.byStart.get(node.span.start - Number(node.attrs["continues"]));
|
|
67
|
+
if (origin === undefined || context.articleLevel === undefined || level < context.articleLevel)
|
|
68
|
+
return undefined;
|
|
69
|
+
const parts = origin.target.split(".");
|
|
70
|
+
const kept = level - context.articleLevel + 1;
|
|
71
|
+
return parts.length < kept ? undefined : { target: parts.slice(0, kept).join("."), document: origin.document };
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* 参照が名指しした深さを覚える。名指しは、書き出しの深さ(第〇条なら条、前項なら項)から番地の深さまで。
|
|
75
|
+
* 番地を深さで切る起点は条。条より外のまとまりは番地の形が違うので覚えない。
|
|
76
|
+
*/
|
|
77
|
+
const remember = (context, target, document, from) => {
|
|
78
|
+
const articleLevel = context.articleLevel;
|
|
79
|
+
// 章・節は番地の形(ch1)が条から始まらないので覚えない。覚えると「同条」が章を指してしまう。
|
|
80
|
+
if (articleLevel === undefined || from < articleLevel)
|
|
81
|
+
return;
|
|
82
|
+
const parts = target.split(".");
|
|
83
|
+
parts.forEach((_, index) => {
|
|
84
|
+
const level = articleLevel + index;
|
|
85
|
+
if (level >= from)
|
|
86
|
+
context.last.set(level, { target: parts.slice(0, index + 1).join("."), document });
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
/** 「第二項第三号」を足す。一つ深いものは続け、二つ深い号は番号の無い第 1 項の中(x.1.n)に置く。 */
|
|
90
|
+
const withSuffix = (place, suffix, implicitLevel) => suffix
|
|
91
|
+
.split(",")
|
|
92
|
+
.filter((part) => part !== "")
|
|
93
|
+
.reduce((current, part) => {
|
|
94
|
+
const [depth, value] = part.split(":").map(Number);
|
|
95
|
+
if (current === undefined || depth === undefined || value === undefined)
|
|
96
|
+
return undefined;
|
|
97
|
+
if (depth === current.level + 1)
|
|
98
|
+
return { address: `${current.address}.${String(value)}`, level: depth };
|
|
99
|
+
if (implicitLevel === current.level + 1 && depth === current.level + 2)
|
|
100
|
+
return { address: `${current.address}.1.${String(value)}`, level: depth };
|
|
101
|
+
return undefined;
|
|
102
|
+
}, place);
|
|
103
|
+
/** 番号の無い第 1 項(x.1)は、条そのものでもある。 */
|
|
104
|
+
const fallbackOf = (place, implicitLevel) => place.level === implicitLevel && place.address.endsWith(".1") ? place.address.slice(0, -".1".length) : undefined;
|
|
105
|
+
const baseOf = (way, node, anchor, last, context) => {
|
|
106
|
+
const level = Number(node.attrs["level"]);
|
|
107
|
+
if (way === "same")
|
|
108
|
+
return bySame(level, last);
|
|
109
|
+
if (way === "continue") {
|
|
110
|
+
const origin = continued(level, node, context);
|
|
111
|
+
return origin === undefined ? undefined : { address: origin.target, level };
|
|
112
|
+
}
|
|
113
|
+
return anchor === undefined ? undefined : byPosition(way, Number(node.attrs["count"]), anchor);
|
|
114
|
+
};
|
|
115
|
+
/** 同と並びの続きは、元の参照が他の文書を指していれば、それを引き継ぐ。前・次・本はこの文書の中。 */
|
|
116
|
+
const documentOf = (way, node, last, context) => {
|
|
117
|
+
if (way === "same")
|
|
118
|
+
return last?.document;
|
|
119
|
+
return way === "continue" ? continued(Number(node.attrs["level"]), node, context)?.document : undefined;
|
|
120
|
+
};
|
|
121
|
+
const resolveOne = (node, path, context) => {
|
|
122
|
+
const way = String(node.attrs["relative"]);
|
|
123
|
+
const level = Number(node.attrs["level"]);
|
|
124
|
+
const last = context.last.get(level);
|
|
125
|
+
const anchor = way === "same" || way === "continue" ? undefined : anchorAt(path, level, context);
|
|
126
|
+
const base = baseOf(way, node, anchor, last, context);
|
|
127
|
+
const place = base === undefined ? undefined : withSuffix(base, String(node.attrs["suffix"] ?? ""), context.implicitLevel);
|
|
128
|
+
if (place === undefined)
|
|
129
|
+
return undefined;
|
|
130
|
+
const fallback = fallbackOf(place, context.implicitLevel);
|
|
131
|
+
const document = documentOf(way, node, last, context);
|
|
132
|
+
const attrs = {
|
|
133
|
+
target: place.address,
|
|
134
|
+
label: String(node.attrs["label"]),
|
|
135
|
+
...(fallback === undefined ? {} : { fallback }),
|
|
136
|
+
...(document === undefined ? {} : { document }),
|
|
137
|
+
};
|
|
138
|
+
return { ...node, attrs };
|
|
139
|
+
};
|
|
140
|
+
const isRelative = (node) => node.kind === "reference" && node.attrs["relative"] !== undefined;
|
|
141
|
+
/** 文書の順に読み、参照ごとに「その前の参照」を覚える。 */
|
|
142
|
+
const walk = (node, path, context) => {
|
|
143
|
+
if (isRelative(node)) {
|
|
144
|
+
const resolved = resolveOne(node, path, context);
|
|
145
|
+
const target = resolved === undefined ? undefined : String(resolved.attrs["target"]);
|
|
146
|
+
const document = optional(resolved?.attrs["document"]);
|
|
147
|
+
if (target !== undefined)
|
|
148
|
+
context.byStart.set(node.span.start, { target, document });
|
|
149
|
+
if (target !== undefined)
|
|
150
|
+
remember(context, target, document, Number(node.attrs["names"] ?? node.attrs["level"]));
|
|
151
|
+
return resolved;
|
|
152
|
+
}
|
|
153
|
+
if (node.kind === "reference") {
|
|
154
|
+
const target = String(node.attrs["target"]);
|
|
155
|
+
const document = optional(node.attrs["document"]);
|
|
156
|
+
context.byStart.set(node.span.start, { target, document });
|
|
157
|
+
remember(context, target, document, context.articleLevel ?? 0);
|
|
158
|
+
}
|
|
159
|
+
const inside = [...path, node];
|
|
160
|
+
const children = node.children.flatMap((child) => {
|
|
161
|
+
const kept = walk(child, inside, context);
|
|
162
|
+
return kept === undefined ? [] : [kept];
|
|
163
|
+
});
|
|
164
|
+
return { ...node, children };
|
|
165
|
+
};
|
|
166
|
+
const optional = (value) => (value === undefined ? undefined : String(value));
|
|
167
|
+
const articlesOf = (node) => {
|
|
168
|
+
const place = node.kind === "article" ? placeOf(node) : undefined;
|
|
169
|
+
return [...(place === undefined ? [] : [place]), ...node.children.flatMap(articlesOf)];
|
|
170
|
+
};
|
|
171
|
+
export const resolveRelative = (tree, implicitLevel) => {
|
|
172
|
+
const articles = articlesOf(tree);
|
|
173
|
+
return walk(tree, [], { articles, articleLevel: articles[0]?.level, implicitLevel, last: new Map(), byStart: new Map() }) ?? tree;
|
|
174
|
+
};
|
|
175
|
+
//# sourceMappingURL=relative-resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relative-resolve.js","sourceRoot":"","sources":["../../src/structure/relative-resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { StructureNode } from "../plugin.ts";
|
|
2
|
+
export type Unread = {
|
|
3
|
+
readonly clauses: number;
|
|
4
|
+
readonly units: number;
|
|
5
|
+
};
|
|
6
|
+
/** 読めていなければ、本文の条項番号の数と木の番号の数。読めていれば undefined。 */
|
|
7
|
+
export declare const unreadStructure: (source: string, tree: StructureNode) => Unread | undefined;
|
|
8
|
+
//# sourceMappingURL=unread.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unread.d.ts","sourceRoot":"","sources":["../../src/structure/unread.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAoBlD,MAAM,MAAM,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAY1E,kDAAkD;AAClD,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,EAAE,MAAM,aAAa,KAAG,MAAM,GAAG,SAK9E,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 番号の付いた条項が本文にあるのに、木にほとんど入っていない文書。PDF から取り出した契約書は、字下げが深かったり
|
|
3
|
+
* 行が本文につながったりして、番号の行として読めないことが多い。そのとき構造の rule は「0 件」ではなく「読めなかった」と言う。
|
|
4
|
+
*/
|
|
5
|
+
const NUMBERED = new Set(["chapter", "article", "item"]);
|
|
6
|
+
/**
|
|
7
|
+
* 「11.3. Liability Cap」「2.1 Term」: 二段以上の番号と、大文字で始まる語。行頭か、文の区切り(「. 12.10. Waiver」)の後ろ。
|
|
8
|
+
* 語の後ろの番号(「Version 1.2 Released」「Figure 2.1 Revenue」)は条項ではない。
|
|
9
|
+
* 「1. TERM OF CONTRACT」: 行頭の一段の番号と、大文字だけの語。本文の箇条書き(「1. First」)とは分ける。
|
|
10
|
+
*/
|
|
11
|
+
const CLAUSE_NUMBERS = [/(?:^[ \t]{0,20}|[.;:][ \t]{1,10})\d{1,3}(?:\.\d{1,3}){1,4}\.?[ \t]{1,10}\p{Lu}/gmu, /^[ \t]{0,20}\d{1,3}\.[ \t]{1,10}\p{Lu}{2}/gmu];
|
|
12
|
+
/** 本文の条項番号がこれ以上あれば、番号で組んだ文書。 */
|
|
13
|
+
const MIN_CLAUSES = 5;
|
|
14
|
+
/** 木に入った番号が本文の条項番号のこの割合に届かなければ、読めていない。 */
|
|
15
|
+
const READ_SHARE = 0.25;
|
|
16
|
+
const numberedUnits = (tree) => {
|
|
17
|
+
let count = 0;
|
|
18
|
+
const pending = [tree];
|
|
19
|
+
for (let node = pending.pop(); node !== undefined; node = pending.pop()) {
|
|
20
|
+
if (NUMBERED.has(node.kind))
|
|
21
|
+
count += 1;
|
|
22
|
+
pending.push(...node.children);
|
|
23
|
+
}
|
|
24
|
+
return count;
|
|
25
|
+
};
|
|
26
|
+
/** 読めていなければ、本文の条項番号の数と木の番号の数。読めていれば undefined。 */
|
|
27
|
+
export const unreadStructure = (source, tree) => {
|
|
28
|
+
const clauses = CLAUSE_NUMBERS.reduce((total, pattern) => total + [...source.matchAll(pattern)].length, 0);
|
|
29
|
+
if (clauses < MIN_CLAUSES)
|
|
30
|
+
return undefined;
|
|
31
|
+
const units = numberedUnits(tree);
|
|
32
|
+
return units < clauses * READ_SHARE ? { clauses, units } : undefined;
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=unread.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unread.js","sourceRoot":"","sources":["../../src/structure/unread.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAEzD;;;;GAIG;AACH,MAAM,cAAc,GAAG,CAAC,mFAAmF,EAAE,8CAA8C,CAAC,CAAC;AAE7J,gCAAgC;AAChC,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,0CAA0C;AAC1C,MAAM,UAAU,GAAG,IAAI,CAAC;AAIxB,MAAM,aAAa,GAAG,CAAC,IAAmB,EAAU,EAAE;IACpD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,OAAO,GAAoB,CAAC,IAAI,CAAC,CAAC;IACxC,KAAK,IAAI,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,KAAK,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;QACxE,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,kDAAkD;AAClD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAE,IAAmB,EAAsB,EAAE;IACzF,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC3G,IAAI,OAAO,GAAG,WAAW;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAClC,OAAO,KAAK,GAAG,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chaffjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Prose validation harness. Finds what is hard to read, and never rewrites it for you.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chaff",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"README.md",
|
|
41
41
|
"bin",
|
|
42
42
|
"dist",
|
|
43
|
+
"profiles",
|
|
43
44
|
"rules",
|
|
44
45
|
"skills",
|
|
45
46
|
"src"
|
|
@@ -53,8 +54,8 @@
|
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
55
56
|
"@anthropic-ai/sdk": "^0.125.0",
|
|
56
|
-
"@chaffjs/lang-en": "0.
|
|
57
|
-
"@chaffjs/lang-ja": "0.
|
|
57
|
+
"@chaffjs/lang-en": "0.7.0",
|
|
58
|
+
"@chaffjs/lang-ja": "0.8.0",
|
|
58
59
|
"mdast-util-from-markdown": "^2.0.3",
|
|
59
60
|
"mdast-util-frontmatter": "^2.0.1",
|
|
60
61
|
"mdast-util-gfm-table": "^2.0.0",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
id: statute
|
|
2
|
+
|
|
3
|
+
name:
|
|
4
|
+
ja: 法令
|
|
5
|
+
en: Statute
|
|
6
|
+
|
|
7
|
+
why:
|
|
8
|
+
ja: 法令は条・項・号の番地を漢数字で書き(第二十二条第二項)、各号・及び・本文のような語で番地をつなぎます。番地は割れない一つの単位で、漢字の連なりとして数えません。
|
|
9
|
+
en: A statute writes its addresses in kanji numerals (第二十二条第二項) and joins them with words such as 各号, 及び or 本文. An address is one unit that cannot be broken up, and is not counted as a run of kanji.
|
|
10
|
+
|
|
11
|
+
# 設定(chaff.yaml の profile / by_path)が無いときに、内容から選ぶ。この形の行が min_lines 行以上あれば法令として読む。
|
|
12
|
+
detect:
|
|
13
|
+
ja:
|
|
14
|
+
line: "^第[〇一二三四五六七八九十百千]+条(?:の[〇一二三四五六七八九十百千]+)*[ ]"
|
|
15
|
+
min_lines: 3
|
|
16
|
+
|
|
17
|
+
ja:
|
|
18
|
+
# 番地の書き方。第 + 漢数字 + 単位、枝番号(の二)が続いてもよい。
|
|
19
|
+
# 「前二項」「前三条」は直前の二つの項・三つの条を指す番地で、数量ではない。「前二年」は期間なので書かない。
|
|
20
|
+
addresses:
|
|
21
|
+
- "第[〇一二三四五六七八九十百千]+[条項号章節款目編](?:の[〇一二三四五六七八九十百千]+)*"
|
|
22
|
+
- "前[〇一二三四五六七八九十百千]+[条項号章節款目編]"
|
|
23
|
+
# 番地と番地のあいだ、番地の後ろに付く語。
|
|
24
|
+
connectives: [各号, 各項, 及, 又, 若, 並, 中, 本文, 前段, 後段, 但書, 同条, 乃至]
|
|
25
|
+
# 番地の並びのすぐ後ろに来てよい文字。漢字が続けば、番地ではなく普通の語(第一条件、第五条中央銀行、前二項目標)。
|
|
26
|
+
address_end: "[^\\p{Script=Han}]|$"
|
|
27
|
+
# 条の見出しは、条の前の行に括弧だけで書く(「(解雇の予告)」)。括弧の中が、すぐ次の条の見出しになる。
|
|
28
|
+
caption: "^[ \\t\u3000]*[((]([^()()]{1,40})[))][ \\t\u3000]*$"
|
|
29
|
+
# 書いた場所から番地が決まる参照(前条・次項・同号・本条・前各項・前二項・前条第二項)。
|
|
30
|
+
relative:
|
|
31
|
+
before: [前]
|
|
32
|
+
after: [次]
|
|
33
|
+
same: [同]
|
|
34
|
+
current: [本]
|
|
35
|
+
every: [各]
|
|
36
|
+
count: "[〇一二三四五六七八九十百千]+"
|
|
37
|
+
# 単位の語と、lang-ja が付ける木の深さ(編 -2・章 -1・節 0・条 1・項 2・号 3)。
|
|
38
|
+
units: { 編: -2, 章: -1, 節: 0, 条: 1, 項: 2, 号: 3 }
|
|
39
|
+
suffix_prefix: 第
|
|
40
|
+
# 法令は第 1 項に番号を振らない。
|
|
41
|
+
implicit_first: 項
|
|
42
|
+
# 漢字の後ろの「前条」は語の一部(事前条件)。後ろの決まりは address_end と connectives を使う。
|
|
43
|
+
not_after: "\\p{Script=Han}"
|
|
44
|
+
# 読み替え(「『前条』とあるのは『…』と読み替える」)の括弧の中の前条・同項は、読み替える先の文の言葉。
|
|
45
|
+
substitution: { open: 「, close: 」, after: [とあるのは], before: [とあるのは, とあるのは、] }
|
|
46
|
+
# 条を書かない「第一項」「第二号」は、書いた条・項の中を指す。
|
|
47
|
+
inside: [項, 号]
|
|
48
|
+
# 並びをつなぐもの(正規表現)。「第三十三条第七項若しくは第九項」の「第九項」は、前の参照(第三十三条)の続き。
|
|
49
|
+
# 号の下の「イ」「ロ」と枝番号の「の二」も、並びの途中に挟まる番地の一部。
|
|
50
|
+
joiners:
|
|
51
|
+
- 及び
|
|
52
|
+
- 並びに
|
|
53
|
+
- 若しくは
|
|
54
|
+
- 又は
|
|
55
|
+
- から
|
|
56
|
+
- まで
|
|
57
|
+
- ただし書
|
|
58
|
+
- 、
|
|
59
|
+
- "[イロハニホヘトチリヌルヲワカヨタレソツネナラム]"
|
|
60
|
+
- "の[〇一二三四五六七八九十百千]+"
|
|
61
|
+
# 並びの途中に挟まる括弧書き。
|
|
62
|
+
aside: { open: (, close: ) }
|
package/skills/chaff/SKILL.md
CHANGED
|
@@ -17,10 +17,14 @@ npx chaffjs . --compact # two lines per finding: line:col severity me
|
|
|
17
17
|
npx chaffjs <file> --experimental # also the experimental rules
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
A run exits 1 when a finding is an `error
|
|
21
|
-
unknown `--genre`, no package for the language
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
A run exits 1 when a finding is an `error`. It also exits 1 when it could not check anything: no file to
|
|
21
|
+
check, an unknown `--genre`, no package for the language. So a clean exit means the files were checked.
|
|
22
|
+
|
|
23
|
+
After the findings comes the list of rules that did not run, and why. Only the default output shows it;
|
|
24
|
+
`--compact` gives just their number. Read it before saying a document is clean.
|
|
25
|
+
|
|
26
|
+
A run over several files prints only the files that have findings. To call one file clean, run chaff on that
|
|
27
|
+
file alone and read its list.
|
|
24
28
|
|
|
25
29
|
## For each finding, choose one of three
|
|
26
30
|
|
|
@@ -53,6 +57,22 @@ relaxing a rule.
|
|
|
53
57
|
- `npx chaffjs cite <source> <quotes.json>` checks that quotations (`[{ "address", "quote" }]`) are really in
|
|
54
58
|
the source; exit 1 if any is not. Use it to back every quotation you put in an answer or a summary.
|
|
55
59
|
|
|
60
|
+
## When chaff is wrong
|
|
61
|
+
|
|
62
|
+
If a finding is wrong for the text (a false positive), or chaff missed something it should catch, draft a report
|
|
63
|
+
for the chaff project:
|
|
64
|
+
|
|
65
|
+
```sh
|
|
66
|
+
npx chaffjs feedback <file> --rule <rule-id> [--line N] # a wrong finding
|
|
67
|
+
npx chaffjs feedback <file> --missed --line N # something missed
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
It writes `.chaff-feedback.md`: chaff's version, Node and OS, the file name, the one finding, the two lines on
|
|
71
|
+
each side of it, and the reported rule's setting in `chaff.yaml` (all of `chaff.yaml` only with `--with-config`).
|
|
72
|
+
When a rule has several findings in the file, add `--line` to pick one. It prints how to send the draft
|
|
73
|
+
(`gh issue create …`, or a link that carries the title only). It sends nothing. Show the draft to the person and let
|
|
74
|
+
them decide; their document may be private.
|
|
75
|
+
|
|
56
76
|
## Do not
|
|
57
77
|
|
|
58
78
|
- Do not change what a document says to satisfy a rule. If a finding cannot be fixed without changing the
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { DocumentProfile, Span } from "./plugin.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 番地は、つなぎの語(各号・及び・本文 …)を挟んで続く。番地とつなぎの並び全体を一つとして探す。
|
|
5
|
+
* 番地の書き方、つなぎの語、並びの後ろに来てよい文字は文書の種類(profiles/*.yaml)が持ち、ここは並べ方だけを知る。
|
|
6
|
+
*
|
|
7
|
+
* 番地は、その位置で正規表現が当たるとおりに一度だけ取り、後ろに合わせて縮めない。縮めると「第五十二条の二中央銀行」の
|
|
8
|
+
* 「第五十二条」が番地になってしまう。並びは、番地かつなぎの語で終わる切れ目のうち、後ろの決まりを満たす最も長いところまで。
|
|
9
|
+
*/
|
|
10
|
+
const escape = (word: string): string => word.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
11
|
+
|
|
12
|
+
type Compiled = { readonly find: RegExp; readonly address: RegExp; readonly connective: RegExp | undefined; readonly end: RegExp | undefined };
|
|
13
|
+
|
|
14
|
+
const compile = (profile: DocumentProfile): Compiled | undefined => {
|
|
15
|
+
if (profile.addresses.length === 0) return undefined;
|
|
16
|
+
const address = `(?:${profile.addresses.join("|")})`;
|
|
17
|
+
return {
|
|
18
|
+
find: new RegExp(address, "gu"),
|
|
19
|
+
address: new RegExp(address, "uy"),
|
|
20
|
+
connective: profile.connectives.length === 0 ? undefined : new RegExp(`(?:${profile.connectives.map(escape).join("|")})`, "uy"),
|
|
21
|
+
end: profile.addressEnd === undefined ? undefined : new RegExp(`(?=${profile.addressEnd})`, "uy"),
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const compiled = new WeakMap<DocumentProfile, Compiled | undefined>();
|
|
26
|
+
|
|
27
|
+
const patternsOf = (profile: DocumentProfile): Compiled | undefined => {
|
|
28
|
+
if (!compiled.has(profile)) compiled.set(profile, compile(profile));
|
|
29
|
+
return compiled.get(profile);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** at から pattern が当たれば、その終わり。空の一致は当たらなかったことにする。 */
|
|
33
|
+
const matchEnd = (pattern: RegExp | undefined, text: string, at: number): number | undefined => {
|
|
34
|
+
if (pattern === undefined) return undefined;
|
|
35
|
+
pattern.lastIndex = at;
|
|
36
|
+
const found = pattern.exec(text);
|
|
37
|
+
return found === null || found[0] === "" ? undefined : at + found[0].length;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const endsHere = (patterns: Compiled, text: string, at: number): boolean => {
|
|
41
|
+
if (patterns.end === undefined) return true;
|
|
42
|
+
patterns.end.lastIndex = at;
|
|
43
|
+
return patterns.end.test(text);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type Cut = { readonly end: number; readonly addresses: number };
|
|
47
|
+
|
|
48
|
+
/** at から続くつなぎの語を読み、その切れ目を cuts に足す。読み終えた位置を返す。 */
|
|
49
|
+
const readConnectives = (patterns: Compiled, text: string, at: number, addresses: number, cuts: Cut[]): number => {
|
|
50
|
+
let position = at;
|
|
51
|
+
for (let next = matchEnd(patterns.connective, text, position); next !== undefined; next = matchEnd(patterns.connective, text, position)) {
|
|
52
|
+
position = next;
|
|
53
|
+
cuts.push({ end: position, addresses });
|
|
54
|
+
}
|
|
55
|
+
return position;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 番地の後ろから並びを読み、切れ目(番地かつなぎの語の終わり)と、そこまでの番地を集める。
|
|
60
|
+
* 並びは設定しだいでいくらでも長くなるので、再帰せずに読む。
|
|
61
|
+
*/
|
|
62
|
+
const readChain = (patterns: Compiled, text: string, first: Span): { spans: Span[]; cuts: Cut[] } => {
|
|
63
|
+
const spans: Span[] = [first];
|
|
64
|
+
const cuts: Cut[] = [{ end: first.end, addresses: 1 }];
|
|
65
|
+
let at = first.end;
|
|
66
|
+
for (;;) {
|
|
67
|
+
const next = readConnectives(patterns, text, at, spans.length, cuts);
|
|
68
|
+
const addressEnd = matchEnd(patterns.address, text, next);
|
|
69
|
+
if (addressEnd === undefined) return { spans, cuts };
|
|
70
|
+
spans.push({ start: next, end: addressEnd });
|
|
71
|
+
cuts.push({ end: addressEnd, addresses: spans.length });
|
|
72
|
+
at = addressEnd;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/** start から始まる並び。後ろの決まりを満たす切れ目が無ければ、並びではない。 */
|
|
77
|
+
const chainAt = (patterns: Compiled, text: string, start: number): { readonly spans: readonly Span[]; readonly end: number } | undefined => {
|
|
78
|
+
const firstEnd = matchEnd(patterns.address, text, start);
|
|
79
|
+
if (firstEnd === undefined) return undefined;
|
|
80
|
+
const { spans, cuts } = readChain(patterns, text, { start, end: firstEnd });
|
|
81
|
+
const cut = [...cuts].reverse().find((candidate) => endsHere(patterns, text, candidate.end));
|
|
82
|
+
return cut === undefined ? undefined : { spans: spans.slice(0, cut.addresses), end: cut.end };
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/** 1 文字先。絵文字のような 2 単位の文字の途中に止まると、同じ位置の空の一致を繰り返す。 */
|
|
86
|
+
const nextCharacter = (text: string, at: number): number => at + ((text.codePointAt(at) ?? 0) > 0xffff ? 2 : 1);
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 並びとして認めた範囲の中の番地の範囲。「第一条件」「前二項中央銀行」のように後ろが語に続くものは、並びにならないので含まない。
|
|
90
|
+
* 漢字の連なりを数える側も数量を読む側も、同じ範囲を使う。
|
|
91
|
+
*/
|
|
92
|
+
export const addressSpans = (text: string, profile: DocumentProfile | undefined): Span[] => {
|
|
93
|
+
const patterns = profile === undefined ? undefined : patternsOf(profile);
|
|
94
|
+
if (patterns === undefined) return [];
|
|
95
|
+
const spans: Span[] = [];
|
|
96
|
+
patterns.find.lastIndex = 0;
|
|
97
|
+
for (let found = patterns.find.exec(text); found !== null; found = patterns.find.exec(text)) {
|
|
98
|
+
const chain = chainAt(patterns, text, found.index);
|
|
99
|
+
spans.push(...(chain?.spans ?? []));
|
|
100
|
+
patterns.find.lastIndex = chain === undefined ? nextCharacter(text, found.index) : chain.end;
|
|
101
|
+
}
|
|
102
|
+
return spans;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/** 番地を空白にする。空白が連なりを切るので、番地は数えられず、前後は別の連なりになる。 */
|
|
106
|
+
export const maskAddresses = (text: string, profile: DocumentProfile | undefined): string => {
|
|
107
|
+
const spans = addressSpans(text, profile);
|
|
108
|
+
if (spans.length === 0) return text;
|
|
109
|
+
const pieces: string[] = [];
|
|
110
|
+
spans.forEach((span, index) => pieces.push(text.slice(spans[index - 1]?.end ?? 0, span.start), " "));
|
|
111
|
+
pieces.push(text.slice(spans.at(-1)?.end ?? 0));
|
|
112
|
+
return pieces.join("");
|
|
113
|
+
};
|
package/src/cli-args.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Options of the commands that take files to check, whose value is the next argument. That value is not a file.
|
|
3
3
|
* `--why` (relax), `--format` and `--language` (tree) belong to commands that read their own arguments.
|
|
4
4
|
*/
|
|
5
|
-
export const VALUE_FLAGS: readonly string[] = ["--sarif", "--genre", "--rule"];
|
|
5
|
+
export const VALUE_FLAGS: readonly string[] = ["--sarif", "--genre", "--rule", "--line"];
|
|
6
6
|
|
|
7
7
|
/** The arguments that name what to check: everything that is neither an option nor an option's value. */
|
|
8
8
|
export const targetsOf = (args: readonly string[]): string[] =>
|
package/src/cli-text.ts
CHANGED
|
@@ -22,6 +22,8 @@ const USAGE_JA = `chaff — 文章の読みにくいところを見つけます
|
|
|
22
22
|
chaff suppressions <dir> stet で黙らせている指摘を数える
|
|
23
23
|
chaff relax|strict|off <rule> [--why "理由"]
|
|
24
24
|
chaff skill [--global] Claude Code の skill を入れる(.claude/skills/chaff/、--global で ~/.claude/)
|
|
25
|
+
chaff feedback <file> --rule <rule> [--line N] | --missed --line N
|
|
26
|
+
誤った指摘・見逃しの報告の下書きを作る(何も送らない。--with-config で chaff.yaml 全体も載せる)
|
|
25
27
|
|
|
26
28
|
--compact エンジニア向けの 1 行形式
|
|
27
29
|
--experimental 試験中の rule も動かす
|
|
@@ -53,6 +55,8 @@ const USAGE_EN = `chaff — finds what makes writing hard to read. It never rewr
|
|
|
53
55
|
chaff suppressions <dir> count the findings silenced with stet
|
|
54
56
|
chaff relax|strict|off <rule> [--why "reason"]
|
|
55
57
|
chaff skill [--global] install the Claude Code skill (.claude/skills/chaff/; --global for ~/.claude/)
|
|
58
|
+
chaff feedback <file> --rule <rule> [--line N] | --missed --line N
|
|
59
|
+
draft a report of a wrong or missed finding (sends nothing; --with-config adds all of chaff.yaml)
|
|
56
60
|
|
|
57
61
|
--compact one line per finding, for engineers
|
|
58
62
|
--experimental run the experimental rules too
|
package/src/cli.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { VERSION } from "./version.ts";
|
|
|
27
27
|
import { runTree, treeTargets, type TreeContext } from "./commands/tree.ts";
|
|
28
28
|
import { citeTargets, runCite } from "./commands/cite.ts";
|
|
29
29
|
import { runSkill } from "./commands/skill.ts";
|
|
30
|
+
import { runFeedback, settingsOf } from "./commands/feedback.ts";
|
|
30
31
|
import { homedir } from "node:os";
|
|
31
32
|
import { ruleProblems } from "./config/rule-problems.ts";
|
|
32
33
|
import { renderSummary, type FileOutcome } from "./render/summary.ts";
|
|
@@ -34,6 +35,7 @@ import { neededBy, runRules } from "./run.ts";
|
|
|
34
35
|
import type { Level, RuleDefinition } from "./plugin.ts";
|
|
35
36
|
import { CLI_TEXT, type CliText, type GenreSource } from "./cli-text.ts";
|
|
36
37
|
import { hostLanguage, uiLanguageOf, type UiLanguage } from "./ui.ts";
|
|
38
|
+
import { profileFor } from "./profile/for-file.ts";
|
|
37
39
|
|
|
38
40
|
/** Text for output that is not about one document. */
|
|
39
41
|
const hostText = (config: Config): CliText => CLI_TEXT[hostLanguage(config.language, process.env)];
|
|
@@ -82,6 +84,7 @@ type Inspected = {
|
|
|
82
84
|
readonly rules: readonly RuleDefinition[];
|
|
83
85
|
/** ファイルごとの言語。by_path で 1 つの repo に 2 言語が混ざる。 */
|
|
84
86
|
readonly language: string;
|
|
87
|
+
readonly genre: string;
|
|
85
88
|
readonly outcome: FileOutcome;
|
|
86
89
|
readonly perFile: PerFile;
|
|
87
90
|
readonly all: readonly string[];
|
|
@@ -101,7 +104,7 @@ const inspect = async (path: string, config: Config, argv: readonly string[]): P
|
|
|
101
104
|
const rules = loadRules(language);
|
|
102
105
|
const experimental = config.experimental || argv.includes("--experimental");
|
|
103
106
|
await adapter.prepare?.(neededBy(rules, config.rules, experimental, genre, language));
|
|
104
|
-
const doc = buildDocument(path, source, adapter, teamRules(config));
|
|
107
|
+
const doc = buildDocument(path, source, adapter, teamRules(config), profileFor(config, path, source, language));
|
|
105
108
|
const raw = runRules(doc, rules, config.rules, experimental, genre, config.limits);
|
|
106
109
|
// 応答は 3 つ。stet で黙らせたものは、ここで落とす。
|
|
107
110
|
const applied = applySuppressions(
|
|
@@ -118,6 +121,7 @@ const inspect = async (path: string, config: Config, argv: readonly string[]): P
|
|
|
118
121
|
text,
|
|
119
122
|
rules,
|
|
120
123
|
language,
|
|
124
|
+
genre,
|
|
121
125
|
outcome: { path, findings: split.fresh, notRun: raw.skipped.length },
|
|
122
126
|
perFile: { path, suppressed: applied.suppressed, reasonless: applied.unusedReasonless },
|
|
123
127
|
all: applied.kept.map((finding) => fingerprint(path, finding)),
|
|
@@ -297,6 +301,21 @@ const HANDLERS: Readonly<Record<string, Handler>> = {
|
|
|
297
301
|
relax: (argv) => changeSetting("relaxed", argv[1], flag(argv, "--why")),
|
|
298
302
|
strict: (argv) => changeSetting("strict", argv[1], flag(argv, "--why")),
|
|
299
303
|
off: (argv) => changeSetting("off", argv[1], flag(argv, "--why")),
|
|
304
|
+
feedback: (argv) => {
|
|
305
|
+
const config = readConfig();
|
|
306
|
+
return runFeedback(positional(argv), argv, {
|
|
307
|
+
cwd: process.cwd(),
|
|
308
|
+
ui: hostLanguage(config.language, process.env),
|
|
309
|
+
version: VERSION,
|
|
310
|
+
runtime: `Node ${process.version} · ${process.platform} ${process.arch}`,
|
|
311
|
+
flag,
|
|
312
|
+
settingsOf: (ruleIds) => settingsOf(config, ruleIds),
|
|
313
|
+
check: async (path) => {
|
|
314
|
+
const inspected = await inspect(path, config, [...argv, "--show-baseline"]);
|
|
315
|
+
return { findings: inspected.outcome.findings, rules: inspected.rules, language: inspected.language, genre: inspected.genre };
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
},
|
|
300
319
|
skill: (argv) => runSkill(argv, { cwd: process.cwd(), home: homedir(), ui: hostLanguage(readConfig().language, process.env) }),
|
|
301
320
|
};
|
|
302
321
|
|
package/src/commands/eval.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { evaluate } from "../eval.ts";
|
|
|
9
9
|
import { renderEval } from "../render/eval.ts";
|
|
10
10
|
import { neededBy } from "../run.ts";
|
|
11
11
|
import type { Config } from "../config/load.ts";
|
|
12
|
+
import { profileFor } from "../profile/for-file.ts";
|
|
12
13
|
|
|
13
14
|
export type Context = {
|
|
14
15
|
readonly config: Config;
|
|
@@ -35,7 +36,7 @@ export const runEval = async (targets: readonly string[], argv: readonly string[
|
|
|
35
36
|
const adapter = await loadAdapter(language);
|
|
36
37
|
const { genre } = resolveGenre(path, source, config);
|
|
37
38
|
await adapter.prepare?.(neededBy(loadRules(language), config.rules, config.experimental, genre, language));
|
|
38
|
-
return { doc: buildDocument(path, source, adapter, teamRules(config)), language, genre };
|
|
39
|
+
return { doc: buildDocument(path, source, adapter, teamRules(config), profileFor(config, path, source, language)), language, genre };
|
|
39
40
|
}),
|
|
40
41
|
);
|
|
41
42
|
const language = docs[0]?.language ?? "ja";
|