chaffjs 0.11.0 → 0.13.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/date-stamp.d.ts +14 -0
- package/dist/date-stamp.d.ts.map +1 -0
- package/dist/date-stamp.js +40 -0
- package/dist/date-stamp.js.map +1 -0
- package/dist/declared-lists.d.ts +4 -0
- package/dist/declared-lists.d.ts.map +1 -0
- package/dist/declared-lists.js +3 -0
- package/dist/declared-lists.js.map +1 -0
- package/dist/detectors/acronym-context.d.ts +25 -0
- package/dist/detectors/acronym-context.d.ts.map +1 -0
- package/dist/detectors/acronym-context.js +28 -0
- package/dist/detectors/acronym-context.js.map +1 -0
- package/dist/detectors/acronym-expansion.d.ts +9 -0
- package/dist/detectors/acronym-expansion.d.ts.map +1 -0
- package/dist/detectors/acronym-expansion.js +94 -0
- package/dist/detectors/acronym-expansion.js.map +1 -0
- package/dist/detectors/char-shape.d.ts.map +1 -1
- package/dist/detectors/char-shape.js +20 -34
- package/dist/detectors/char-shape.js.map +1 -1
- package/dist/detectors/doubled-word.d.ts +27 -0
- package/dist/detectors/doubled-word.d.ts.map +1 -0
- package/dist/detectors/doubled-word.js +94 -0
- package/dist/detectors/doubled-word.js.map +1 -0
- package/dist/detectors/heading-echo.d.ts.map +1 -1
- package/dist/detectors/heading-echo.js +22 -12
- package/dist/detectors/heading-echo.js.map +1 -1
- package/dist/detectors/index.d.ts.map +1 -1
- package/dist/detectors/index.js +2 -0
- package/dist/detectors/index.js.map +1 -1
- package/dist/detectors/lead-in.d.ts +8 -0
- package/dist/detectors/lead-in.d.ts.map +1 -0
- package/dist/detectors/lead-in.js +13 -0
- package/dist/detectors/lead-in.js.map +1 -0
- package/dist/detectors/lexicon-match.d.ts +6 -0
- package/dist/detectors/lexicon-match.d.ts.map +1 -1
- package/dist/detectors/lexicon-match.js +8 -0
- package/dist/detectors/lexicon-match.js.map +1 -1
- package/dist/detectors/lexicon.d.ts +5 -0
- package/dist/detectors/lexicon.d.ts.map +1 -1
- package/dist/detectors/lexicon.js +21 -4
- package/dist/detectors/lexicon.js.map +1 -1
- package/dist/detectors/orthography.d.ts.map +1 -1
- package/dist/detectors/orthography.js +17 -1
- package/dist/detectors/orthography.js.map +1 -1
- package/dist/detectors/place-run.d.ts +8 -0
- package/dist/detectors/place-run.d.ts.map +1 -0
- package/dist/detectors/place-run.js +54 -0
- package/dist/detectors/place-run.js.map +1 -0
- package/dist/detectors/register.d.ts +32 -0
- package/dist/detectors/register.d.ts.map +1 -0
- package/dist/detectors/register.js +62 -0
- package/dist/detectors/register.js.map +1 -0
- package/dist/detectors/sentence-ending.d.ts.map +1 -1
- package/dist/detectors/sentence-ending.js +17 -28
- package/dist/detectors/sentence-ending.js.map +1 -1
- package/dist/detectors/signals.d.ts.map +1 -1
- package/dist/detectors/signals.js +20 -115
- package/dist/detectors/signals.js.map +1 -1
- package/dist/detectors/structure.d.ts.map +1 -1
- package/dist/detectors/structure.js +14 -1
- package/dist/detectors/structure.js.map +1 -1
- package/dist/detectors/superlative-scope.d.ts +16 -0
- package/dist/detectors/superlative-scope.d.ts.map +1 -0
- package/dist/detectors/superlative-scope.js +40 -0
- package/dist/detectors/superlative-scope.js.map +1 -0
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +17 -11
- package/dist/document.js.map +1 -1
- package/dist/eval.d.ts.map +1 -1
- package/dist/eval.js +3 -2
- package/dist/eval.js.map +1 -1
- package/dist/heading-title.d.ts +6 -0
- package/dist/heading-title.d.ts.map +1 -0
- package/dist/heading-title.js +8 -0
- package/dist/heading-title.js.map +1 -0
- package/dist/in-page-nav.d.ts +19 -0
- package/dist/in-page-nav.d.ts.map +1 -0
- package/dist/in-page-nav.js +44 -0
- package/dist/in-page-nav.js.map +1 -0
- package/dist/number-name.d.ts +9 -0
- package/dist/number-name.d.ts.map +1 -0
- package/dist/number-name.js +57 -0
- package/dist/number-name.js.map +1 -0
- package/dist/orthography.d.ts +7 -2
- package/dist/orthography.d.ts.map +1 -1
- package/dist/orthography.js +79 -17
- package/dist/orthography.js.map +1 -1
- package/dist/plugin.d.ts +4 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/rule-load.d.ts.map +1 -1
- package/dist/rule-load.js +1 -0
- package/dist/rule-load.js.map +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +5 -4
- package/dist/run.js.map +1 -1
- package/package.json +3 -3
- package/rules/doubled-word.yaml +27 -0
- package/rules/latin-spacing.yaml +4 -2
- package/rules/max-kanji-continuous.yaml +2 -0
- package/rules/undefined-acronym.yaml +2 -0
- package/rules/unqualified-superlative.yaml +1 -0
- package/src/date-stamp.ts +65 -0
- package/src/declared-lists.ts +5 -0
- package/src/detectors/acronym-context.ts +50 -0
- package/src/detectors/acronym-expansion.ts +109 -0
- package/src/detectors/char-shape.ts +12 -30
- package/src/detectors/doubled-word.ts +128 -0
- package/src/detectors/heading-echo.ts +13 -3
- package/src/detectors/index.ts +2 -0
- package/src/detectors/lead-in.ts +14 -0
- package/src/detectors/lexicon-match.ts +10 -0
- package/src/detectors/lexicon.ts +32 -6
- package/src/detectors/orthography.ts +20 -2
- package/src/detectors/place-run.ts +63 -0
- package/src/detectors/register.ts +83 -0
- package/src/detectors/sentence-ending.ts +24 -28
- package/src/detectors/signals.ts +24 -120
- package/src/detectors/structure.ts +21 -2
- package/src/detectors/superlative-scope.ts +66 -0
- package/src/document.ts +19 -11
- package/src/eval.ts +2 -1
- package/src/heading-title.ts +8 -0
- package/src/in-page-nav.ts +67 -0
- package/src/number-name.ts +68 -0
- package/src/orthography.ts +77 -15
- package/src/plugin.ts +4 -0
- package/src/rule-load.ts +1 -0
- package/src/run.ts +5 -4
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Span } from "./plugin.ts";
|
|
2
|
+
/** 段落 1 つ。dates は段落の中の日付の位置で、段落の先頭から数える。 */
|
|
3
|
+
export type StampCandidate = {
|
|
4
|
+
readonly text: string;
|
|
5
|
+
readonly dates: readonly Span[];
|
|
6
|
+
};
|
|
7
|
+
/** 段落ごとの候補。dates は文書の中の日付の位置で、段落の中にすっかり収まるものだけを段落の先頭からの位置にする。 */
|
|
8
|
+
export declare const stampCandidates: (source: string, paragraphs: readonly Span[], dates: readonly Span[]) => StampCandidate[];
|
|
9
|
+
/**
|
|
10
|
+
* 更新日・公開日の刻印になっている段落の位置。ページの付帯情報で、書いた人が読み手に読ませる前置きではない。
|
|
11
|
+
* ラベルの語は言語パッケージの語彙表(date-stamp-label)から渡す。文の中に日付があるだけの段落は刻印ではない。
|
|
12
|
+
*/
|
|
13
|
+
export declare const dateStampIndexes: (candidates: readonly StampCandidate[], labels: readonly string[]) => ReadonlySet<number>;
|
|
14
|
+
//# sourceMappingURL=date-stamp.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-stamp.d.ts","sourceRoot":"","sources":["../src/date-stamp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,4CAA4C;AAC5C,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAA;CAAE,CAAC;AAExF,iEAAiE;AACjE,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,EAAE,YAAY,SAAS,IAAI,EAAE,EAAE,OAAO,SAAS,IAAI,EAAE,KAAG,cAAc,EAM/G,CAAC;AA2CN;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,YAAY,SAAS,cAAc,EAAE,EAAE,QAAQ,SAAS,MAAM,EAAE,KAAG,WAAW,CAAC,MAAM,CAKnH,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** 段落ごとの候補。dates は文書の中の日付の位置で、段落の中にすっかり収まるものだけを段落の先頭からの位置にする。 */
|
|
2
|
+
export const stampCandidates = (source, paragraphs, dates) => paragraphs.map((paragraph) => ({
|
|
3
|
+
text: source.slice(paragraph.start, paragraph.end),
|
|
4
|
+
dates: dates
|
|
5
|
+
.filter((date) => date.start >= paragraph.start && date.end <= paragraph.end)
|
|
6
|
+
.map((date) => ({ start: date.start - paragraph.start, end: date.end - paragraph.start })),
|
|
7
|
+
}));
|
|
8
|
+
/** 文字か数字。日付を除いてこれが 1 つも残らなければ、日付だけの段落。 */
|
|
9
|
+
const WORD = /[\p{L}\p{N}]/u;
|
|
10
|
+
const ENDS_WITH_COLON = /[::]\s*$/u;
|
|
11
|
+
const LABEL_EDGE = /[\s::]/u;
|
|
12
|
+
/** 幅の無い日付は日付として読まない。段落が日付だけかどうかを、何も覆わない位置で決めない。 */
|
|
13
|
+
const datesOf = (candidate) => candidate.dates.filter((date) => date.end > date.start);
|
|
14
|
+
const withoutDates = (candidate) => {
|
|
15
|
+
const ordered = datesOf(candidate).sort((left, right) => left.start - right.start);
|
|
16
|
+
const gaps = ordered.reduce((acc, date) => ({ parts: [...acc.parts, candidate.text.slice(acc.from, date.start)], from: Math.max(acc.from, date.end) }), { parts: [], from: 0 });
|
|
17
|
+
return [...gaps.parts, candidate.text.slice(gaps.from)].join(" ");
|
|
18
|
+
};
|
|
19
|
+
/** 前後の空白とコロンを外したラベル。「Last updated:」も「:最終更新日」も同じ語として引く。 */
|
|
20
|
+
const bareLabel = (text) => {
|
|
21
|
+
const chars = [...text];
|
|
22
|
+
const first = chars.findIndex((char) => !LABEL_EDGE.test(char));
|
|
23
|
+
const last = chars.findLastIndex((char) => !LABEL_EDGE.test(char));
|
|
24
|
+
return first === -1 ? "" : chars.slice(first, last + 1).join("");
|
|
25
|
+
};
|
|
26
|
+
const isLabel = (text, labels) => {
|
|
27
|
+
const bare = bareLabel(text).toLowerCase();
|
|
28
|
+
return bare !== "" && labels.some((label) => label.toLowerCase() === bare);
|
|
29
|
+
};
|
|
30
|
+
const isDateOnly = (candidate) => candidate !== undefined && datesOf(candidate).length > 0 && !WORD.test(withoutDates(candidate));
|
|
31
|
+
/** 「Updated 2026-03-03」「最終更新日:2025年6月20日」。日付を除くと、語彙表のラベルしか残らない。 */
|
|
32
|
+
const isLabelledDate = (candidate, labels) => datesOf(candidate).length > 0 && isLabel(withoutDates(candidate), labels);
|
|
33
|
+
/** 「最終更新日:」の段落のすぐ後に日付だけの段落。Web ページを写すと、ラベルと日付が別の段落に割れる。 */
|
|
34
|
+
const isLabelBeforeDate = (candidate, next, labels) => ENDS_WITH_COLON.test(candidate.text) && isLabel(candidate.text, labels) && isDateOnly(next);
|
|
35
|
+
/**
|
|
36
|
+
* 更新日・公開日の刻印になっている段落の位置。ページの付帯情報で、書いた人が読み手に読ませる前置きではない。
|
|
37
|
+
* ラベルの語は言語パッケージの語彙表(date-stamp-label)から渡す。文の中に日付があるだけの段落は刻印ではない。
|
|
38
|
+
*/
|
|
39
|
+
export const dateStampIndexes = (candidates, labels) => new Set(candidates.flatMap((candidate, index) => isDateOnly(candidate) || isLabelledDate(candidate, labels) || isLabelBeforeDate(candidate, candidates[index + 1], labels) ? [index] : []));
|
|
40
|
+
//# sourceMappingURL=date-stamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-stamp.js","sourceRoot":"","sources":["../src/date-stamp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Lexicon, RuleDefinition } from "./plugin.ts";
|
|
2
|
+
/** rule が宣言した語彙表のうち、その言語に無い最初のもの。無いまま動かすと、照らす語が無いだけの 0 件や指摘が本物に見える。 */
|
|
3
|
+
export declare const missingList: (rule: RuleDefinition, lexicons: Readonly<Record<string, Lexicon>>) => string | undefined;
|
|
4
|
+
//# sourceMappingURL=declared-lists.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declared-lists.d.ts","sourceRoot":"","sources":["../src/declared-lists.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE3D,uEAAuE;AACvE,eAAO,MAAM,WAAW,GAAI,MAAM,cAAc,EAAE,UAAU,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAG,MAAM,GAAG,SAC2B,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** rule が宣言した語彙表のうち、その言語に無い最初のもの。無いまま動かすと、照らす語が無いだけの 0 件や指摘が本物に見える。 */
|
|
2
|
+
export const missingList = (rule, lexicons) => [...(rule.word_list === undefined ? [] : [rule.word_list]), ...rule.extra_word_lists].find((name) => lexicons[name] === undefined);
|
|
3
|
+
//# sourceMappingURL=declared-lists.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declared-lists.js","sourceRoot":"","sources":["../src/declared-lists.ts"],"names":[],"mappings":"AAEA,uEAAuE;AACvE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAoB,EAAE,QAA2C,EAAsB,EAAE,CACnH,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 大文字の語が略語ではなく、決まった書き方の一部として読める所(3:30 PM、1pm ET、USD 1,000、Kansas City, MO 64108)。
|
|
3
|
+
* どれも閉じた集合で、しかも隣の数字があるときだけ認める。PM(project manager)、CT、CA(certificate authority)は
|
|
4
|
+
* 数字の隣でなければ略語のまま数える。語は言語パッケージの語彙表から読み、書き方の組み立てだけをここに置く。
|
|
5
|
+
*/
|
|
6
|
+
type Span = {
|
|
7
|
+
readonly start: number;
|
|
8
|
+
readonly end: number;
|
|
9
|
+
};
|
|
10
|
+
/** 言語パッケージの語彙表から読む、数字の隣でだけ略語から外す語と、単独で強調として書かれる語。字面どおりに照らす。 */
|
|
11
|
+
export type NotationWords = {
|
|
12
|
+
readonly meridiem: readonly string[];
|
|
13
|
+
readonly timeZones: readonly string[];
|
|
14
|
+
readonly currencies: readonly string[];
|
|
15
|
+
readonly usStates: readonly string[];
|
|
16
|
+
readonly emphasis: readonly string[];
|
|
17
|
+
};
|
|
18
|
+
export type NotAcronymSpans = (text: string) => Span[];
|
|
19
|
+
/**
|
|
20
|
+
* 文の中で、略語として数えない大文字を含む範囲。語彙表から一度だけ組み立てて、文ごとに呼ぶ。
|
|
21
|
+
* 略語は範囲にまるごと入るときだけ外れるので、語の境目は見なくてよい(NOTE の中の NOT)。
|
|
22
|
+
*/
|
|
23
|
+
export declare const notAcronymSpansOf: (words: NotationWords) => NotAcronymSpans;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=acronym-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acronym-context.d.ts","sourceRoot":"","sources":["../../src/detectors/acronym-context.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH,KAAK,IAAI,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,CAAC;AAuBF,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAAE,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,aAAa,KAAG,eAGxD,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { escapeRegExp } from "../orthography.js";
|
|
2
|
+
// 空の語彙表は「その書き方が無い」。空の選択肢 (?:) は至る所で空文字に当たるので、何にも当たらない形にする。
|
|
3
|
+
const oneOf = (words) => (words.length === 0 ? "(?!)" : `(?:${words.map(escapeRegExp).join("|")})`);
|
|
4
|
+
const MINUTES = String.raw `:[0-5]\d`;
|
|
5
|
+
const CLOCK_12 = String.raw `(?<![\d:.])(?:1[0-2]|0?[1-9])(?:${MINUTES})?`;
|
|
6
|
+
const CLOCK_24 = String.raw `(?<![\d:.])(?:[01]?\d|2[0-3])${MINUTES}`;
|
|
7
|
+
/** 時間帯の前の午前・午後は書き方を問わない(pm、p.m.、P.M.、PM)。 */
|
|
8
|
+
const ANY_MERIDIEM = String.raw `[AaPp]\.?[Mm]\.?`;
|
|
9
|
+
/** 桁区切りは 3 桁ずつ揃っているときだけ金額と読む。「item 1, USD」の 1, は金額ではない。 */
|
|
10
|
+
const AMOUNT = String.raw `(?:\d{1,3}(?:,\d{3})+|\d+)(?:\.\d+)?`;
|
|
11
|
+
// 強調の記号は空白に置き換えてある(**3:30** PM)ので、部品の間の空白は数を問わない。
|
|
12
|
+
const patternsOf = (words) => [
|
|
13
|
+
new RegExp(String.raw `${CLOCK_12}\s*${oneOf(words.meridiem)}`, "gu"),
|
|
14
|
+
new RegExp(String.raw `(?:${CLOCK_24}|${CLOCK_12}\s*${ANY_MERIDIEM})\s*${oneOf(words.timeZones)}`, "gu"),
|
|
15
|
+
new RegExp(String.raw `${oneOf(words.currencies)}\s*[$€£¥]?${AMOUNT}`, "gu"),
|
|
16
|
+
new RegExp(String.raw `(?<![\w.,])${AMOUNT}\s*${oneOf(words.currencies)}`, "gu"),
|
|
17
|
+
new RegExp(String.raw `,\s+${oneOf(words.usStates)}\s+\d{5}(?:-\d{4})?(?!\d)`, "gu"),
|
|
18
|
+
new RegExp(oneOf(words.emphasis), "gu"),
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* 文の中で、略語として数えない大文字を含む範囲。語彙表から一度だけ組み立てて、文ごとに呼ぶ。
|
|
22
|
+
* 略語は範囲にまるごと入るときだけ外れるので、語の境目は見なくてよい(NOTE の中の NOT)。
|
|
23
|
+
*/
|
|
24
|
+
export const notAcronymSpansOf = (words) => {
|
|
25
|
+
const patterns = patternsOf(words);
|
|
26
|
+
return (text) => patterns.flatMap((pattern) => [...text.matchAll(pattern)].map((match) => ({ start: match.index, end: match.index + match[0].length })));
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=acronym-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acronym-context.js","sourceRoot":"","sources":["../../src/detectors/acronym-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAmBjD,2DAA2D;AAC3D,MAAM,KAAK,GAAG,CAAC,KAAwB,EAAU,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE/H,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAA,UAAU,CAAC;AACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA,mCAAmC,OAAO,IAAI,CAAC;AAC1E,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAA,gCAAgC,OAAO,EAAE,CAAC;AACrE,6CAA6C;AAC7C,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAA,kBAAkB,CAAC;AAClD,2DAA2D;AAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAA,sCAAsC,CAAC;AAEhE,kDAAkD;AAClD,MAAM,UAAU,GAAG,CAAC,KAAoB,EAAqB,EAAE,CAAC;IAC9D,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,GAAG,QAAQ,MAAM,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IACpE,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,MAAM,QAAQ,IAAI,QAAQ,MAAM,YAAY,OAAO,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC;IACvG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,aAAa,MAAM,EAAE,EAAE,IAAI,CAAC;IAC3E,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,cAAc,MAAM,MAAM,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC;IAC/E,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,OAAO,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,2BAA2B,EAAE,IAAI,CAAC;IACnF,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC;CACxC,CAAC;AAIF;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAAoB,EAAmB,EAAE;IACzE,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3J,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** 言語パッケージの語彙表から読む、括弧の中で略語の前に書く語(以下、hereinafter)と後ろに書く語(という)。 */
|
|
2
|
+
export type DefinitionWords = {
|
|
3
|
+
readonly markers: readonly string[];
|
|
4
|
+
readonly verbs: readonly string[];
|
|
5
|
+
};
|
|
6
|
+
export type ExpandedAt = (body: string, acronym: string, at: number) => boolean;
|
|
7
|
+
/** body の at にある略語が、その場で展開・定義されているか。語彙表から一度だけ組み立てて、略語ごとに呼ぶ。 */
|
|
8
|
+
export declare const expansionAt: (words: DefinitionWords) => ExpandedAt;
|
|
9
|
+
//# sourceMappingURL=acronym-expansion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acronym-expansion.d.ts","sourceRoot":"","sources":["../../src/detectors/acronym-expansion.ts"],"names":[],"mappings":"AAuEA,iEAAiE;AACjE,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AA8BzG,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;AAEhF,+DAA+D;AAC/D,eAAO,MAAM,WAAW,GAAI,OAAO,eAAe,KAAG,UAGpD,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { escapeRegExp } from "../orthography.js";
|
|
2
|
+
/**
|
|
3
|
+
* 展開は略語の**すぐ隣**にあるときだけ認める。
|
|
4
|
+
* 60 文字も見ると、同じ文のどこかに括弧があるだけで「説明済み」になり、1 件も出なくなる。
|
|
5
|
+
*
|
|
6
|
+
* 認めるのは次の形。どれも実際によく書かれる。
|
|
7
|
+
* CI(継続的インテグレーション) 略語のあとに括弧
|
|
8
|
+
* Continuous Integration (CI) 括弧の中が略語
|
|
9
|
+
* Tax Cuts and Jobs Act [TCJA] 角括弧の中が略語で、直前の語の頭文字と揃う
|
|
10
|
+
* Relief Act (RA; P.L. 112-240) 括弧の最初の項目が略語で、直前の語か区切りの後の語の頭文字と揃う
|
|
11
|
+
* 人事部(以下「HR」という。) 括弧の中が定義の語と略語だけ
|
|
12
|
+
* 括弧と略語の間には、引用符((“MNDA”)、(「MNDA」))と空白だけを許す。
|
|
13
|
+
*/
|
|
14
|
+
const WRAP = String.raw `[\s"“”'‘’「」『』]*`;
|
|
15
|
+
const OPENS = new RegExp(String.raw `^${WRAP}[((]`, "u");
|
|
16
|
+
const CLOSES = new RegExp(String.raw `^${WRAP}[))]`, "u");
|
|
17
|
+
const OPENED = new RegExp(String.raw `[((]${WRAP}$`, "u");
|
|
18
|
+
const SQUARE_CLOSES = new RegExp(String.raw `^${WRAP}\]`, "u");
|
|
19
|
+
const SQUARE_OPENED = new RegExp(String.raw `\[${WRAP}$`, "u");
|
|
20
|
+
const ANY_OPENED = new RegExp(String.raw `[(([]${WRAP}$`, "u");
|
|
21
|
+
/** 括弧の最初の項目のあとの区切りと、括弧が閉じるまでの残り((ARRA; P.L. 111-5)、(OP、Originator Profile))。 */
|
|
22
|
+
const SEPARATED = new RegExp(String.raw `^${WRAP}[;;,,、](?<rest>[^()()]*)`, "u");
|
|
23
|
+
const QUOTES = /["“”'‘’「」『』]/gu;
|
|
24
|
+
/** 括弧と略語の間の幅。空白は 1 つに畳んであるので、(“ MNDA ”) まで収まる。 */
|
|
25
|
+
const NEAR = 3;
|
|
26
|
+
/** 定義の語を挟む形で、括弧から略語まで・略語から括弧までに見る幅。(hereinafter referred to as “SLA”) が収まる。 */
|
|
27
|
+
const DEFINITION_REACH = 60;
|
|
28
|
+
/** 定義の語どうし、定義の語と略語の間に来てよいもの(以下、HR)。英字が続けば語の途中((theSLA))。 */
|
|
29
|
+
const MARKER_GAP = String.raw `(?![A-Za-z])[\s、,]*`;
|
|
30
|
+
/**
|
|
31
|
+
* 角括弧は引用の印にも使う([IANA]、[1])。直前の語のうち大文字で始まる語の頭文字が
|
|
32
|
+
* 略語と揃うときだけ展開と見なす。見る語は略語の文字数の 2 倍まで(and や of を挟むため)。
|
|
33
|
+
*/
|
|
34
|
+
const lettersOf = (acronym) => acronym.replaceAll("&", "");
|
|
35
|
+
const initialsOf = (words) => words
|
|
36
|
+
.filter((word) => /^[A-Z]/u.test(word))
|
|
37
|
+
.map((word) => word.charAt(0))
|
|
38
|
+
.join("");
|
|
39
|
+
const spellsOut = (before, acronym) => {
|
|
40
|
+
const letters = lettersOf(acronym);
|
|
41
|
+
const words = before
|
|
42
|
+
.replace(ANY_OPENED, "")
|
|
43
|
+
.trim()
|
|
44
|
+
.split(/\s+/u)
|
|
45
|
+
.slice(-letters.length * 2);
|
|
46
|
+
return initialsOf(words).endsWith(letters);
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* 括弧の最初の項目が略語で、区切りのあとに注記が続く形((ARRA; P.L. 111-5)、(OP、Originator Profile))。
|
|
50
|
+
* 同じ形で列挙も書く((MR, handbook, etc.)、(EPA, FDIC, GSA))ので、直前の語か、区切りから括弧が閉じるまでの語の
|
|
51
|
+
* 頭文字が略語と揃うときだけ展開と見なす。区切りの後ろは閉じた括弧の中だけを見て、頭文字がちょうど略語になることを求める。
|
|
52
|
+
*/
|
|
53
|
+
const isSeparatedAt = (body, acronym, at) => {
|
|
54
|
+
if (!OPENED.test(body.slice(Math.max(0, at - NEAR), at)))
|
|
55
|
+
return false;
|
|
56
|
+
const separated = SEPARATED.exec(body.slice(at + acronym.length, at + acronym.length + DEFINITION_REACH));
|
|
57
|
+
if (separated === null)
|
|
58
|
+
return false;
|
|
59
|
+
const rest = separated.groups?.["rest"] ?? "";
|
|
60
|
+
const end = at + acronym.length + separated[0].length;
|
|
61
|
+
const closed = CLOSES.test(body.slice(end, end + NEAR));
|
|
62
|
+
return spellsOut(body.slice(0, at), acronym) || (closed && initialsOf(rest.replace(QUOTES, " ").trim().split(/\s+/u)) === lettersOf(acronym));
|
|
63
|
+
};
|
|
64
|
+
const oneOf = (words) => (words.length === 0 ? "(?!)" : words.map(escapeRegExp).join("|"));
|
|
65
|
+
const definitionPatterns = (words) => ({
|
|
66
|
+
opened: new RegExp(String.raw `[((]\s*(?<markers>(?:(?:${oneOf(words.markers)})${MARKER_GAP})*)${WRAP}(?<![A-Za-z])$`, "iu"),
|
|
67
|
+
closes: new RegExp(String.raw `^${WRAP}(?<verb>(?:${oneOf(words.verbs)})[。.]?)?${WRAP}[))]`, "iu"),
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* 括弧の中に定義の語と略語だけがある形。語が 1 つも無い(CI)は OPENED と CLOSES が見るので、ここでは数えない。
|
|
71
|
+
* 括弧の中身が語と略語で尽きることを求めるので、ふつうの意味の「以下」((以下のSRE手順))は定義にならない。
|
|
72
|
+
*/
|
|
73
|
+
const isDefinedAt = (patterns, body, acronym, at) => {
|
|
74
|
+
const opened = patterns.opened.exec(body.slice(Math.max(0, at - DEFINITION_REACH), at));
|
|
75
|
+
const closes = patterns.closes.exec(body.slice(at + acronym.length, at + acronym.length + DEFINITION_REACH));
|
|
76
|
+
if (opened === null || closes === null)
|
|
77
|
+
return false;
|
|
78
|
+
return (opened.groups?.["markers"] ?? "") !== "" || (closes.groups?.["verb"] ?? "") !== "";
|
|
79
|
+
};
|
|
80
|
+
const isBracketedAt = (body, acronym, at) => {
|
|
81
|
+
const after = body.slice(at + acronym.length, at + acronym.length + NEAR);
|
|
82
|
+
const before = body.slice(Math.max(0, at - NEAR), at);
|
|
83
|
+
if (OPENS.test(after) || (OPENED.test(before) && CLOSES.test(after)))
|
|
84
|
+
return true;
|
|
85
|
+
if (SQUARE_OPENED.test(before) && SQUARE_CLOSES.test(after) && spellsOut(body.slice(0, at), acronym))
|
|
86
|
+
return true;
|
|
87
|
+
return isSeparatedAt(body, acronym, at);
|
|
88
|
+
};
|
|
89
|
+
/** body の at にある略語が、その場で展開・定義されているか。語彙表から一度だけ組み立てて、略語ごとに呼ぶ。 */
|
|
90
|
+
export const expansionAt = (words) => {
|
|
91
|
+
const patterns = definitionPatterns(words);
|
|
92
|
+
return (body, acronym, at) => isBracketedAt(body, acronym, at) || isDefinedAt(patterns, body, acronym, at);
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=acronym-expansion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acronym-expansion.js","sourceRoot":"","sources":["../../src/detectors/acronym-expansion.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"char-shape.d.ts","sourceRoot":"","sources":["../../src/detectors/char-shape.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"char-shape.d.ts","sourceRoot":"","sources":["../../src/detectors/char-shape.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAsC,MAAM,cAAc,CAAC;AA4BjF;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,QAatB,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,QAWjB,CAAC"}
|
|
@@ -1,58 +1,44 @@
|
|
|
1
1
|
import { compacted, placeOf } from "./gram-place.js";
|
|
2
2
|
import { maskAddresses } from "../address-chain.js";
|
|
3
|
+
import { isAddressRun } from "./place-run.js";
|
|
3
4
|
import { proseText } from "../measure.js";
|
|
4
5
|
/**
|
|
5
6
|
* 文字の並びを見る検出。漢字の連なりが住所かどうかだけは、形態素解析の地名と数で決める。
|
|
6
7
|
* 覆った箇所は空白になっているので、proseText で潰してから数える。
|
|
7
8
|
*/
|
|
8
9
|
const KANJI_RUN = /[一-鿿]+/gu;
|
|
9
|
-
/**
|
|
10
|
-
const
|
|
11
|
-
const isGeo = (token) => isGeoName(token) || token?.features?.["NameType"] === "GeoUnit";
|
|
12
|
-
const isNumber = (token) => token?.features?.["NumType"] === "Card";
|
|
13
|
-
/**
|
|
14
|
-
* 住所の語: 地名と地名の単位(NameType=Geo / GeoUnit)、数(NumType=Card)、数のすぐ後ろの助数詞(丁目、NounType=Class)。
|
|
15
|
-
* 辞書に無い町名(新橋)は、地名の後ろで数の前に来るときだけ住所の一部とする。
|
|
16
|
-
*/
|
|
17
|
-
const isPlacePart = (tokens, index) => isGeo(tokens[index]) ||
|
|
18
|
-
isNumber(tokens[index]) ||
|
|
19
|
-
(isNumber(tokens[index - 1]) && tokens[index]?.features?.["NounType"] === "Class") ||
|
|
20
|
-
(isGeo(tokens[index - 1]) && isNumber(tokens[index + 1]));
|
|
21
|
-
/**
|
|
22
|
-
* 漢字の連なりが住所か(東京都港区新橋二丁目)。形態素解析が地名と読んだ語で始まり、住所の語だけでできている。
|
|
23
|
-
* 住所は決まった形で、ひらがなを挟んで書けない。組織名(日本経済団体連合会)は地名の後ろに普通の語が続くので住所ではない。品詞が無ければ判定しない。
|
|
24
|
-
*/
|
|
25
|
-
const isPlaceName = (sentence, run) => {
|
|
10
|
+
/** 漢字の連なりが住所か(東京都港区新橋二丁目)。形態素解析の地名と数で決める。品詞が無ければ判定しない。 */
|
|
11
|
+
const isPlaceName = (sentence, run, topUnits) => {
|
|
26
12
|
const tokens = sentence.tokens;
|
|
27
13
|
const place = tokens === undefined ? undefined : placeOf(compacted(sentence.text, "word"), run);
|
|
28
14
|
if (tokens === undefined || place === undefined)
|
|
29
15
|
return false;
|
|
30
16
|
const [start, end] = [sentence.span.start + place.start, sentence.span.start + place.end];
|
|
31
17
|
const covering = tokens.flatMap((token, index) => (token.span.start < end && start < token.span.end ? [index] : []));
|
|
32
|
-
|
|
33
|
-
// 地名が単位を挟まずに続けば(東京大阪名古屋福岡)、住所ではなく地名の並び。
|
|
34
|
-
const listed = covering.some((index) => isGeoName(tokens[index]) && isGeoName(tokens[index + 1]));
|
|
35
|
-
return first !== undefined && isGeo(tokens[first]) && !listed && covering.every((index) => isPlacePart(tokens, index));
|
|
18
|
+
return isAddressRun(tokens, covering, topUnits);
|
|
36
19
|
};
|
|
37
|
-
const longestKanji = (sentence, profile) => [...maskAddresses(proseText(sentence), profile).matchAll(KANJI_RUN)]
|
|
20
|
+
const longestKanji = (sentence, profile, topUnits) => [...maskAddresses(proseText(sentence), profile).matchAll(KANJI_RUN)]
|
|
38
21
|
.map((match) => match[0])
|
|
39
|
-
.filter((run) => !isPlaceName(sentence, run))
|
|
22
|
+
.filter((run) => !isPlaceName(sentence, run, topUnits))
|
|
40
23
|
.reduce((longest, run) => (run.length > longest.length ? run : longest), "");
|
|
41
24
|
/**
|
|
42
25
|
* 漢字が続くと、どこで語が切れるのか読み手が探すことになる。
|
|
43
26
|
* 「情報処理推進機構認定試験」は 12 字。ひらがなを 1 つ挟むだけで読める。
|
|
44
27
|
*/
|
|
45
|
-
export const kanjiRun = (doc, options) =>
|
|
46
|
-
.map((
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
28
|
+
export const kanjiRun = (doc, options) => {
|
|
29
|
+
const topUnits = new Set((doc.lexicons["prefecture-unit"] ?? []).map((entry) => entry.pattern));
|
|
30
|
+
return doc.sentences
|
|
31
|
+
.map((sentence) => ({ sentence, run: longestKanji(sentence, doc.profile, topUnits) }))
|
|
32
|
+
.filter(({ run }) => run.length > options.limit)
|
|
33
|
+
.map(({ sentence, run }) => ({
|
|
34
|
+
rule: "max-kanji-continuous",
|
|
35
|
+
severity: "warning",
|
|
36
|
+
line: 0,
|
|
37
|
+
column: 0,
|
|
38
|
+
quote: sentence.text.trim(),
|
|
39
|
+
values: { word: run, count: run.length, limit: options.limit, offset: sentence.span.start },
|
|
40
|
+
}));
|
|
41
|
+
};
|
|
56
42
|
const MIDDLE_DOT = /・/gu;
|
|
57
43
|
/**
|
|
58
44
|
* 中黒で並べると、どこまでが 1 つの項目か分からなくなる。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"char-shape.js","sourceRoot":"","sources":["../../src/detectors/char-shape.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"char-shape.js","sourceRoot":"","sources":["../../src/detectors/char-shape.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Detector, Lexicon, Token } from "../plugin.ts";
|
|
2
|
+
/** 二語のあいだ。space は空白だけ、markup は印だけ(文字も数字も無い)、text はそれ以外で、別々の語。 */
|
|
3
|
+
export type Gap = "space" | "markup" | "text";
|
|
4
|
+
export declare const gapBetween: (source: string, first: Token, second: Token) => Gap;
|
|
5
|
+
/** 語を空白で区切る言語だけ。日本語は語どうしが接しているのが普通。 */
|
|
6
|
+
export declare const isPartOfLongerWord: (source: string, first: Token, second: Token) => boolean;
|
|
7
|
+
/**
|
|
8
|
+
* tokens の at 語目と次の語の重なりを、語彙表のどれかの行がそのまま含むか。
|
|
9
|
+
* 語彙表の語は、文と同じ解析器で分けたもの(entry.tokens)で比べる。書き方の空白の有無に左右されない。
|
|
10
|
+
*/
|
|
11
|
+
export declare const isAllowed: (tokens: readonly Token[], at: number, allowed: Lexicon) => boolean;
|
|
12
|
+
export type Doubled = {
|
|
13
|
+
readonly first: Token;
|
|
14
|
+
readonly second: Token;
|
|
15
|
+
};
|
|
16
|
+
/** 小文字の語の後ろの大文字は、題名や名前の書き出し(the [Your Rights section])。同じ語の the The は書き損じのまま。 */
|
|
17
|
+
export declare const startsTitle: (first: Token, second: Token) => boolean;
|
|
18
|
+
/** 並んだ二語が書き損じか。source は文書全体で、token の span もその座標。 */
|
|
19
|
+
export declare const doubledAt: (source: string, first: Token, second: Token, spaced: boolean) => boolean;
|
|
20
|
+
/**
|
|
21
|
+
* 文の途中で、大文字の語の後ろに小文字の同じ語が来たら、一つ目は名前(Payment for May may be delayed)。
|
|
22
|
+
* 文頭の The the と、冠詞・所有の語(review The the draft)は名前にならないので書き損じ。
|
|
23
|
+
*/
|
|
24
|
+
export declare const isNameBefore: (first: Token, second: Token, opensSentence: boolean) => boolean;
|
|
25
|
+
export declare const doubledIn: (source: string, tokens: readonly Token[], spaced: boolean, allowed: Lexicon) => Doubled[];
|
|
26
|
+
export declare const doubledWord: Detector;
|
|
27
|
+
//# sourceMappingURL=doubled-word.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doubled-word.d.ts","sourceRoot":"","sources":["../../src/detectors/doubled-word.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAW,OAAO,EAAY,KAAK,EAAE,MAAM,cAAc,CAAC;AA+BhF,iEAAiE;AACjE,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9C,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,OAAO,KAAK,EAAE,QAAQ,KAAK,KAAG,GAIxE,CAAC;AAEF,uCAAuC;AACvC,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,EAAE,OAAO,KAAK,EAAE,QAAQ,KAAK,KAAG,OACgB,CAAC;AAWlG;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,IAAI,MAAM,EAAE,SAAS,OAAO,KAAG,OACZ,CAAC;AAExE,MAAM,MAAM,OAAO,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAA;CAAE,CAAC;AAKxE,iFAAiF;AACjF,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,EAAE,QAAQ,KAAK,KAAG,OAA8E,CAAC;AAUzI,oDAAoD;AACpD,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,OAAO,KAAK,EAAE,QAAQ,KAAK,EAAE,QAAQ,OAAO,KAAG,OAKxF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,OAAO,KAAK,EAAE,QAAQ,KAAK,EAAE,eAAe,OAAO,KAAG,OAC4B,CAAC;AAYhH,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,QAAQ,SAAS,KAAK,EAAE,EAAE,QAAQ,OAAO,EAAE,SAAS,OAAO,KAAG,OAAO,EAM3G,CAAC;AAcL,eAAO,MAAM,WAAW,EAAE,QAMzB,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 語を書き損じて二度書いた(the the / 資料をを)。消し忘れと、書き換えの途中で残った語(our the platform)の二つ。
|
|
3
|
+
*
|
|
4
|
+
* 同じ語は、表層(大文字小文字は問わない)と品詞の両方が同じときだけ。「that that」は接続詞と指示語で品詞が違う。
|
|
5
|
+
* 冠詞と所有の語は名詞の前に一つしか立たないので、違う語でも二つ並べば書き損じ。印はアダプタが UD の FEATS で付ける。
|
|
6
|
+
* どの言語でも書き損じでない重なり(had had / 一つ一つ)は、言語ごとの語彙表に置く。
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* 重ねても書き損じにならない品詞。記号と数は語ではない。間投詞(はいはい / no no)と副詞(そうそう / very very)は
|
|
10
|
+
* 重ねて強める書き方がどの語でもできるので、語彙表では尽くせない。固有名詞は重なった名前(Walla Walla)がある。
|
|
11
|
+
*/
|
|
12
|
+
const REPEATABLE = new Set(["PUNCT", "SYM", "NUM", "X", "INTJ", "ADV", "PROPN"]);
|
|
13
|
+
/** 強調やリンクの印を挟んで重なった内容語は、画面名とその名詞(**app settings** settings screen)。機能語だけが書き損じ。 */
|
|
14
|
+
const FUNCTION_WORD = new Set(["DET", "ADP", "PRON", "AUX", "CCONJ", "SCONJ", "PART"]);
|
|
15
|
+
const LETTER = /\p{L}/u;
|
|
16
|
+
const LETTER_OR_DIGIT = /[\p{L}\p{N}]/u;
|
|
17
|
+
const SPACE_ONLY = /^\s*$/u;
|
|
18
|
+
/** 語を空白で区切る言語で、語に接していれば長い語の一部(114A The の A、Content-Type の Content)。 */
|
|
19
|
+
const JOINED = /[\p{L}\p{N}-]/u;
|
|
20
|
+
const isWord = (token) => LETTER.test(token.surface) && !REPEATABLE.has(token.pos) && token.features?.["NumType"] !== "Card";
|
|
21
|
+
const isDeterminer = (token) => token.features?.["PronType"] === "Art" || token.features?.["Poss"] === "Yes";
|
|
22
|
+
const sameWord = (first, second) => first.surface.toLowerCase() === second.surface.toLowerCase() && first.pos === second.pos;
|
|
23
|
+
export const gapBetween = (source, first, second) => {
|
|
24
|
+
const between = source.slice(first.span.end, second.span.start);
|
|
25
|
+
if (SPACE_ONLY.test(between))
|
|
26
|
+
return "space";
|
|
27
|
+
return LETTER_OR_DIGIT.test(between) ? "text" : "markup";
|
|
28
|
+
};
|
|
29
|
+
/** 語を空白で区切る言語だけ。日本語は語どうしが接しているのが普通。 */
|
|
30
|
+
export const isPartOfLongerWord = (source, first, second) => JOINED.test(source.charAt(first.span.start - 1)) || JOINED.test(source.charAt(second.span.end));
|
|
31
|
+
const surfacesOf = (tokens) => tokens.map((token) => token.surface.toLowerCase()).join("\u0000");
|
|
32
|
+
/**
|
|
33
|
+
* 語彙表の行(had had、sign in in、set up up to)の k 語目と k+1 語目を重なりに重ねて、行の語が全部並んでいるか。
|
|
34
|
+
* 一語の行は重なりを言っていないので、重ねる位置が無い。
|
|
35
|
+
*/
|
|
36
|
+
const coversPairAt = (tokens, at, words) => Array.from({ length: words.length - 1 }, (_, k) => tokens.slice(at - k, at - k + words.length)).some((row) => surfacesOf(row) === surfacesOf(words));
|
|
37
|
+
/**
|
|
38
|
+
* tokens の at 語目と次の語の重なりを、語彙表のどれかの行がそのまま含むか。
|
|
39
|
+
* 語彙表の語は、文と同じ解析器で分けたもの(entry.tokens)で比べる。書き方の空白の有無に左右されない。
|
|
40
|
+
*/
|
|
41
|
+
export const isAllowed = (tokens, at, allowed) => allowed.some((entry) => coversPairAt(tokens, at, entry.tokens ?? []));
|
|
42
|
+
const LOWER_START = /^\p{Ll}/u;
|
|
43
|
+
const UPPER_START = /^\p{Lu}/u;
|
|
44
|
+
/** 小文字の語の後ろの大文字は、題名や名前の書き出し(the [Your Rights section])。同じ語の the The は書き損じのまま。 */
|
|
45
|
+
export const startsTitle = (first, second) => LOWER_START.test(first.surface) && UPPER_START.test(second.surface);
|
|
46
|
+
/** アダプタが重ね言葉(UD の Echo=Rdp)と読んだ語。「会社会社で」の二つ目。 */
|
|
47
|
+
const isEcho = (token) => token.features?.["Echo"] === "Rdp";
|
|
48
|
+
const isDeterminerPair = (first, second) => isDeterminer(first) && isDeterminer(second) && !startsTitle(first, second);
|
|
49
|
+
const isDoubled = (first, second) => isWord(first) && isWord(second) && !isEcho(second) && (sameWord(first, second) || isDeterminerPair(first, second));
|
|
50
|
+
/** 並んだ二語が書き損じか。source は文書全体で、token の span もその座標。 */
|
|
51
|
+
export const doubledAt = (source, first, second, spaced) => {
|
|
52
|
+
if (!isDoubled(first, second))
|
|
53
|
+
return false;
|
|
54
|
+
if (spaced && isPartOfLongerWord(source, first, second))
|
|
55
|
+
return false;
|
|
56
|
+
const gap = gapBetween(source, first, second);
|
|
57
|
+
return gap === "space" || (gap === "markup" && FUNCTION_WORD.has(first.pos));
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* 文の途中で、大文字の語の後ろに小文字の同じ語が来たら、一つ目は名前(Payment for May may be delayed)。
|
|
61
|
+
* 文頭の The the と、冠詞・所有の語(review The the draft)は名前にならないので書き損じ。
|
|
62
|
+
*/
|
|
63
|
+
export const isNameBefore = (first, second, opensSentence) => !opensSentence && !isDeterminer(first) && UPPER_START.test(first.surface) && LOWER_START.test(second.surface);
|
|
64
|
+
const opensSentence = (tokens, at) => !tokens.slice(0, at).some((token) => LETTER.test(token.surface));
|
|
65
|
+
const repeatsPrevious = (tokens, at) => {
|
|
66
|
+
const [previous, token] = [tokens[at - 1], tokens[at]];
|
|
67
|
+
return previous !== undefined && token !== undefined && surfacesOf([previous]) === surfacesOf([token]);
|
|
68
|
+
};
|
|
69
|
+
/** 語彙表の重なり(had had)も、三つ続けば(had had had)書き損じ。 */
|
|
70
|
+
const allowedAt = (tokens, at, allowed) => (repeatsPrevious(tokens, at) ? [] : allowed);
|
|
71
|
+
export const doubledIn = (source, tokens, spaced, allowed) => tokens.flatMap((second, index) => {
|
|
72
|
+
const first = tokens[index - 1];
|
|
73
|
+
if (first === undefined || !doubledAt(source, first, second, spaced))
|
|
74
|
+
return [];
|
|
75
|
+
if (isAllowed(tokens, index - 1, allowedAt(tokens, index - 1, allowed)))
|
|
76
|
+
return [];
|
|
77
|
+
return isNameBefore(first, second, opensSentence(tokens, index - 1)) ? [] : [{ first, second }];
|
|
78
|
+
});
|
|
79
|
+
/** 印を挟んでいても(the [the)、見せるのは二語だけ。 */
|
|
80
|
+
const wordOf = (doubled, spaced) => [doubled.first.surface, doubled.second.surface].join(spaced ? " " : "");
|
|
81
|
+
const findingOf = (sentence, doubled, spaced) => ({
|
|
82
|
+
rule: "doubled-word",
|
|
83
|
+
severity: "warning",
|
|
84
|
+
line: 0,
|
|
85
|
+
column: 0,
|
|
86
|
+
quote: sentence.text.trim(),
|
|
87
|
+
values: { word: wordOf(doubled, spaced), offset: doubled.second.span.start },
|
|
88
|
+
});
|
|
89
|
+
export const doubledWord = (doc, options) => {
|
|
90
|
+
const spaced = doc.lengthUnit === "word";
|
|
91
|
+
const allowed = options.lexicon ?? [];
|
|
92
|
+
return doc.sentences.flatMap((sentence) => doubledIn(doc.source, sentence.tokens ?? [], spaced, allowed).map((doubled) => findingOf(sentence, doubled, spaced)));
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=doubled-word.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doubled-word.js","sourceRoot":"","sources":["../../src/detectors/doubled-word.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heading-echo.d.ts","sourceRoot":"","sources":["../../src/detectors/heading-echo.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"heading-echo.d.ts","sourceRoot":"","sources":["../../src/detectors/heading-echo.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAA+C,MAAM,cAAc,CAAC;AA0D1F,eAAO,MAAM,WAAW,EAAE,QAezB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { lengthOf } from "../measure.js";
|
|
2
|
+
import { handsOver } from "./lead-in.js";
|
|
2
3
|
/** 見出しが短すぎると、偶然の一致で 100% になる。これ未満の見出しは見ない。 */
|
|
3
4
|
const MIN_GRAMS = 4;
|
|
4
5
|
/**
|
|
@@ -44,16 +45,25 @@ const addsLittle = (section, unit) => {
|
|
|
44
45
|
return false;
|
|
45
46
|
return lengthOf(first, unit) - headingUnits(section.heading, unit) <= NEW_MATERIAL[unit];
|
|
46
47
|
};
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}))
|
|
48
|
+
/** 最初の文が、同じ節の後ろ(箇条書き・表・コード)へ読者を渡している。 */
|
|
49
|
+
const leadsIn = (doc, section, phrases) => {
|
|
50
|
+
const first = section.firstSentence;
|
|
51
|
+
return first !== undefined && handsOver(first.text, doc.source.slice(first.span.end, section.span.end), phrases);
|
|
52
|
+
};
|
|
53
|
+
export const headingEcho = (doc, options) => {
|
|
54
|
+
const leadIns = (doc.lexicons["lead-in"] ?? []).map((entry) => entry.pattern);
|
|
55
|
+
return doc.sections
|
|
56
|
+
.filter((section) => section.heading.length > 0 && section.firstSentence !== undefined && addsLittle(section, doc.lengthUnit))
|
|
57
|
+
.filter((section) => !leadsIn(doc, section, leadIns))
|
|
58
|
+
.map((section) => ({ section, overlap: Math.round(containment(trigrams(section.heading), trigrams(section.firstSentence?.text ?? "")) * 100) }))
|
|
59
|
+
.filter(({ overlap }) => overlap >= options.limit)
|
|
60
|
+
.map(({ section, overlap }) => ({
|
|
61
|
+
rule: "heading-echo",
|
|
62
|
+
severity: "warning",
|
|
63
|
+
line: 0,
|
|
64
|
+
column: 0,
|
|
65
|
+
quote: section.firstSentence?.text.trim() ?? "",
|
|
66
|
+
values: { heading: section.heading, count: overlap, limit: options.limit, offset: section.firstSentence?.span.start ?? section.span.start },
|
|
67
|
+
}));
|
|
68
|
+
};
|
|
59
69
|
//# sourceMappingURL=heading-echo.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heading-echo.js","sourceRoot":"","sources":["../../src/detectors/heading-echo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,8CAA8C;AAC9C,MAAM,SAAS,GAAG,CAAC,CAAC;AAEpB;;;GAGG;AACH,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAe,EAAE;IAC7C,2CAA2C;IAC3C,sDAAsD;IACtD,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IAC3D,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/H,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,GAAG,CAAC,OAAoB,EAAE,QAAqB,EAAU,EAAE;IAC1E,IAAI,OAAO,CAAC,IAAI,GAAG,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;AACjF,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,YAAY,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AAE3C,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,IAAgB,EAAU,EAAE,CACjE,IAAI,KAAK,MAAM;IACb,CAAC,CAAC,OAAO;SACJ,IAAI,EAAE;SACN,KAAK,CAAC,MAAM,CAAC;SACb,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM;IAC7C,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;AAE1C,MAAM,UAAU,GAAG,CAAC,OAAgB,EAAE,IAAgB,EAAW,EAAE;IACjE,MAAM,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC;IACpC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,OAAO,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;AAC3F,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAa,CAAC,GAAG,EAAE,OAAO,EAAa,EAAE
|
|
1
|
+
{"version":3,"file":"heading-echo.js","sourceRoot":"","sources":["../../src/detectors/heading-echo.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detectors/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAoB7C,kDAAkD;AAClD,eAAO,MAAM,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CA8CxD,CAAC"}
|