chaffjs 0.5.0 → 0.6.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/adapter-load.d.ts.map +1 -1
- package/dist/adapter-load.js +18 -2
- package/dist/adapter-load.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/cite.d.ts +16 -0
- package/dist/commands/cite.d.ts.map +1 -0
- package/dist/commands/cite.js +69 -0
- package/dist/commands/cite.js.map +1 -0
- package/dist/commands/tree.d.ts +33 -0
- package/dist/commands/tree.d.ts.map +1 -0
- package/dist/commands/tree.js +76 -0
- package/dist/commands/tree.js.map +1 -0
- package/dist/detectors/index.d.ts.map +1 -1
- package/dist/detectors/index.js +4 -0
- package/dist/detectors/index.js.map +1 -1
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +6 -1
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/structure-tree.d.ts +5 -0
- package/dist/detectors/structure-tree.d.ts.map +1 -0
- package/dist/detectors/structure-tree.js +25 -0
- package/dist/detectors/structure-tree.js.map +1 -0
- package/dist/document.d.ts +9 -0
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +21 -0
- package/dist/document.js.map +1 -1
- package/dist/eval.d.ts.map +1 -1
- package/dist/eval.js +13 -2
- package/dist/eval.js.map +1 -1
- package/dist/plugin.d.ts +71 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/position.d.ts.map +1 -1
- package/dist/position.js +21 -1
- package/dist/position.js.map +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +7 -2
- package/dist/run.js.map +1 -1
- package/dist/sentence-shape.d.ts.map +1 -1
- package/dist/sentence-shape.js +18 -1
- package/dist/sentence-shape.js.map +1 -1
- package/dist/structure/build.d.ts +20 -0
- package/dist/structure/build.d.ts.map +1 -0
- package/dist/structure/build.js +162 -0
- package/dist/structure/build.js.map +1 -0
- package/dist/structure/cite.d.ts +21 -0
- package/dist/structure/cite.d.ts.map +1 -0
- package/dist/structure/cite.js +91 -0
- package/dist/structure/cite.js.map +1 -0
- package/dist/structure/issues.d.ts +15 -0
- package/dist/structure/issues.d.ts.map +1 -0
- package/dist/structure/issues.js +53 -0
- package/dist/structure/issues.js.map +1 -0
- package/dist/structure/lines.d.ts +15 -0
- package/dist/structure/lines.d.ts.map +1 -0
- package/dist/structure/lines.js +33 -0
- package/dist/structure/lines.js.map +1 -0
- package/dist/structure/markdown-path.d.ts +3 -0
- package/dist/structure/markdown-path.d.ts.map +1 -0
- package/dist/structure/markdown-path.js +5 -0
- package/dist/structure/markdown-path.js.map +1 -0
- package/dist/structure/numbering.d.ts +9 -0
- package/dist/structure/numbering.d.ts.map +1 -0
- package/dist/structure/numbering.js +38 -0
- package/dist/structure/numbering.js.map +1 -0
- package/dist/structure/of.d.ts +13 -0
- package/dist/structure/of.d.ts.map +1 -0
- package/dist/structure/of.js +8 -0
- package/dist/structure/of.js.map +1 -0
- package/dist/structure/sexp.d.ts +7 -0
- package/dist/structure/sexp.d.ts.map +1 -0
- package/dist/structure/sexp.js +25 -0
- package/dist/structure/sexp.js.map +1 -0
- package/dist/structure/universal.d.ts +7 -0
- package/dist/structure/universal.d.ts.map +1 -0
- package/dist/structure/universal.js +21 -0
- package/dist/structure/universal.js.map +1 -0
- package/package.json +3 -3
- package/rules/concrete-evidence-density.yaml +2 -2
- package/rules/dangling-reference.yaml +27 -0
- package/rules/duplicate-definition.yaml +26 -0
- package/rules/numbering-gap.yaml +26 -0
- package/src/adapter-load.ts +19 -2
- package/src/cli.ts +6 -0
- package/src/commands/cite.ts +74 -0
- package/src/commands/tree.ts +94 -0
- package/src/detectors/index.ts +4 -0
- package/src/detectors/signals.ts +6 -1
- package/src/detectors/structure-tree.ts +32 -0
- package/src/document.ts +26 -2
- package/src/eval.ts +11 -2
- package/src/plugin.ts +75 -0
- package/src/position.ts +21 -1
- package/src/run.ts +7 -2
- package/src/sentence-shape.ts +19 -1
- package/src/structure/build.ts +203 -0
- package/src/structure/cite.ts +115 -0
- package/src/structure/issues.ts +63 -0
- package/src/structure/lines.ts +32 -0
- package/src/structure/markdown-path.ts +6 -0
- package/src/structure/numbering.ts +44 -0
- package/src/structure/of.ts +15 -0
- package/src/structure/sexp.ts +28 -0
- package/src/structure/universal.ts +21 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { StructureNode } from "../plugin.ts";
|
|
2
|
+
export type Citation = {
|
|
3
|
+
readonly address: string;
|
|
4
|
+
readonly quote: string;
|
|
5
|
+
};
|
|
6
|
+
export type CitationStatus = "ok" | "missing-address" | "quote-elsewhere" | "quote-not-found";
|
|
7
|
+
export type CitationResult = {
|
|
8
|
+
readonly citation: Citation;
|
|
9
|
+
readonly status: CitationStatus;
|
|
10
|
+
/** 引用文が原文で見つかった位置の、いちばん内側の番地。quote-elsewhere のとき、本当はどこに書いてあるか。 */
|
|
11
|
+
readonly foundAt?: string;
|
|
12
|
+
/** 引用文が見つかった行。引用文が空なら、番地の行。 */
|
|
13
|
+
readonly line?: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* 引用を一件ずつ確かめる。source は木を作った原文そのもの。
|
|
17
|
+
* 引用文が空(空白だけ)なら番地だけを確かめる。同じ番地が二つある(附則が第1条から振り直す)ときは、どちらかにあれば一致。
|
|
18
|
+
* 原文は一度だけ揃え、引用ごとには番地の範囲を揃え直さない。長い契約書に引用が何百とあっても、引用ごとの代金は原文の長さに比例するだけ。
|
|
19
|
+
*/
|
|
20
|
+
export declare const checkCitations: (source: string, tree: StructureNode, citations: readonly Citation[]) => CitationResult[];
|
|
21
|
+
//# sourceMappingURL=cite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cite.d.ts","sourceRoot":"","sources":["../../src/structure/cite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAMlD,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5E,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE9F,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,kEAAkE;IAClE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAqEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,EAAE,MAAM,aAAa,EAAE,WAAW,SAAS,QAAQ,EAAE,KAAG,cAAc,EAuBlH,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { lineStarts, placeOf } from "../position.js";
|
|
2
|
+
const WHITESPACE = /^\s+$/u;
|
|
3
|
+
const GRAPHEMES = new Intl.Segmenter("und", { granularity: "grapheme" });
|
|
4
|
+
/**
|
|
5
|
+
* 書記素(見た目の一文字)ごとに NFKC をかける。1 符号単位ずつでは「ガ」と「ガ」、「ハ」+濁点と「バ」が揃わない。
|
|
6
|
+
* NFKC は 1 文字を複数にすることがある(「㈱」→「(株)」)。どれも元の書記素の先頭を指す。
|
|
7
|
+
*/
|
|
8
|
+
const normalize = (source) => {
|
|
9
|
+
const text = [];
|
|
10
|
+
const index = [];
|
|
11
|
+
[...GRAPHEMES.segment(source)].forEach(({ segment, index: at }) => {
|
|
12
|
+
if (WHITESPACE.test(segment))
|
|
13
|
+
return;
|
|
14
|
+
// 位置の表は UTF-16 の単位で持つ。検索(indexOf)がその単位で数えるので、絵文字のような 2 単位の文字でもずれない。
|
|
15
|
+
const normalized = segment.normalize("NFKC");
|
|
16
|
+
text.push(normalized);
|
|
17
|
+
index.push(...Array.from({ length: normalized.length }, () => at));
|
|
18
|
+
});
|
|
19
|
+
return { text: text.join(""), index };
|
|
20
|
+
};
|
|
21
|
+
const within = (node, occurrence) => node.span.start <= occurrence.start && occurrence.last < node.span.end;
|
|
22
|
+
/**
|
|
23
|
+
* key が現れる位置を上から順に見て、候補の番地に収まるものが見つかった時点で止める。見つからなければ最初の位置を返す。
|
|
24
|
+
* 全部を配列に溜めない。「の」のような短い引用が長い原文に何百万回現れても、覚えるのは二つだけ。
|
|
25
|
+
* 次は 1 文字先から探す。重なって現れる引用(「ああ」の中の「ああ」)も、どの位置も見落とさない。
|
|
26
|
+
*/
|
|
27
|
+
const locate = (whole, key, candidates) => {
|
|
28
|
+
// 空の key は indexOf がどこまでも位置を返し、終わらなくなる。
|
|
29
|
+
if (key === "")
|
|
30
|
+
return {};
|
|
31
|
+
let earliest;
|
|
32
|
+
for (let at = whole.text.indexOf(key); at !== -1; at = whole.text.indexOf(key, at + 1)) {
|
|
33
|
+
const occurrence = { start: whole.index[at] ?? 0, last: whole.index[at + key.length - 1] ?? 0 };
|
|
34
|
+
earliest ??= occurrence;
|
|
35
|
+
if (candidates.some((node) => within(node, occurrence)))
|
|
36
|
+
return { holding: occurrence, earliest };
|
|
37
|
+
}
|
|
38
|
+
return earliest === undefined ? {} : { earliest };
|
|
39
|
+
};
|
|
40
|
+
/** 番地を持つ節点と、その深さ。深いほど内側。 */
|
|
41
|
+
const addressedNodes = (tree) => {
|
|
42
|
+
const found = [];
|
|
43
|
+
const pending = [{ node: tree, depth: 0 }];
|
|
44
|
+
while (pending.length > 0) {
|
|
45
|
+
const current = pending.pop();
|
|
46
|
+
if (current === undefined)
|
|
47
|
+
break;
|
|
48
|
+
if (current.node.address !== "")
|
|
49
|
+
found.push(current);
|
|
50
|
+
[...current.node.children].reverse().forEach((child) => pending.push({ node: child, depth: current.depth + 1 }));
|
|
51
|
+
}
|
|
52
|
+
return found;
|
|
53
|
+
};
|
|
54
|
+
/** 引用の全体を含む、いちばん内側の番地。二つの項にまたがる引用なら、両方を含む条。どの番地にも入らなければ undefined。 */
|
|
55
|
+
const innermostHolding = (nodes, occurrence) => nodes
|
|
56
|
+
.filter(({ node }) => within(node, occurrence))
|
|
57
|
+
.reduce((best, current) => (best === undefined || current.depth > best.depth ? current : best), undefined)?.node.address;
|
|
58
|
+
/**
|
|
59
|
+
* 引用を一件ずつ確かめる。source は木を作った原文そのもの。
|
|
60
|
+
* 引用文が空(空白だけ)なら番地だけを確かめる。同じ番地が二つある(附則が第1条から振り直す)ときは、どちらかにあれば一致。
|
|
61
|
+
* 原文は一度だけ揃え、引用ごとには番地の範囲を揃え直さない。長い契約書に引用が何百とあっても、引用ごとの代金は原文の長さに比例するだけ。
|
|
62
|
+
*/
|
|
63
|
+
export const checkCitations = (source, tree, citations) => {
|
|
64
|
+
const nodes = addressedNodes(tree);
|
|
65
|
+
const byAddress = new Map();
|
|
66
|
+
nodes.forEach(({ node }) => {
|
|
67
|
+
const same = byAddress.get(node.address) ?? [];
|
|
68
|
+
same.push(node);
|
|
69
|
+
byAddress.set(node.address, same);
|
|
70
|
+
});
|
|
71
|
+
const whole = normalize(source);
|
|
72
|
+
const starts = lineStarts(source);
|
|
73
|
+
return citations.map((citation) => {
|
|
74
|
+
const candidates = byAddress.get(citation.address) ?? [];
|
|
75
|
+
const first = candidates[0];
|
|
76
|
+
if (first === undefined)
|
|
77
|
+
return { citation, status: "missing-address" };
|
|
78
|
+
const key = normalize(citation.quote).text;
|
|
79
|
+
if (key === "")
|
|
80
|
+
return { citation, status: "ok", line: first.line };
|
|
81
|
+
const { holding, earliest } = locate(whole, key, candidates);
|
|
82
|
+
if (holding !== undefined)
|
|
83
|
+
return { citation, status: "ok", line: placeOf(starts, holding.start).line };
|
|
84
|
+
if (earliest === undefined)
|
|
85
|
+
return { citation, status: "quote-not-found" };
|
|
86
|
+
const foundAt = innermostHolding(nodes, earliest);
|
|
87
|
+
const line = placeOf(starts, earliest.start).line;
|
|
88
|
+
return { citation, status: "quote-elsewhere", line, ...(foundAt === undefined ? {} : { foundAt }) };
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=cite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cite.js","sourceRoot":"","sources":["../../src/structure/cite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StructureNode } from "../plugin.ts";
|
|
2
|
+
export type StructureIssue = {
|
|
3
|
+
readonly offset: number;
|
|
4
|
+
readonly values: Readonly<Record<string, string | number>>;
|
|
5
|
+
};
|
|
6
|
+
/** 木を上から順に平らにする。文書の中での順番と同じになる。再帰にしないのは、深い木でスタックを使い切らないため。 */
|
|
7
|
+
export declare const inDocumentOrder: (tree: StructureNode) => StructureNode[];
|
|
8
|
+
/**
|
|
9
|
+
* 参照の番地が木に無い。他の文書の名前が付いた参照(民法第709条、Section 9 of the Master Agreement)は引かない。
|
|
10
|
+
* 番号付きのまとまりを 1 つも持たない文書も見ない。他の文書を指しているだけかもしれない。
|
|
11
|
+
*/
|
|
12
|
+
export declare const danglingReferences: (tree: StructureNode) => StructureIssue[];
|
|
13
|
+
/** 同じ語の二度目以降の定義。どちらが正しいかは決めず、両方の場所を示す。 */
|
|
14
|
+
export declare const duplicateDefinitions: (tree: StructureNode) => StructureIssue[];
|
|
15
|
+
//# sourceMappingURL=issues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/structure/issues.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKlD,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAA;CAAE,CAAC;AAIrH,8DAA8D;AAC9D,eAAO,MAAM,eAAe,GAAI,MAAM,aAAa,KAAG,aAAa,EAUlE,CAAC;AAcF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAAI,MAAM,aAAa,KAAG,cAAc,EAQtE,CAAC;AAEF,0CAA0C;AAC1C,eAAO,MAAM,oBAAoB,GAAI,MAAM,aAAa,KAAG,cAAc,EAaxE,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const NUMBERED = ["chapter", "article", "item"];
|
|
2
|
+
/** 木を上から順に平らにする。文書の中での順番と同じになる。再帰にしないのは、深い木でスタックを使い切らないため。 */
|
|
3
|
+
export const inDocumentOrder = (tree) => {
|
|
4
|
+
const order = [];
|
|
5
|
+
const pending = [tree];
|
|
6
|
+
while (pending.length > 0) {
|
|
7
|
+
const node = pending.pop();
|
|
8
|
+
if (node === undefined)
|
|
9
|
+
break;
|
|
10
|
+
order.push(node);
|
|
11
|
+
pending.push(...[...node.children].reverse());
|
|
12
|
+
}
|
|
13
|
+
return order;
|
|
14
|
+
};
|
|
15
|
+
const textOf = (node, key) => {
|
|
16
|
+
const value = node.attrs[key];
|
|
17
|
+
return value === undefined ? "" : String(value);
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* 参照がこの文書のどこかを指しているか。fallback は言語パッケージが付ける別の行き先で、
|
|
21
|
+
* 日本語の「第4条第1項」は、番号の無い第 1 項を持つ第4条を指しうる。
|
|
22
|
+
*/
|
|
23
|
+
const resolves = (node, addresses) => addresses.has(textOf(node, "target")) || (node.attrs["fallback"] !== undefined && addresses.has(textOf(node, "fallback")));
|
|
24
|
+
/**
|
|
25
|
+
* 参照の番地が木に無い。他の文書の名前が付いた参照(民法第709条、Section 9 of the Master Agreement)は引かない。
|
|
26
|
+
* 番号付きのまとまりを 1 つも持たない文書も見ない。他の文書を指しているだけかもしれない。
|
|
27
|
+
*/
|
|
28
|
+
export const danglingReferences = (tree) => {
|
|
29
|
+
const nodes = inDocumentOrder(tree);
|
|
30
|
+
const addresses = new Set(nodes.filter((node) => NUMBERED.includes(node.kind)).map((node) => node.address));
|
|
31
|
+
if (addresses.size === 0)
|
|
32
|
+
return [];
|
|
33
|
+
return nodes
|
|
34
|
+
.filter((node) => node.kind === "reference" && node.attrs["document"] === undefined)
|
|
35
|
+
.filter((node) => !resolves(node, addresses))
|
|
36
|
+
.map((node) => ({ offset: node.span.start, values: { label: textOf(node, "label"), target: textOf(node, "target") } }));
|
|
37
|
+
};
|
|
38
|
+
/** 同じ語の二度目以降の定義。どちらが正しいかは決めず、両方の場所を示す。 */
|
|
39
|
+
export const duplicateDefinitions = (tree) => {
|
|
40
|
+
const first = new Map();
|
|
41
|
+
return inDocumentOrder(tree)
|
|
42
|
+
.filter((node) => node.kind === "definition")
|
|
43
|
+
.flatMap((node) => {
|
|
44
|
+
const term = textOf(node, "term");
|
|
45
|
+
const earlier = first.get(term);
|
|
46
|
+
if (earlier === undefined) {
|
|
47
|
+
first.set(term, node);
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
return [{ offset: node.span.start, values: { term, first: earlier.line } }];
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=issues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/structure/issues.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** 1 行。text は改行を含まず、\r\n の \r も落としてある。start は元の文書での位置。 */
|
|
2
|
+
export type Line = {
|
|
3
|
+
readonly text: string;
|
|
4
|
+
readonly start: number;
|
|
5
|
+
readonly number: number;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* 行に分ける。位置は元の文字列のまま数える。
|
|
9
|
+
* Windows で書かれた契約書は \r\n で届くので、\r を本文に残すと行末の判定がずれる。
|
|
10
|
+
* 行ごとに配列を作り直さない。何万行もある契約書で二乗に遅くなるため。
|
|
11
|
+
*/
|
|
12
|
+
export declare const linesOf: (source: string) => Line[];
|
|
13
|
+
/** offset を含む行の番号(1 始まり)。lines は start の昇順。二分探索で、行数に対して対数で引く。 */
|
|
14
|
+
export declare const lineNumberAt: (lines: readonly Line[], offset: number) => number | undefined;
|
|
15
|
+
//# sourceMappingURL=lines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.d.ts","sourceRoot":"","sources":["../../src/structure/lines.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,MAAM,MAAM,IAAI,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9F;;;;GAIG;AACH,eAAO,MAAM,OAAO,GAAI,QAAQ,MAAM,KAAG,IAAI,EAQ5C,CAAC;AAEF,iEAAiE;AACjE,eAAO,MAAM,YAAY,GAAI,OAAO,SAAS,IAAI,EAAE,EAAE,QAAQ,MAAM,KAAG,MAAM,GAAG,SAY9E,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 行に分ける。位置は元の文字列のまま数える。
|
|
3
|
+
* Windows で書かれた契約書は \r\n で届くので、\r を本文に残すと行末の判定がずれる。
|
|
4
|
+
* 行ごとに配列を作り直さない。何万行もある契約書で二乗に遅くなるため。
|
|
5
|
+
*/
|
|
6
|
+
export const linesOf = (source) => {
|
|
7
|
+
const lines = [];
|
|
8
|
+
let at = 0;
|
|
9
|
+
source.split("\n").forEach((raw, index) => {
|
|
10
|
+
lines.push({ text: raw.endsWith("\r") ? raw.slice(0, -1) : raw, start: at, number: index + 1 });
|
|
11
|
+
at += raw.length + 1;
|
|
12
|
+
});
|
|
13
|
+
return lines;
|
|
14
|
+
};
|
|
15
|
+
/** offset を含む行の番号(1 始まり)。lines は start の昇順。二分探索で、行数に対して対数で引く。 */
|
|
16
|
+
export const lineNumberAt = (lines, offset) => {
|
|
17
|
+
let low = 0;
|
|
18
|
+
let high = lines.length - 1;
|
|
19
|
+
while (low <= high) {
|
|
20
|
+
const middle = (low + high) >> 1;
|
|
21
|
+
const line = lines[middle];
|
|
22
|
+
if (line === undefined)
|
|
23
|
+
return undefined;
|
|
24
|
+
if (offset < line.start)
|
|
25
|
+
high = middle - 1;
|
|
26
|
+
else if (offset > line.start + line.text.length)
|
|
27
|
+
low = middle + 1;
|
|
28
|
+
else
|
|
29
|
+
return line.number;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=lines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lines.js","sourceRoot":"","sources":["../../src/structure/lines.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAU,EAAE;IAChD,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACxC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;QAChG,EAAE,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAsB,EAAE,MAAc,EAAsB,EAAE;IACzF,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5B,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACzC,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK;YAAE,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC;aACtC,IAAI,MAAM,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,GAAG,GAAG,MAAM,GAAG,CAAC,CAAC;;YAC7D,OAAO,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-path.d.ts","sourceRoot":"","sources":["../../src/structure/markdown-path.ts"],"names":[],"mappings":"AAIA,0DAA0D;AAC1D,eAAO,MAAM,cAAc,GAAI,MAAM,MAAM,KAAG,OAAyD,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { extname } from "node:path";
|
|
2
|
+
const MARKDOWN = [".md", ".markdown", ".mdx"];
|
|
3
|
+
/** 見出しとコードの範囲を Markdown として読むか。.txt の契約書は行頭の番号だけで木にする。 */
|
|
4
|
+
export const isMarkdownPath = (path) => MARKDOWN.includes(extname(path).toLowerCase());
|
|
5
|
+
//# sourceMappingURL=markdown-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-path.js","sourceRoot":"","sources":["../../src/structure/markdown-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;AAE9C,0DAA0D;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { StructureNode } from "../plugin.ts";
|
|
2
|
+
import { type StructureIssue } from "./issues.ts";
|
|
3
|
+
/**
|
|
4
|
+
* 番号の抜けと重なり。比べるのは同じ親の子どうしだけ。英米の法令は章ごとに Section 101、201 と百の位を変えるので、
|
|
5
|
+
* 文書全体の通し番号として比べると抜けに見える。最初の番号は見ない。日本語の項は 2 から番号を振る。
|
|
6
|
+
* 1 に戻った番号は新しい並びの始まりとして扱うので、「(a) の後の (a)」の重なりは見逃す。
|
|
7
|
+
*/
|
|
8
|
+
export declare const numberingBreaks: (tree: StructureNode) => StructureIssue[];
|
|
9
|
+
//# sourceMappingURL=numbering.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"numbering.d.ts","sourceRoot":"","sources":["../../src/structure/numbering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAiCnE;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,aAAa,KAAG,cAAc,EAId,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { inDocumentOrder } from "./issues.js";
|
|
2
|
+
const labelOf = (node) => String(node.attrs["label"] ?? node.address);
|
|
3
|
+
/** 同じ親の子のうち、番号の付いたものを種類ごとに分ける。条と項は別の並び。 */
|
|
4
|
+
const sequencesOf = (parent) => {
|
|
5
|
+
const groups = new Map();
|
|
6
|
+
parent.children.forEach((node) => {
|
|
7
|
+
if (node.ordinal === undefined)
|
|
8
|
+
return;
|
|
9
|
+
// 配列を作り直さずに足す。条が何千もある法令で二乗にしない。
|
|
10
|
+
const group = groups.get(node.kind) ?? [];
|
|
11
|
+
group.push({ node, ordinal: node.ordinal });
|
|
12
|
+
groups.set(node.kind, group);
|
|
13
|
+
});
|
|
14
|
+
return [...groups.values()];
|
|
15
|
+
};
|
|
16
|
+
/** 隣り合う二つの番号が、1 つ進んでいなければ指摘する。同じ番号なら重なり、飛べば抜け。 */
|
|
17
|
+
const breaksIn = (sequence) => sequence.flatMap((current, index) => {
|
|
18
|
+
const previous = sequence[index - 1];
|
|
19
|
+
// 1 に戻ったら新しい並び。一つの条に (a)(b) の箇条書きが二つある、附則が第1条から振り直す、のどちらも誤りではない。
|
|
20
|
+
if (previous === undefined || current.ordinal === previous.ordinal + 1 || current.ordinal === 1)
|
|
21
|
+
return [];
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
offset: current.node.span.start,
|
|
25
|
+
values: { previous: labelOf(previous.node), label: labelOf(current.node), expected: previous.ordinal + 1, found: current.ordinal },
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* 番号の抜けと重なり。比べるのは同じ親の子どうしだけ。英米の法令は章ごとに Section 101、201 と百の位を変えるので、
|
|
31
|
+
* 文書全体の通し番号として比べると抜けに見える。最初の番号は見ない。日本語の項は 2 から番号を振る。
|
|
32
|
+
* 1 に戻った番号は新しい並びの始まりとして扱うので、「(a) の後の (a)」の重なりは見逃す。
|
|
33
|
+
*/
|
|
34
|
+
export const numberingBreaks = (tree) => inDocumentOrder(tree)
|
|
35
|
+
.flatMap(sequencesOf)
|
|
36
|
+
.flatMap(breaksIn)
|
|
37
|
+
.sort((left, right) => left.offset - right.offset);
|
|
38
|
+
//# sourceMappingURL=numbering.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"numbering.js","sourceRoot":"","sources":["../../src/structure/numbering.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAuB,MAAM,aAAa,CAAC;AAEnE,MAAM,OAAO,GAAG,CAAC,IAAmB,EAAU,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;AAI7F,2CAA2C;AAC3C,MAAM,WAAW,GAAG,CAAC,MAAqB,EAAe,EAAE;IACzD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC5C,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QAC/B,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO;QACvC,gCAAgC;QAChC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEF,kDAAkD;AAClD,MAAM,QAAQ,GAAG,CAAC,QAA4B,EAAoB,EAAE,CAClE,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE;IAClC,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACrC,iEAAiE;IACjE,IAAI,QAAQ,KAAK,SAAS,IAAI,OAAO,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO,GAAG,CAAC,IAAI,OAAO,CAAC,OAAO,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3G,OAAO;QACL;YACE,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;YAC/B,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,OAAO,GAAG,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE;SACnI;KACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEL;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAmB,EAAoB,EAAE,CACvE,eAAe,CAAC,IAAI,CAAC;KAClB,OAAO,CAAC,WAAW,CAAC;KACpB,OAAO,CAAC,QAAQ,CAAC;KACjB,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { StructureNode, StructurePatterns } from "../plugin.ts";
|
|
2
|
+
export type SourceInput = {
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly source: string;
|
|
5
|
+
readonly language: string;
|
|
6
|
+
readonly markdown: boolean;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* 文字列から木を作る。Markdown なら見出しとコードの範囲を先に取る。
|
|
10
|
+
* lint は文書モデルを作るときの解析を使い回すので、ここを通らずに buildTree を呼ぶ。
|
|
11
|
+
*/
|
|
12
|
+
export declare const buildStructure: (input: SourceInput, patterns: StructurePatterns) => StructureNode;
|
|
13
|
+
//# sourceMappingURL=of.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"of.d.ts","sourceRoot":"","sources":["../../src/structure/of.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGrE,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpI;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,WAAW,EAAE,UAAU,iBAAiB,KAAG,aAI9E,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { markdownOutline } from "../document.js";
|
|
2
|
+
import { buildTree, NO_OUTLINE } from "./build.js";
|
|
3
|
+
/**
|
|
4
|
+
* 文字列から木を作る。Markdown なら見出しとコードの範囲を先に取る。
|
|
5
|
+
* lint は文書モデルを作るときの解析を使い回すので、ここを通らずに buildTree を呼ぶ。
|
|
6
|
+
*/
|
|
7
|
+
export const buildStructure = (input, patterns) => buildTree({ path: input.path, source: input.source, language: input.language, outline: input.markdown ? markdownOutline(input.source) : NO_OUTLINE }, patterns);
|
|
8
|
+
//# sourceMappingURL=of.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"of.js","sourceRoot":"","sources":["../../src/structure/of.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAInD;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAkB,EAAE,QAA2B,EAAiB,EAAE,CAC/F,SAAS,CACP,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,EAC1I,QAAQ,CACT,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { StructureNode } from "../plugin.ts";
|
|
2
|
+
/**
|
|
3
|
+
* 木を S 式にする。人と AI が読むための形で、JSON と同じ木から作る。
|
|
4
|
+
* `(kind "番地" :key value ... 子)`。番地を持たない葉は番地を書かない。
|
|
5
|
+
*/
|
|
6
|
+
export declare const toSexp: (node: StructureNode, indent?: string) => string;
|
|
7
|
+
//# sourceMappingURL=sexp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sexp.d.ts","sourceRoot":"","sources":["../../src/structure/sexp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAkBlD;;;GAGG;AACH,eAAO,MAAM,MAAM,GAAI,MAAM,aAAa,EAAE,eAAW,KAAG,MAKzD,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** 文字列は二重引用符で囲み、中の \ と " だけを逃がす。改行は \n にして 1 行に保つ。 */
|
|
2
|
+
const quote = (text) => `"${text.replace(/\\/gu, "\\\\").replace(/"/gu, '\\"').replace(/\r?\n/gu, "\\n")}"`;
|
|
3
|
+
const atom = (value) => (typeof value === "number" ? String(value) : quote(value));
|
|
4
|
+
/** 属性はキーの順に並べる。同じ木から毎回同じ文字列を出すため。 */
|
|
5
|
+
const keywords = (node) => [
|
|
6
|
+
...Object.keys(node.attrs)
|
|
7
|
+
.sort((left, right) => left.localeCompare(right, "en"))
|
|
8
|
+
.flatMap((key) => {
|
|
9
|
+
const value = node.attrs[key];
|
|
10
|
+
return value === undefined ? [] : [`:${key} ${atom(value)}`];
|
|
11
|
+
}),
|
|
12
|
+
`:line ${String(node.line)}`,
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* 木を S 式にする。人と AI が読むための形で、JSON と同じ木から作る。
|
|
16
|
+
* `(kind "番地" :key value ... 子)`。番地を持たない葉は番地を書かない。
|
|
17
|
+
*/
|
|
18
|
+
export const toSexp = (node, indent = "") => {
|
|
19
|
+
const head = [node.kind, ...(node.address === "" ? [] : [quote(node.address)]), ...keywords(node)].join(" ");
|
|
20
|
+
if (node.children.length === 0)
|
|
21
|
+
return `${indent}(${head})`;
|
|
22
|
+
const inner = node.children.map((child) => toSexp(child, `${indent} `)).join("\n");
|
|
23
|
+
return `${indent}(${head}\n${inner})`;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=sexp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sexp.js","sourceRoot":"","sources":["../../src/structure/sexp.ts"],"names":[],"mappings":"AAEA,sDAAsD;AACtD,MAAM,KAAK,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC;AAE5H,MAAM,IAAI,GAAG,CAAC,KAAsB,EAAU,EAAE,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;AAE5G,qCAAqC;AACrC,MAAM,QAAQ,GAAG,CAAC,IAAmB,EAAY,EAAE,CAAC;IAClD,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;SACvB,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;SACtD,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC;IACJ,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;CAC7B,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAmB,EAAE,MAAM,GAAG,EAAE,EAAU,EAAE;IACjE,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC7G,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,MAAM,IAAI,IAAI,GAAG,CAAC;IAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpF,OAAO,GAAG,MAAM,IAAI,IAAI,KAAK,KAAK,GAAG,CAAC;AACxC,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NumberedLine, NumberingContext } from "../plugin.ts";
|
|
2
|
+
/**
|
|
3
|
+
* 本文の「1. 」は箇条書きで、見出しの「1. 」は章番号。点を含まない番号は、見出しの行でだけ読む。
|
|
4
|
+
* 「4.2 」のように点を含むものは、.txt の仕様書でも見出しとして書かれるので本文でも読む。
|
|
5
|
+
*/
|
|
6
|
+
export declare const dottedNumber: (line: string, context: NumberingContext) => NumberedLine | undefined;
|
|
7
|
+
//# sourceMappingURL=universal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"universal.d.ts","sourceRoot":"","sources":["../../src/structure/universal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAQnE;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,SAAS,gBAAgB,KAAG,YAAY,GAAG,SAQrF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「4.2 設定」「3.1.4 Scope」のような通し番号。数字と点だけで書くので言語を問わない。
|
|
3
|
+
* 各部分を 3 桁・深さを 6 までに抑え、後戻りが爆発しない形にしてある。
|
|
4
|
+
*/
|
|
5
|
+
const DOTTED = /^[ \t]{0,3}(?<number>\d{1,3}(?:\.\d{1,3}){0,5})\.?[ \t\u3000]+(?<rest>\S.*)$/u;
|
|
6
|
+
/**
|
|
7
|
+
* 本文の「1. 」は箇条書きで、見出しの「1. 」は章番号。点を含まない番号は、見出しの行でだけ読む。
|
|
8
|
+
* 「4.2 」のように点を含むものは、.txt の仕様書でも見出しとして書かれるので本文でも読む。
|
|
9
|
+
*/
|
|
10
|
+
export const dottedNumber = (line, context) => {
|
|
11
|
+
const groups = DOTTED.exec(line)?.groups;
|
|
12
|
+
const number = groups?.["number"];
|
|
13
|
+
if (number === undefined)
|
|
14
|
+
return undefined;
|
|
15
|
+
const depth = number.split(".").length;
|
|
16
|
+
if (depth < 2 && !context.isHeading)
|
|
17
|
+
return undefined;
|
|
18
|
+
const rest = groups?.["rest"]?.trim() ?? "";
|
|
19
|
+
return { kind: "article", depth, number, absolute: true, label: number, heading: rest, rest, ordinal: Number(number.split(".").at(-1)) };
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=universal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"universal.js","sourceRoot":"","sources":["../../src/structure/universal.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,MAAM,GAAG,+EAA+E,CAAC;AAE/F;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,OAAyB,EAA4B,EAAE;IAChG,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC;IAClC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACtD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC5C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC3I,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chaffjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@anthropic-ai/sdk": "^0.125.0",
|
|
55
|
-
"@chaffjs/lang-en": "0.
|
|
56
|
-
"@chaffjs/lang-ja": "0.
|
|
55
|
+
"@chaffjs/lang-en": "0.6.0",
|
|
56
|
+
"@chaffjs/lang-ja": "0.6.0",
|
|
57
57
|
"mdast-util-from-markdown": "^2.0.3",
|
|
58
58
|
"mdast-util-frontmatter": "^2.0.1",
|
|
59
59
|
"mdast-util-gfm-table": "^2.0.0",
|
|
@@ -9,7 +9,7 @@ name:
|
|
|
9
9
|
en: Section with nothing concrete
|
|
10
10
|
|
|
11
11
|
why:
|
|
12
|
-
ja:
|
|
12
|
+
ja: 数値もコードもリンクも無い節は、読み終えても持ち帰るものがありません。抽象的な説明だけが残ります。仕様書では「error とは何か」のような定義の節が普通にあるので、technical では動かしません。
|
|
13
13
|
en: A section with no number, no code and no link leaves the reader with nothing to take away.
|
|
14
14
|
|
|
15
15
|
message:
|
|
@@ -22,4 +22,4 @@ how_to_fix:
|
|
|
22
22
|
|
|
23
23
|
levels: { strict: 1, normal: 3, relaxed: 6 }
|
|
24
24
|
|
|
25
|
-
use_for: [blog, business
|
|
25
|
+
use_for: [blog, business]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
id: dangling-reference
|
|
2
|
+
layer: L3
|
|
3
|
+
status: experimental
|
|
4
|
+
how_to_find: dangling-reference
|
|
5
|
+
requires: [structure]
|
|
6
|
+
severity: error
|
|
7
|
+
|
|
8
|
+
name:
|
|
9
|
+
ja: 参照先が無い
|
|
10
|
+
en: Reference to a missing provision
|
|
11
|
+
|
|
12
|
+
why:
|
|
13
|
+
ja: 「第12条に定める」のような参照は、その条が文書に無ければ読み手を行き止まりにします。条を消したり番号を振り直したりしたときに、参照だけが古い番号のまま残ることがよくあります。chaff は文書を番地の付いた木にして(chaff tree)、参照の番地が木にあるかを見ます。
|
|
14
|
+
en: A reference such as "as set out in Section 12" leaves the reader at a dead end when that section is not in the document. It usually happens when a provision is deleted or renumbered and the reference keeps the old number. chaff builds the document's tree of addresses (chaff tree) and checks that each reference's address is in it.
|
|
15
|
+
|
|
16
|
+
message:
|
|
17
|
+
ja: 「{label}」(番地 {target})はこの文書にありません
|
|
18
|
+
en: '"{label}" (address {target}) is not in this document'
|
|
19
|
+
|
|
20
|
+
how_to_fix:
|
|
21
|
+
ja: 正しい番号に直すか、参照を消してください。他の文書を指しているなら、「民法第3条」のように文書名を添えると読み手に伝わります。
|
|
22
|
+
en: Fix the number or remove the reference. If it points into another document, name that document so the reader knows where to look.
|
|
23
|
+
|
|
24
|
+
# 何件あれば指摘するか。1 は「1 件でもあれば」。
|
|
25
|
+
levels: { strict: 1, normal: 1, relaxed: 1 }
|
|
26
|
+
|
|
27
|
+
use_for: [business, technical, blog]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
id: duplicate-definition
|
|
2
|
+
layer: L3
|
|
3
|
+
status: experimental
|
|
4
|
+
how_to_find: duplicate-definition
|
|
5
|
+
requires: [structure]
|
|
6
|
+
severity: warning
|
|
7
|
+
|
|
8
|
+
name:
|
|
9
|
+
ja: 同じ語の二重定義
|
|
10
|
+
en: Term defined twice
|
|
11
|
+
|
|
12
|
+
why:
|
|
13
|
+
ja: 同じ語を二か所で定義すると、二つの定義が食い違っていないかを読み手が確かめなければなりません。長い契約書では、後から足した定義が先の定義と少しずれることがよくあります。中身が食い違っているかは機械では決まらないので、chaff は二度目の定義の場所だけを示します。
|
|
14
|
+
en: A term defined in two places makes the reader check whether the two definitions agree. In long contracts a definition added later often drifts from the first. Whether they conflict is not something a machine can decide, so chaff only points at the second one.
|
|
15
|
+
|
|
16
|
+
message:
|
|
17
|
+
ja: 「{term}」は {first} 行目でも定義されています
|
|
18
|
+
en: '"{term}" is also defined on line {first}'
|
|
19
|
+
|
|
20
|
+
how_to_fix:
|
|
21
|
+
ja: 定義を一か所にまとめ、もう一方は「第2条に定める{term}」のように参照にしてください。意図して意味を変えているなら、別の語にします。
|
|
22
|
+
en: Keep one definition and refer to it from the other place. If the meaning changes on purpose, use a different term.
|
|
23
|
+
|
|
24
|
+
levels: { strict: 1, normal: 1, relaxed: 1 }
|
|
25
|
+
|
|
26
|
+
use_for: [business, technical, blog]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
id: numbering-gap
|
|
2
|
+
layer: L3
|
|
3
|
+
status: experimental
|
|
4
|
+
how_to_find: numbering-gap
|
|
5
|
+
requires: [structure]
|
|
6
|
+
severity: error
|
|
7
|
+
|
|
8
|
+
name:
|
|
9
|
+
ja: 番号の抜け・重なり
|
|
10
|
+
en: Skipped or repeated number
|
|
11
|
+
|
|
12
|
+
why:
|
|
13
|
+
ja: 第3条の次が第5条、(a) の次が (c)、同じ第2項が二つ。番号が飛ぶか重なると、読み手は何かが消えたのか、参照がどちらを指すのかを判断できません。同じ親の中で並ぶ番号だけを比べます。枝番号(第3条の2)は並びの外として扱います。
|
|
14
|
+
en: Article 5 right after Article 3, (c) right after (a), two paragraphs numbered 2. A reader cannot tell whether something was removed, or which one a reference means. Only numbers side by side under the same parent are compared.
|
|
15
|
+
|
|
16
|
+
message:
|
|
17
|
+
ja: 「{previous}」の次が「{label}」です({expected} 番目のはず)
|
|
18
|
+
en: '"{label}" follows "{previous}" (expected number {expected})'
|
|
19
|
+
|
|
20
|
+
how_to_fix:
|
|
21
|
+
ja: 番号を振り直してください。削った条を欠番として残すなら、「第4条(削除)」のように番号だけを残すと読み手に伝わります。
|
|
22
|
+
en: Renumber. If a provision was removed on purpose, keep its number with a note such as "Section 4 [Deleted]".
|
|
23
|
+
|
|
24
|
+
levels: { strict: 1, normal: 1, relaxed: 1 }
|
|
25
|
+
|
|
26
|
+
use_for: [business, technical, blog]
|