chaffjs 0.27.0 → 0.27.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"change-rate.d.ts","sourceRoot":"","sources":["../../src/detectors/change-rate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAA+C,MAAM,cAAc,CAAC;AAgG1F,eAAO,MAAM,UAAU,EAAE,QAsBxB,CAAC"}
1
+ {"version":3,"file":"change-rate.d.ts","sourceRoot":"","sources":["../../src/detectors/change-rate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAA6D,MAAM,cAAc,CAAC;AA2HxG,eAAO,MAAM,UAAU,EAAE,QA0BxB,CAAC"}
@@ -65,13 +65,32 @@ const spansOf = (source, word) => {
65
65
  return [...source.matchAll(pattern)].map((match) => ({ start: match.index, end: match.index + match[0].length }));
66
66
  };
67
67
  const SIGNS = { rise: 1, fall: -1 };
68
- /** Phrases that hold a direction word but give no direction ("up to 25%" is a ceiling): lexicon change-direction-not. */
69
- const directionsOf = (doc) => {
70
- const not = patternsOf(doc, "change-direction-not").flatMap((phrase) => spansOf(doc.source, phrase));
71
- return (doc.lexicons["change-direction"] ?? []).flatMap((entry) => {
72
- const sign = SIGNS[entry.group ?? ""];
73
- const spans = spansOf(doc.source, entry.pattern).filter((span) => !not.some((phrase) => phrase.start <= span.start && span.end <= phrase.end));
74
- return sign === undefined ? [] : spans.map((span) => ({ ...span, sign }));
68
+ /** Where the words of a lexicon stand, less those inside a phrase of its "-not" lexicon ("up to 25%" is a ceiling). */
69
+ const spansWithout = (doc, entries, notLexicon) => {
70
+ const not = patternsOf(doc, notLexicon).flatMap((phrase) => spansOf(doc.source, phrase));
71
+ return entries.flatMap((entry) => spansOf(doc.source, entry.pattern)
72
+ .filter((span) => !not.some((phrase) => phrase.start <= span.start && span.end <= phrase.end))
73
+ .map((span) => ({ ...span, entry })));
74
+ };
75
+ /** Lexicon change-direction, less the phrases of change-direction-not. */
76
+ const directionsOf = (doc) => spansWithout(doc, doc.lexicons["change-direction"] ?? [], "change-direction-not").flatMap(({ start, end, entry }) => {
77
+ const sign = SIGNS[entry.group ?? ""];
78
+ return sign === undefined ? [] : [{ start, end, sign }];
79
+ });
80
+ /** Lexicon change-break (「は」, "and"), less the phrases of change-break-not (「上がり」 holds が but starts no subject). */
81
+ const breaksOf = (doc) => spansWithout(doc, doc.lexicons["change-break"] ?? [], "change-break-not").map(({ start, end, entry }) => ({
82
+ start,
83
+ end,
84
+ beforeRateOnly: entry.group === "rate",
85
+ }));
86
+ /** A calendar year written alone or with a unit of calendar year (2025, 2025年, 2025年度), and not part of an amount ($2025). */
87
+ const CALENDAR_YEAR = /(?<!\d|\d[.,])(?:1[89]|2[01])\d{2}(?!\d|[.,]\d)/gu;
88
+ const periodsOf = (doc, figures) => {
89
+ const yearUnits = new Set(patternsOf(doc, "calendar-year-unit").map((unit) => `${unit}|`));
90
+ const amounts = figures.filter((figure) => !yearUnits.has(figure.unit));
91
+ return [...doc.source.matchAll(CALENDAR_YEAR)].flatMap((match) => {
92
+ const span = { start: match.index, end: match.index + match[0].length };
93
+ return amounts.some((figure) => figure.start < span.end && span.start < figure.end) ? [] : [{ ...span, year: Number(match[0]) }];
75
94
  });
76
95
  };
77
96
  const marksOf = (doc, lexicon) => (doc.lexicons[lexicon] ?? []).flatMap((entry) => entry.position === undefined ? [] : spansOf(doc.source, entry.pattern).map((span) => ({ ...span, position: entry.position ?? "before" })));
@@ -82,13 +101,17 @@ export const changeRate = (doc) => {
82
101
  const units = patternsOf(doc, "percent-unit");
83
102
  const multipliers = patternsOf(doc, "amount-multiplier").map((word) => word.toLowerCase());
84
103
  const taken = nodes.map((node) => node.span);
104
+ const figures = [...treeFigures(doc, nodes, units, multipliers), ...countedFigures(doc, taken, multipliers)];
85
105
  const text = {
86
106
  sentences: doc.sentences.map((sentence) => sentence.span),
87
- figures: [...treeFigures(doc, nodes, units, multipliers), ...countedFigures(doc, taken, multipliers)],
107
+ figures,
88
108
  rates: ratesOf(doc, nodes, units),
89
109
  directions: directionsOf(doc),
90
110
  marks: marksOf(doc, "change-base"),
91
111
  targets: marksOf(doc, "change-target"),
112
+ periods: periodsOf(doc, figures),
113
+ breaks: breaksOf(doc),
114
+ source: doc.source,
92
115
  };
93
116
  return changeRateMismatches(text).map((issue) => ({
94
117
  rule: "change-rate-mismatch",
@@ -1 +1 @@
1
- {"version":3,"file":"change-rate.js","sourceRoot":"","sources":["../../src/detectors/change-rate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"change-rate.js","sourceRoot":"","sources":["../../src/detectors/change-rate.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,14 @@ export type Direction = Span & {
19
19
  export type BaseMark = Span & {
20
20
  readonly position: "before" | "after";
21
21
  };
22
+ /** A calendar year written in the sentence (「2025年」, "in 2025"). */
23
+ export type Period = Span & {
24
+ readonly year: number;
25
+ };
26
+ /** A word that starts another subject or clause; one that joins two values ("… in 2025 and …") is read only before the rate. */
27
+ export type Break = Span & {
28
+ readonly beforeRateOnly: boolean;
29
+ };
22
30
  export type ChangeText = {
23
31
  readonly sentences: readonly Span[];
24
32
  readonly figures: readonly Figure[];
@@ -27,7 +35,17 @@ export type ChangeText = {
27
35
  readonly marks: readonly BaseMark[];
28
36
  /** Words that mark the later value ("to", 「に」). */
29
37
  readonly targets: readonly BaseMark[];
38
+ readonly periods: readonly Period[];
39
+ /** Words that start another subject or clause (「利益は」, "and", ";"): a rate after one is not about the values before it. */
40
+ readonly breaks: readonly Break[];
41
+ /** The document's text, which the gaps of a pair are measured in. */
42
+ readonly source: string;
30
43
  };
31
- /** Each sentence with one rate of change, one direction, one marked earlier value and one other value in its unit, that disagree. */
44
+ /** The length of a gap, a Latin word counting as one character: "an increase of" is as short as 「前年比」. */
45
+ export declare const gapLength: (source: string, gap: Span) => number;
46
+ /**
47
+ * Each sentence with one rate of change and its direction, and the two values it is computed from, that disagree: the
48
+ * earlier value marked beside the rate, or the two values written together right before it.
49
+ */
32
50
  export declare const changeRateMismatches: (text: ChangeText) => StructureIssue[];
33
51
  //# sourceMappingURL=change-rate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"change-rate.d.ts","sourceRoot":"","sources":["../../src/structure/change-rate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,sIAAsI;AACtI,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACrG,yDAAyD;AACzD,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAChF,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;CAAE,CAAC;AACzD,2IAA2I;AAC3I,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,CAAC;AAExE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,IAAI,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;CACvC,CAAC;AA8EF,qIAAqI;AACrI,eAAO,MAAM,oBAAoB,GAAI,MAAM,UAAU,KAAG,cAAc,EAAmE,CAAC"}
1
+ {"version":3,"file":"change-rate.d.ts","sourceRoot":"","sources":["../../src/structure/change-rate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,sIAAsI;AACtI,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACrG,yDAAyD;AACzD,MAAM,MAAM,IAAI,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAChF,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;CAAE,CAAC;AACzD,2IAA2I;AAC3I,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,CAAC;AACxE,oEAAoE;AACpE,MAAM,MAAM,MAAM,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AACtD,gIAAgI;AAChI,MAAM,MAAM,KAAK,GAAG,IAAI,GAAG;IAAE,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,SAAS,EAAE,SAAS,IAAI,EAAE,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,0HAA0H;IAC1H,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AA+BF,0GAA0G;AAC1G,eAAO,MAAM,SAAS,GAAI,QAAQ,MAAM,EAAE,KAAK,IAAI,KAAG,MAA6E,CAAC;AA0JpI;;;GAGG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM,UAAU,KAAG,cAAc,EAAmE,CAAC"}
@@ -7,11 +7,24 @@ const MARK_GAP = 3;
7
7
  * away, the rate is of something else in the sentence (「100店から120店に増え、売上は15%増えた」).
8
8
  */
9
9
  const BASE_REACH = 12;
10
+ /**
11
+ * The two values written together, the earlier then the later or the other way round (「昨年の100万円から今年は150万円」
12
+ * "from $1.0 million last year to $1.5 million"): how far apart they may stand, and how far after them the rate may
13
+ * (「150万円になり、前年比20%」", an increase of 20%"). Measured with a Latin word counting as one character.
14
+ */
15
+ const PAIR_GAP = 16;
16
+ const PAIR_REACH = 16;
17
+ /** How far a year may stand from the value it dates (「2025年の100万円」"$1.0 million in 2025"), a word counting as one. */
18
+ const PERIOD_GAP = 8;
19
+ const LATIN_WORD = /[A-Za-z]+/gu;
10
20
  const PERCENT = 100;
11
21
  const HALF = 0.5;
12
22
  const DECIMAL_BASE = 10;
13
23
  const within = (outer, inner) => inner.start >= outer.start && inner.end <= outer.end;
14
24
  const distance = (left, right) => Math.max(left.start - right.end, right.start - left.end, 0);
25
+ const gapBetween = (left, right) => ({ start: left.end, end: right.start });
26
+ /** The length of a gap, a Latin word counting as one character: "an increase of" is as short as 「前年比」. */
27
+ export const gapLength = (source, gap) => source.slice(gap.start, gap.end).replaceAll(LATIN_WORD, "w").length;
15
28
  const markOf = (figure, marks) => marks.find((mark) => {
16
29
  const gap = mark.position === "after" ? mark.start - figure.end : figure.start - mark.end;
17
30
  return gap >= 0 && gap <= MARK_GAP;
@@ -43,29 +56,116 @@ const rateRange = (base, current) => {
43
56
  return undefined;
44
57
  return [(currentLow / baseHigh - 1) * PERCENT, (currentHigh / baseLow - 1) * PERCENT];
45
58
  };
46
- const issueIn = (text, sentence) => {
47
- const rates = text.rates.filter((rate) => within(sentence, rate));
48
- const figures = text.figures.filter((figure) => within(sentence, figure));
49
- const [rate] = rates;
50
- if (rates.length !== 1 || rate === undefined)
51
- return [];
52
- const sign = signNear(rate, text.directions.filter((direction) => within(sentence, direction)));
53
- const bases = figures.filter((figure) => isBaseFor(figure, rate, text.marks));
59
+ /** A word between the two that starts another subject or clause (「100万円から150万円に増え、利益は20%」). */
60
+ const brokenBetween = (text, one, other) => {
61
+ const gap = one.end <= other.start ? gapBetween(one, other) : gapBetween(other, one);
62
+ return text.breaks.some((word) => within(gap, word));
63
+ };
64
+ /** The earlier value marked beside the rate, and the one value in its unit before the rate or marked as reached. */
65
+ const besideRate = (text) => {
66
+ const bases = text.figures.filter((figure) => isBaseFor(figure, text.rate, text.marks) && !brokenBetween(text, figure, text.rate));
54
67
  const [base] = bases;
55
- if (sign === undefined || bases.length !== 1 || base === undefined)
56
- return [];
57
- const currents = figures.filter((figure) => figure !== base && figure.unit === base.unit && isCurrentFor(figure, rate, text.targets));
68
+ if (bases.length !== 1 || base === undefined)
69
+ return undefined;
70
+ const currents = text.figures.filter((figure) => figure !== base && figure.unit === base.unit && isCurrentFor(figure, text.rate, text.targets));
58
71
  const [current] = currents;
59
- const range = currents.length === 1 && current !== undefined ? rateRange(base, current) : undefined;
60
- if (range === undefined || current === undefined)
72
+ return currents.length === 1 && current !== undefined ? { base, current } : undefined;
73
+ };
74
+ const yearsBeside = (text, figure, side, bound) => text.periods.filter((period) => {
75
+ const [left, right] = side === "before" ? [period, figure] : [figure, period];
76
+ return left.end <= right.start && within(bound, period) && gapLength(text.source, gapBetween(left, right)) <= PERIOD_GAP;
77
+ });
78
+ /**
79
+ * Of two values each dated by a year, the earlier year's. The years stand on the same side of both values: before them
80
+ * (「2025年は100万円、2026年は150万円」) or after them ("$1.0 million in 2025 and $1.5 million in 2026").
81
+ */
82
+ const datedEarlier = (text, first, second) => {
83
+ const middle = gapBetween(first, second);
84
+ const sides = [
85
+ [yearsBeside(text, first, "before", { start: 0, end: first.start }), yearsBeside(text, second, "before", middle)],
86
+ [yearsBeside(text, first, "after", middle), yearsBeside(text, second, "after", { start: second.end, end: text.source.length })],
87
+ ].filter(([early, late]) => early?.length === 1 && late?.length === 1);
88
+ const [[early, late] = []] = sides;
89
+ const [firstYear, secondYear] = [early?.[0]?.year, late?.[0]?.year];
90
+ if (sides.length !== 1 || firstYear === undefined || secondYear === undefined || firstYear === secondYear)
91
+ return undefined;
92
+ return firstYear < secondYear ? first : second;
93
+ };
94
+ /** Which of two values written together is the earlier: the one marked (「から」, "from", 「前年の」), else the one dated earlier. */
95
+ const pairOf = (text, first, second) => {
96
+ const marked = [first, second].filter((figure) => markOf(figure, text.marks) !== undefined);
97
+ if (marked.length > 1)
98
+ return undefined;
99
+ const base = marked[0] ?? datedEarlier(text, first, second);
100
+ if (base === undefined)
101
+ return undefined;
102
+ return { base, current: base === first ? second : first };
103
+ };
104
+ /** Nothing between the later value and the rate that makes the rate another one's: a value, another subject, another base. */
105
+ const leadsTo = (text, second) => {
106
+ const gap = gapBetween(second, text.rate);
107
+ if (gap.start > gap.end || gapLength(text.source, gap) > PAIR_REACH)
108
+ return false;
109
+ return ![...text.figures, ...text.breaks, ...text.marks].some((span) => within(gap, span));
110
+ };
111
+ /** Two values of one subject written close, with no rate between them (「売上は100万円、費用は150万円」 is two subjects). */
112
+ const standTogether = (text, first, second) => {
113
+ const gap = gapBetween(first, second);
114
+ const inGap = (span) => within(gap, span);
115
+ if (gapLength(text.source, gap) > PAIR_GAP || text.rates.some(inGap))
116
+ return false;
117
+ return !text.breaks.some((word) => !word.beforeRateOnly && inGap(word));
118
+ };
119
+ /** The two values written together right before the rate (「昨年の100万円から今年は150万円になり、前年比20%の増加」). */
120
+ const beforeRate = (text) => {
121
+ const pairs = text.figures.flatMap((first, index) => {
122
+ const second = text.figures.slice(index + 1).find((figure) => figure.unit === first.unit);
123
+ const pair = second !== undefined && standTogether(text, first, second) && leadsTo(text, second) ? pairOf(text, first, second) : undefined;
124
+ return pair === undefined ? [] : [pair];
125
+ });
126
+ const [pair] = pairs;
127
+ return pairs.length === 1 ? pair : undefined;
128
+ };
129
+ /**
130
+ * The sentence's one rate with a word of direction beside it, a word counting for the rate it stands nearest. A percentage
131
+ * without one (「20%の増加、利益率は10%」) is about something else.
132
+ */
133
+ const readingIn = (text, sentence) => {
134
+ const inSentence = (span) => within(sentence, span);
135
+ const directions = text.directions.filter(inSentence);
136
+ const rates = text.rates.filter(inSentence);
137
+ const nearestTo = (rate, direction) => rates.every((other) => distance(direction, rate) <= distance(direction, other));
138
+ const signed = rates.flatMap((rate) => {
139
+ const sign = signNear(rate, directions.filter((direction) => nearestTo(rate, direction)));
140
+ return sign === undefined ? [] : [{ rate, sign }];
141
+ });
142
+ const [only] = signed;
143
+ if (signed.length !== 1 || only === undefined)
144
+ return undefined;
145
+ const parts = {
146
+ figures: text.figures.filter(inSentence).toSorted((left, right) => left.start - right.start),
147
+ periods: text.periods.filter(inSentence),
148
+ breaks: text.breaks.filter(inSentence),
149
+ };
150
+ return { ...text, ...parts, ...only, rates };
151
+ };
152
+ const issueIn = (text, sentence) => {
153
+ const reading = readingIn(text, sentence);
154
+ const pair = reading === undefined ? undefined : (besideRate(reading) ?? beforeRate(reading));
155
+ const range = pair === undefined ? undefined : rateRange(pair.base, pair.current);
156
+ if (reading === undefined || pair === undefined || range === undefined)
61
157
  return [];
158
+ const { rate, sign } = reading;
62
159
  const written = sign * rate.value;
63
160
  const slack = HALF * DECIMAL_BASE ** -rate.decimals;
64
161
  if (written >= range[0] - slack && written <= range[1] + slack)
65
162
  return [];
66
- const computed = Math.abs((current.value / base.value - 1) * PERCENT).toFixed(rate.decimals);
163
+ const computed = Math.abs((pair.current.value / pair.base.value - 1) * PERCENT).toFixed(rate.decimals);
67
164
  return [{ offset: rate.start, values: { rate: String(rate.value), computed } }];
68
165
  };
69
- /** Each sentence with one rate of change, one direction, one marked earlier value and one other value in its unit, that disagree. */
166
+ /**
167
+ * Each sentence with one rate of change and its direction, and the two values it is computed from, that disagree: the
168
+ * earlier value marked beside the rate, or the two values written together right before it.
169
+ */
70
170
  export const changeRateMismatches = (text) => text.sentences.flatMap((sentence) => issueIn(text, sentence));
71
171
  //# sourceMappingURL=change-rate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"change-rate.js","sourceRoot":"","sources":["../../src/structure/change-rate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"change-rate.js","sourceRoot":"","sources":["../../src/structure/change-rate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chaffjs",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "Prose validation harness. Finds what is hard to read, and never rewrites it for you.",
5
5
  "keywords": [
6
6
  "chaff",
@@ -87,8 +87,8 @@
87
87
  },
88
88
  "dependencies": {
89
89
  "@anthropic-ai/sdk": "^0.125.0",
90
- "@chaffjs/lang-en": "0.24.0",
91
- "@chaffjs/lang-ja": "0.26.0",
90
+ "@chaffjs/lang-en": "0.24.1",
91
+ "@chaffjs/lang-ja": "0.26.1",
92
92
  "mdast-util-from-markdown": "^2.0.3",
93
93
  "mdast-util-frontmatter": "^2.0.1",
94
94
  "mdast-util-gfm-table": "^2.0.0",
@@ -10,8 +10,8 @@ name:
10
10
  en: A rate of change the two values do not give
11
11
 
12
12
  why:
13
- ja: 「前年同月の1,000社から20%増えて1,200社」のように、もとの値・今の値・増減率を一つの文に書くと、読み手は率を確かめずに信じます。数字を一つだけ更新したとき、率だけを去年の文書から写したときに食い違います。一つの文に、もとの値(「から」「に比べて」の付いた値)、同じ単位の今の値、向きの語(増加、減少)の付いた百分率が一つずつあるとき、二つの値から率を計算して比べます。値は書いた桁までの丸めを認めます(12億円は11.5億円から12.5億円のどれか)。
14
- en: When one sentence gives the earlier value, the current one and the rate of change ("1,200 companies, up 20% from 1,000"), readers trust the rate without checking it. It goes wrong when one figure is updated and the others are not, or when the rate is copied from last year's text. When a sentence has one earlier value (marked by "from" or "compared with"), one current value in the same unit, and one percentage with a word of direction (up, decline), chaff computes the rate from the two values and compares. Each value may be rounded to its last written digit ($12 million is anything from $11.5 million to $12.5 million).
13
+ ja: 「前年同月の1,000社から20%増えて1,200社」のように、もとの値・今の値・増減率を一つの文に書くと、読み手は率を確かめずに信じます。数字を一つだけ更新したとき、率だけを去年の文書から写したときに食い違います。一つの文に、もとの値(「から」「に比べて」「前年の」の付いた値)、同じ単位の今の値、向きの語(増加、減少)の付いた百分率が一つずつあるとき、二つの値から率を計算して比べます。率のそばにもとの値が無くても、「昨年の100万円から今年は150万円になり、前年比50%の増加」「2025年度は100万円、2026年度は150万円で」のように二つの値が並んですぐ後に率が続くなら読みます(年が書いてあれば早い年の値がもとの値)。値は書いた桁までの丸めを認めます(12億円は11.5億円から12.5億円のどれか)。
14
+ en: When one sentence gives the earlier value, the current one and the rate of change ("1,200 companies, up 20% from 1,000"), readers trust the rate without checking it. It goes wrong when one figure is updated and the others are not, or when the rate is copied from last year's text. When a sentence has one earlier value (marked by "from" or "compared with"), one current value in the same unit, and one percentage with a word of direction (up, decline), chaff computes the rate from the two values and compares. The two values may also stand together right before the rate ("rose from $1.0 million last year to $1.5 million, an increase of 50%", "$1.0 million in 2025 and $1.5 million in 2026, up 50%"; with years, the earlier year's value is the earlier one). Each value may be rounded to its last written digit ($12 million is anything from $11.5 million to $12.5 million).
15
15
 
16
16
  message:
17
17
  ja: 「{rate}%」と書いていますが、二つの値からは {computed}% です
@@ -40,5 +40,5 @@ example:
40
40
  after: 1,300 companies used the app, up 30% from 1,000 companies a year earlier.
41
41
 
42
42
  not_flagged:
43
- ja: 率が二つある文、もとの値が「から」「に比べて」で名指されていない文、同じ単位の今の値が一つでない文、向きの語が率のそばに無い文は比べません。「前年比20%増」のように値が一つしか無いもの、ポイントの差、倍は見ません。丸めで届く範囲の率は言いません。
44
- en: 'A sentence with two rates, with no value marked as the earlier one, with no single current value in the same unit, or with no word of direction beside the rate is not compared. A change given with one value ("up 20% year on year"), percentage points and "times" are not read. A rate the rounding of the values can reach is not reported.'
43
+ ja: 向きの語の付いた率が二つある文、もとの値が「から」「に比べて」や年で名指されていない文、二つの値と率のあいだで主語が変わる文(「…に増え、利益は20%増えた」)、同じ単位の今の値が一つでない文、向きの語が率のそばに無い文は比べません。「前年比20%増」のように値が一つしか無いもの、ポイントの差、倍は見ません。丸めで届く範囲の率は言いません。
44
+ en: 'A sentence with two rates that each have a word of direction, with no value marked as the earlier one (by a word or a year), with another subject between the values and the rate ("…, and costs rose 20%"), with no single current value in the same unit, or with no word of direction beside the rate is not compared. A change given with one value ("up 20% year on year"), percentage points and "times" are not read. A rate the rounding of the values can reach is not reported.'
@@ -1,9 +1,9 @@
1
1
  // change-rate-mismatch: the reading half. Builds the figures, the rates and the words of structure/change-rate.ts from the
2
- // tree's quantities, the numbers counted with a word ("1,200 companies"), and the lexicons change-direction, change-base,
3
- // percent-unit and amount-multiplier.
4
- import type { Detector, Finding, ProseDocument, Span, StructureNode } from "../plugin.ts";
2
+ // tree's quantities, the numbers counted with a word ("1,200 companies"), the calendar years, and the lexicons change-direction,
3
+ // change-base, change-target, change-break, percent-unit and amount-multiplier.
4
+ import type { Detector, Finding, LexiconEntry, ProseDocument, Span, StructureNode } from "../plugin.ts";
5
5
  import { inDocumentOrder } from "../structure/issues.ts";
6
- import { changeRateMismatches, type BaseMark, type Direction, type Figure, type Rate } from "../structure/change-rate.ts";
6
+ import { changeRateMismatches, type BaseMark, type Break, type Direction, type Figure, type Period, type Rate } from "../structure/change-rate.ts";
7
7
  import { escapeRegExp } from "../orthography.ts";
8
8
  import { quoteAt } from "./structure-tree.ts";
9
9
 
@@ -82,13 +82,40 @@ const spansOf = (source: string, word: string): Span[] => {
82
82
 
83
83
  const SIGNS: Readonly<Record<string, 1 | -1>> = { rise: 1, fall: -1 };
84
84
 
85
- /** Phrases that hold a direction word but give no direction ("up to 25%" is a ceiling): lexicon change-direction-not. */
86
- const directionsOf = (doc: ProseDocument): Direction[] => {
87
- const not = patternsOf(doc, "change-direction-not").flatMap((phrase) => spansOf(doc.source, phrase));
88
- return (doc.lexicons["change-direction"] ?? []).flatMap((entry) => {
85
+ /** Where the words of a lexicon stand, less those inside a phrase of its "-not" lexicon ("up to 25%" is a ceiling). */
86
+ const spansWithout = (doc: ProseDocument, entries: readonly LexiconEntry[], notLexicon: string): (Span & { readonly entry: LexiconEntry })[] => {
87
+ const not = patternsOf(doc, notLexicon).flatMap((phrase) => spansOf(doc.source, phrase));
88
+ return entries.flatMap((entry) =>
89
+ spansOf(doc.source, entry.pattern)
90
+ .filter((span) => !not.some((phrase) => phrase.start <= span.start && span.end <= phrase.end))
91
+ .map((span) => ({ ...span, entry })),
92
+ );
93
+ };
94
+
95
+ /** Lexicon change-direction, less the phrases of change-direction-not. */
96
+ const directionsOf = (doc: ProseDocument): Direction[] =>
97
+ spansWithout(doc, doc.lexicons["change-direction"] ?? [], "change-direction-not").flatMap(({ start, end, entry }) => {
89
98
  const sign = SIGNS[entry.group ?? ""];
90
- const spans = spansOf(doc.source, entry.pattern).filter((span) => !not.some((phrase) => phrase.start <= span.start && span.end <= phrase.end));
91
- return sign === undefined ? [] : spans.map((span) => ({ ...span, sign }));
99
+ return sign === undefined ? [] : [{ start, end, sign }];
100
+ });
101
+
102
+ /** Lexicon change-break (「は」, "and"), less the phrases of change-break-not (「上がり」 holds が but starts no subject). */
103
+ const breaksOf = (doc: ProseDocument): Break[] =>
104
+ spansWithout(doc, doc.lexicons["change-break"] ?? [], "change-break-not").map(({ start, end, entry }) => ({
105
+ start,
106
+ end,
107
+ beforeRateOnly: entry.group === "rate",
108
+ }));
109
+
110
+ /** A calendar year written alone or with a unit of calendar year (2025, 2025年, 2025年度), and not part of an amount ($2025). */
111
+ const CALENDAR_YEAR = /(?<!\d|\d[.,])(?:1[89]|2[01])\d{2}(?!\d|[.,]\d)/gu;
112
+
113
+ const periodsOf = (doc: ProseDocument, figures: readonly Figure[]): Period[] => {
114
+ const yearUnits = new Set(patternsOf(doc, "calendar-year-unit").map((unit) => `${unit}|`));
115
+ const amounts = figures.filter((figure) => !yearUnits.has(figure.unit));
116
+ return [...doc.source.matchAll(CALENDAR_YEAR)].flatMap((match) => {
117
+ const span = { start: match.index, end: match.index + match[0].length };
118
+ return amounts.some((figure) => figure.start < span.end && span.start < figure.end) ? [] : [{ ...span, year: Number(match[0]) }];
92
119
  });
93
120
  };
94
121
 
@@ -103,13 +130,17 @@ export const changeRate: Detector = (doc): Finding[] => {
103
130
  const units = patternsOf(doc, "percent-unit");
104
131
  const multipliers = patternsOf(doc, "amount-multiplier").map((word) => word.toLowerCase());
105
132
  const taken = nodes.map((node) => node.span);
133
+ const figures = [...treeFigures(doc, nodes, units, multipliers), ...countedFigures(doc, taken, multipliers)];
106
134
  const text = {
107
135
  sentences: doc.sentences.map((sentence) => sentence.span),
108
- figures: [...treeFigures(doc, nodes, units, multipliers), ...countedFigures(doc, taken, multipliers)],
136
+ figures,
109
137
  rates: ratesOf(doc, nodes, units),
110
138
  directions: directionsOf(doc),
111
139
  marks: marksOf(doc, "change-base"),
112
140
  targets: marksOf(doc, "change-target"),
141
+ periods: periodsOf(doc, figures),
142
+ breaks: breaksOf(doc),
143
+ source: doc.source,
113
144
  };
114
145
  return changeRateMismatches(text).map((issue) => ({
115
146
  rule: "change-rate-mismatch",
@@ -12,6 +12,10 @@ export type Rate = Span & { readonly value: number; readonly decimals: number };
12
12
  export type Direction = Span & { readonly sign: 1 | -1 };
13
13
  /** A word that marks a value: the earlier one after it (「1,000社から」) or before it ("from 1,000"), the later one (「1,200社に」, "to 1,200"). */
14
14
  export type BaseMark = Span & { readonly position: "before" | "after" };
15
+ /** A calendar year written in the sentence (「2025年」, "in 2025"). */
16
+ export type Period = Span & { readonly year: number };
17
+ /** A word that starts another subject or clause; one that joins two values ("… in 2025 and …") is read only before the rate. */
18
+ export type Break = Span & { readonly beforeRateOnly: boolean };
15
19
 
16
20
  export type ChangeText = {
17
21
  readonly sentences: readonly Span[];
@@ -21,6 +25,11 @@ export type ChangeText = {
21
25
  readonly marks: readonly BaseMark[];
22
26
  /** Words that mark the later value ("to", 「に」). */
23
27
  readonly targets: readonly BaseMark[];
28
+ readonly periods: readonly Period[];
29
+ /** Words that start another subject or clause (「利益は」, "and", ";"): a rate after one is not about the values before it. */
30
+ readonly breaks: readonly Break[];
31
+ /** The document's text, which the gaps of a pair are measured in. */
32
+ readonly source: string;
24
33
  };
25
34
 
26
35
  /** How far a direction word may stand from the rate (「20%の増加」「20%増えました」, "an increase of 20%", "up 20%"). */
@@ -32,6 +41,16 @@ const MARK_GAP = 3;
32
41
  * away, the rate is of something else in the sentence (「100店から120店に増え、売上は15%増えた」).
33
42
  */
34
43
  const BASE_REACH = 12;
44
+ /**
45
+ * The two values written together, the earlier then the later or the other way round (「昨年の100万円から今年は150万円」
46
+ * "from $1.0 million last year to $1.5 million"): how far apart they may stand, and how far after them the rate may
47
+ * (「150万円になり、前年比20%」", an increase of 20%"). Measured with a Latin word counting as one character.
48
+ */
49
+ const PAIR_GAP = 16;
50
+ const PAIR_REACH = 16;
51
+ /** How far a year may stand from the value it dates (「2025年の100万円」"$1.0 million in 2025"), a word counting as one. */
52
+ const PERIOD_GAP = 8;
53
+ const LATIN_WORD = /[A-Za-z]+/gu;
35
54
  const PERCENT = 100;
36
55
  const HALF = 0.5;
37
56
  const DECIMAL_BASE = 10;
@@ -40,6 +59,11 @@ const within = (outer: Span, inner: Span): boolean => inner.start >= outer.start
40
59
 
41
60
  const distance = (left: Span, right: Span): number => Math.max(left.start - right.end, right.start - left.end, 0);
42
61
 
62
+ const gapBetween = (left: Span, right: Span): Span => ({ start: left.end, end: right.start });
63
+
64
+ /** The length of a gap, a Latin word counting as one character: "an increase of" is as short as 「前年比」. */
65
+ export const gapLength = (source: string, gap: Span): number => source.slice(gap.start, gap.end).replaceAll(LATIN_WORD, "w").length;
66
+
43
67
  const markOf = (figure: Figure, marks: readonly BaseMark[]): BaseMark | undefined =>
44
68
  marks.find((mark) => {
45
69
  const gap = mark.position === "after" ? mark.start - figure.end : figure.start - mark.end;
@@ -76,28 +100,124 @@ const rateRange = (base: Figure, current: Figure): readonly [number, number] | u
76
100
  return [(currentLow / baseHigh - 1) * PERCENT, (currentHigh / baseLow - 1) * PERCENT];
77
101
  };
78
102
 
79
- const issueIn = (text: ChangeText, sentence: Span): StructureIssue[] => {
80
- const rates = text.rates.filter((rate) => within(sentence, rate));
81
- const figures = text.figures.filter((figure) => within(sentence, figure));
82
- const [rate] = rates;
83
- if (rates.length !== 1 || rate === undefined) return [];
84
- const sign = signNear(
85
- rate,
86
- text.directions.filter((direction) => within(sentence, direction)),
87
- );
88
- const bases = figures.filter((figure) => isBaseFor(figure, rate, text.marks));
103
+ type Pair = { readonly base: Figure; readonly current: Figure };
104
+ /** One sentence's parts, with the rate: the one percentage that has a word of direction beside it. */
105
+ type Reading = ChangeText & { readonly rate: Rate; readonly sign: 1 | -1 };
106
+
107
+ /** A word between the two that starts another subject or clause (「100万円から150万円に増え、利益は20%」). */
108
+ const brokenBetween = (text: Reading, one: Span, other: Span): boolean => {
109
+ const gap = one.end <= other.start ? gapBetween(one, other) : gapBetween(other, one);
110
+ return text.breaks.some((word) => within(gap, word));
111
+ };
112
+
113
+ /** The earlier value marked beside the rate, and the one value in its unit before the rate or marked as reached. */
114
+ const besideRate = (text: Reading): Pair | undefined => {
115
+ const bases = text.figures.filter((figure) => isBaseFor(figure, text.rate, text.marks) && !brokenBetween(text, figure, text.rate));
89
116
  const [base] = bases;
90
- if (sign === undefined || bases.length !== 1 || base === undefined) return [];
91
- const currents = figures.filter((figure) => figure !== base && figure.unit === base.unit && isCurrentFor(figure, rate, text.targets));
117
+ if (bases.length !== 1 || base === undefined) return undefined;
118
+ const currents = text.figures.filter((figure) => figure !== base && figure.unit === base.unit && isCurrentFor(figure, text.rate, text.targets));
92
119
  const [current] = currents;
93
- const range = currents.length === 1 && current !== undefined ? rateRange(base, current) : undefined;
94
- if (range === undefined || current === undefined) return [];
120
+ return currents.length === 1 && current !== undefined ? { base, current } : undefined;
121
+ };
122
+
123
+ const yearsBeside = (text: Reading, figure: Figure, side: "before" | "after", bound: Span): Period[] =>
124
+ text.periods.filter((period) => {
125
+ const [left, right] = side === "before" ? [period, figure] : [figure, period];
126
+ return left.end <= right.start && within(bound, period) && gapLength(text.source, gapBetween(left, right)) <= PERIOD_GAP;
127
+ });
128
+
129
+ /**
130
+ * Of two values each dated by a year, the earlier year's. The years stand on the same side of both values: before them
131
+ * (「2025年は100万円、2026年は150万円」) or after them ("$1.0 million in 2025 and $1.5 million in 2026").
132
+ */
133
+ const datedEarlier = (text: Reading, first: Figure, second: Figure): Figure | undefined => {
134
+ const middle = gapBetween(first, second);
135
+ const sides = [
136
+ [yearsBeside(text, first, "before", { start: 0, end: first.start }), yearsBeside(text, second, "before", middle)],
137
+ [yearsBeside(text, first, "after", middle), yearsBeside(text, second, "after", { start: second.end, end: text.source.length })],
138
+ ].filter(([early, late]) => early?.length === 1 && late?.length === 1);
139
+ const [[early, late] = []] = sides;
140
+ const [firstYear, secondYear] = [early?.[0]?.year, late?.[0]?.year];
141
+ if (sides.length !== 1 || firstYear === undefined || secondYear === undefined || firstYear === secondYear) return undefined;
142
+ return firstYear < secondYear ? first : second;
143
+ };
144
+
145
+ /** Which of two values written together is the earlier: the one marked (「から」, "from", 「前年の」), else the one dated earlier. */
146
+ const pairOf = (text: Reading, first: Figure, second: Figure): Pair | undefined => {
147
+ const marked = [first, second].filter((figure) => markOf(figure, text.marks) !== undefined);
148
+ if (marked.length > 1) return undefined;
149
+ const base = marked[0] ?? datedEarlier(text, first, second);
150
+ if (base === undefined) return undefined;
151
+ return { base, current: base === first ? second : first };
152
+ };
153
+
154
+ /** Nothing between the later value and the rate that makes the rate another one's: a value, another subject, another base. */
155
+ const leadsTo = (text: Reading, second: Figure): boolean => {
156
+ const gap = gapBetween(second, text.rate);
157
+ if (gap.start > gap.end || gapLength(text.source, gap) > PAIR_REACH) return false;
158
+ return ![...text.figures, ...text.breaks, ...text.marks].some((span) => within(gap, span));
159
+ };
160
+
161
+ /** Two values of one subject written close, with no rate between them (「売上は100万円、費用は150万円」 is two subjects). */
162
+ const standTogether = (text: Reading, first: Figure, second: Figure): boolean => {
163
+ const gap = gapBetween(first, second);
164
+ const inGap = (span: Span): boolean => within(gap, span);
165
+ if (gapLength(text.source, gap) > PAIR_GAP || text.rates.some(inGap)) return false;
166
+ return !text.breaks.some((word) => !word.beforeRateOnly && inGap(word));
167
+ };
168
+
169
+ /** The two values written together right before the rate (「昨年の100万円から今年は150万円になり、前年比20%の増加」). */
170
+ const beforeRate = (text: Reading): Pair | undefined => {
171
+ const pairs = text.figures.flatMap((first, index) => {
172
+ const second = text.figures.slice(index + 1).find((figure) => figure.unit === first.unit);
173
+ const pair = second !== undefined && standTogether(text, first, second) && leadsTo(text, second) ? pairOf(text, first, second) : undefined;
174
+ return pair === undefined ? [] : [pair];
175
+ });
176
+ const [pair] = pairs;
177
+ return pairs.length === 1 ? pair : undefined;
178
+ };
179
+
180
+ /**
181
+ * The sentence's one rate with a word of direction beside it, a word counting for the rate it stands nearest. A percentage
182
+ * without one (「20%の増加、利益率は10%」) is about something else.
183
+ */
184
+ const readingIn = (text: ChangeText, sentence: Span): Reading | undefined => {
185
+ const inSentence = (span: Span): boolean => within(sentence, span);
186
+ const directions = text.directions.filter(inSentence);
187
+ const rates = text.rates.filter(inSentence);
188
+ const nearestTo = (rate: Rate, direction: Direction): boolean => rates.every((other) => distance(direction, rate) <= distance(direction, other));
189
+ const signed = rates.flatMap((rate) => {
190
+ const sign = signNear(
191
+ rate,
192
+ directions.filter((direction) => nearestTo(rate, direction)),
193
+ );
194
+ return sign === undefined ? [] : [{ rate, sign }];
195
+ });
196
+ const [only] = signed;
197
+ if (signed.length !== 1 || only === undefined) return undefined;
198
+ const parts = {
199
+ figures: text.figures.filter(inSentence).toSorted((left, right) => left.start - right.start),
200
+ periods: text.periods.filter(inSentence),
201
+ breaks: text.breaks.filter(inSentence),
202
+ };
203
+ return { ...text, ...parts, ...only, rates };
204
+ };
205
+
206
+ const issueIn = (text: ChangeText, sentence: Span): StructureIssue[] => {
207
+ const reading = readingIn(text, sentence);
208
+ const pair = reading === undefined ? undefined : (besideRate(reading) ?? beforeRate(reading));
209
+ const range = pair === undefined ? undefined : rateRange(pair.base, pair.current);
210
+ if (reading === undefined || pair === undefined || range === undefined) return [];
211
+ const { rate, sign } = reading;
95
212
  const written = sign * rate.value;
96
213
  const slack = HALF * DECIMAL_BASE ** -rate.decimals;
97
214
  if (written >= range[0] - slack && written <= range[1] + slack) return [];
98
- const computed = Math.abs((current.value / base.value - 1) * PERCENT).toFixed(rate.decimals);
215
+ const computed = Math.abs((pair.current.value / pair.base.value - 1) * PERCENT).toFixed(rate.decimals);
99
216
  return [{ offset: rate.start, values: { rate: String(rate.value), computed } }];
100
217
  };
101
218
 
102
- /** Each sentence with one rate of change, one direction, one marked earlier value and one other value in its unit, that disagree. */
219
+ /**
220
+ * Each sentence with one rate of change and its direction, and the two values it is computed from, that disagree: the
221
+ * earlier value marked beside the rate, or the two values written together right before it.
222
+ */
103
223
  export const changeRateMismatches = (text: ChangeText): StructureIssue[] => text.sentences.flatMap((sentence) => issueIn(text, sentence));