slopless 0.2.28 → 0.2.30
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/presets/everything.js +1 -0
- package/dist/registries/words.js +2 -0
- package/dist/reporting/reports.js +3 -0
- package/dist/rules/private/textlint-rule-builders.js +4 -1
- package/dist/rules/words/data/quietly-context.json +694 -0
- package/dist/rules/words/private/quietly-clause.js +60 -0
- package/dist/rules/words/private/quietly-context.js +163 -0
- package/dist/rules/words/private/quietly-evidence.js +68 -0
- package/dist/rules/words/quietly-filler.js +21 -0
- package/dist/shared/text/document.js +2 -2
- package/dist/shared/text/sections.js +36 -11
- package/dist/shared/text/traverse.js +10 -1
- package/package.json +2 -1
package/dist/registries/words.js
CHANGED
|
@@ -3,6 +3,7 @@ import hedgeStacking from "../rules/words/hedge-stacking.js";
|
|
|
3
3
|
import llmVocabularyDensity from "../rules/words/llm-vocabulary-density.js";
|
|
4
4
|
import llmVocabulary from "../rules/words/llm-vocabulary.js";
|
|
5
5
|
import prohibitedWords from "../rules/words/prohibited-words.js";
|
|
6
|
+
import quietlyFiller from "../rules/words/quietly-filler.js";
|
|
6
7
|
import quietlyOveruse from "../rules/words/quietly-overuse.js";
|
|
7
8
|
import simplicity from "../rules/words/simplicity.js";
|
|
8
9
|
export const wordRules = {
|
|
@@ -11,6 +12,7 @@ export const wordRules = {
|
|
|
11
12
|
"llm-vocabulary-density": llmVocabularyDensity,
|
|
12
13
|
"llm-vocabulary": llmVocabulary,
|
|
13
14
|
"prohibited-words": prohibitedWords,
|
|
15
|
+
"quietly-filler": quietlyFiller,
|
|
14
16
|
"quietly-overuse": quietlyOveruse,
|
|
15
17
|
simplicity
|
|
16
18
|
};
|
|
@@ -133,6 +133,9 @@ export function reportsForPolicy(units, detections, policy, formatMessage) {
|
|
|
133
133
|
message: "",
|
|
134
134
|
range: unit?.sourceRangeFor(detection.range) ?? detection.range,
|
|
135
135
|
ruleId: detection.ruleId,
|
|
136
|
+
...(policy.severity === undefined
|
|
137
|
+
? {}
|
|
138
|
+
: { severity: policy.severity }),
|
|
136
139
|
unitId: detection.unitId
|
|
137
140
|
};
|
|
138
141
|
});
|
|
@@ -18,7 +18,10 @@ export function oneToOneRule(input) {
|
|
|
18
18
|
return defineTextlintRule({
|
|
19
19
|
detector: detector(input),
|
|
20
20
|
formatMessage: input.formatMessage,
|
|
21
|
-
reportPolicy: {
|
|
21
|
+
reportPolicy: {
|
|
22
|
+
kind: "one-to-one",
|
|
23
|
+
...(input.severity === undefined ? {} : { severity: input.severity })
|
|
24
|
+
},
|
|
22
25
|
units: (document) => {
|
|
23
26
|
switch (input.unitKind) {
|
|
24
27
|
case "document":
|
|
@@ -0,0 +1,694 @@
|
|
|
1
|
+
{
|
|
2
|
+
"detachedCompanionWords": ["slowly"],
|
|
3
|
+
"detachedExplanationWords": ["ways"],
|
|
4
|
+
"auxiliaries": [
|
|
5
|
+
"am",
|
|
6
|
+
"are",
|
|
7
|
+
"be",
|
|
8
|
+
"been",
|
|
9
|
+
"being",
|
|
10
|
+
"can",
|
|
11
|
+
"could",
|
|
12
|
+
"did",
|
|
13
|
+
"do",
|
|
14
|
+
"does",
|
|
15
|
+
"had",
|
|
16
|
+
"has",
|
|
17
|
+
"have",
|
|
18
|
+
"is",
|
|
19
|
+
"may",
|
|
20
|
+
"might",
|
|
21
|
+
"must",
|
|
22
|
+
"should",
|
|
23
|
+
"was",
|
|
24
|
+
"were",
|
|
25
|
+
"will",
|
|
26
|
+
"would"
|
|
27
|
+
],
|
|
28
|
+
"evaluativeWords": [
|
|
29
|
+
"consequential",
|
|
30
|
+
"dynamic",
|
|
31
|
+
"effective",
|
|
32
|
+
"heartbreaking",
|
|
33
|
+
"important",
|
|
34
|
+
"impressive",
|
|
35
|
+
"influential",
|
|
36
|
+
"powerful",
|
|
37
|
+
"remarkable",
|
|
38
|
+
"revolutionary",
|
|
39
|
+
"significant",
|
|
40
|
+
"stylish",
|
|
41
|
+
"transformative"
|
|
42
|
+
],
|
|
43
|
+
"abstractChangeWords": [
|
|
44
|
+
"abandon",
|
|
45
|
+
"abandoned",
|
|
46
|
+
"abandons",
|
|
47
|
+
"alter",
|
|
48
|
+
"altered",
|
|
49
|
+
"alters",
|
|
50
|
+
"arrive",
|
|
51
|
+
"arrived",
|
|
52
|
+
"arrives",
|
|
53
|
+
"assemble",
|
|
54
|
+
"assembled",
|
|
55
|
+
"assembles",
|
|
56
|
+
"assembling",
|
|
57
|
+
"atrophied",
|
|
58
|
+
"atrophies",
|
|
59
|
+
"atrophy",
|
|
60
|
+
"balloon",
|
|
61
|
+
"ballooned",
|
|
62
|
+
"balloons",
|
|
63
|
+
"became",
|
|
64
|
+
"become",
|
|
65
|
+
"becomes",
|
|
66
|
+
"changed",
|
|
67
|
+
"changes",
|
|
68
|
+
"changing",
|
|
69
|
+
"climbed",
|
|
70
|
+
"climbs",
|
|
71
|
+
"compounded",
|
|
72
|
+
"compounds",
|
|
73
|
+
"degraded",
|
|
74
|
+
"degrades",
|
|
75
|
+
"degrading",
|
|
76
|
+
"disappear",
|
|
77
|
+
"disappeared",
|
|
78
|
+
"disappearing",
|
|
79
|
+
"disappears",
|
|
80
|
+
"discard",
|
|
81
|
+
"discarded",
|
|
82
|
+
"discarding",
|
|
83
|
+
"discards",
|
|
84
|
+
"doubled",
|
|
85
|
+
"doubles",
|
|
86
|
+
"ended",
|
|
87
|
+
"ends",
|
|
88
|
+
"erode",
|
|
89
|
+
"eroded",
|
|
90
|
+
"erodes",
|
|
91
|
+
"escalated",
|
|
92
|
+
"escalates",
|
|
93
|
+
"evolved",
|
|
94
|
+
"evolves",
|
|
95
|
+
"lose",
|
|
96
|
+
"loses",
|
|
97
|
+
"lost",
|
|
98
|
+
"moved",
|
|
99
|
+
"moves",
|
|
100
|
+
"redefined",
|
|
101
|
+
"redefines",
|
|
102
|
+
"reshaped",
|
|
103
|
+
"reshapes",
|
|
104
|
+
"reshaping",
|
|
105
|
+
"revolutionized",
|
|
106
|
+
"revolutionizes",
|
|
107
|
+
"revolutionizing",
|
|
108
|
+
"shift",
|
|
109
|
+
"shifted",
|
|
110
|
+
"shifting",
|
|
111
|
+
"shifts",
|
|
112
|
+
"stopped",
|
|
113
|
+
"stops",
|
|
114
|
+
"survive",
|
|
115
|
+
"survived",
|
|
116
|
+
"survives",
|
|
117
|
+
"surviving",
|
|
118
|
+
"transformed",
|
|
119
|
+
"transforms",
|
|
120
|
+
"trend",
|
|
121
|
+
"trended",
|
|
122
|
+
"trending",
|
|
123
|
+
"trends",
|
|
124
|
+
"widened",
|
|
125
|
+
"widens",
|
|
126
|
+
"wither",
|
|
127
|
+
"withered",
|
|
128
|
+
"withering",
|
|
129
|
+
"withers"
|
|
130
|
+
],
|
|
131
|
+
"strongAbstractChangeWords": [
|
|
132
|
+
"atrophied",
|
|
133
|
+
"atrophies",
|
|
134
|
+
"atrophy",
|
|
135
|
+
"balloon",
|
|
136
|
+
"ballooned",
|
|
137
|
+
"balloons",
|
|
138
|
+
"compounded",
|
|
139
|
+
"compounds",
|
|
140
|
+
"degraded",
|
|
141
|
+
"degrades",
|
|
142
|
+
"degrading",
|
|
143
|
+
"disappear",
|
|
144
|
+
"disappeared",
|
|
145
|
+
"disappearing",
|
|
146
|
+
"disappears",
|
|
147
|
+
"eroded",
|
|
148
|
+
"erodes",
|
|
149
|
+
"redefined",
|
|
150
|
+
"redefines",
|
|
151
|
+
"reshaped",
|
|
152
|
+
"reshapes",
|
|
153
|
+
"reshaping",
|
|
154
|
+
"revolutionized",
|
|
155
|
+
"revolutionizes",
|
|
156
|
+
"revolutionizing",
|
|
157
|
+
"transformed",
|
|
158
|
+
"transforms",
|
|
159
|
+
"widened",
|
|
160
|
+
"widens",
|
|
161
|
+
"wither",
|
|
162
|
+
"withered",
|
|
163
|
+
"withering",
|
|
164
|
+
"withers"
|
|
165
|
+
],
|
|
166
|
+
"abstractSubjectWords": [
|
|
167
|
+
"assumption",
|
|
168
|
+
"assumptions",
|
|
169
|
+
"baseline",
|
|
170
|
+
"build",
|
|
171
|
+
"capacity",
|
|
172
|
+
"category",
|
|
173
|
+
"change",
|
|
174
|
+
"charge",
|
|
175
|
+
"communities",
|
|
176
|
+
"constraint",
|
|
177
|
+
"conversation",
|
|
178
|
+
"cost",
|
|
179
|
+
"curiosity",
|
|
180
|
+
"data",
|
|
181
|
+
"era",
|
|
182
|
+
"expectations",
|
|
183
|
+
"gap",
|
|
184
|
+
"gate",
|
|
185
|
+
"health",
|
|
186
|
+
"improvement",
|
|
187
|
+
"improvements",
|
|
188
|
+
"inconsistency",
|
|
189
|
+
"industry",
|
|
190
|
+
"infrastructure",
|
|
191
|
+
"landscape",
|
|
192
|
+
"market",
|
|
193
|
+
"matrix",
|
|
194
|
+
"model",
|
|
195
|
+
"partnership",
|
|
196
|
+
"performance",
|
|
197
|
+
"pieces",
|
|
198
|
+
"platform",
|
|
199
|
+
"principle",
|
|
200
|
+
"process",
|
|
201
|
+
"product",
|
|
202
|
+
"products",
|
|
203
|
+
"profession",
|
|
204
|
+
"project",
|
|
205
|
+
"projects",
|
|
206
|
+
"quality",
|
|
207
|
+
"review",
|
|
208
|
+
"search",
|
|
209
|
+
"shift",
|
|
210
|
+
"signal",
|
|
211
|
+
"space",
|
|
212
|
+
"spend",
|
|
213
|
+
"standard",
|
|
214
|
+
"strategy",
|
|
215
|
+
"subscriber",
|
|
216
|
+
"subscribers",
|
|
217
|
+
"system",
|
|
218
|
+
"systems",
|
|
219
|
+
"technology",
|
|
220
|
+
"times",
|
|
221
|
+
"trust",
|
|
222
|
+
"volume",
|
|
223
|
+
"web",
|
|
224
|
+
"work"
|
|
225
|
+
],
|
|
226
|
+
"hiddenHarmWords": [
|
|
227
|
+
"bleed",
|
|
228
|
+
"bleeding",
|
|
229
|
+
"block",
|
|
230
|
+
"blocked",
|
|
231
|
+
"blocking",
|
|
232
|
+
"break",
|
|
233
|
+
"breaking",
|
|
234
|
+
"breaks",
|
|
235
|
+
"destroy",
|
|
236
|
+
"destroyed",
|
|
237
|
+
"destroying",
|
|
238
|
+
"destroys",
|
|
239
|
+
"drown",
|
|
240
|
+
"drowned",
|
|
241
|
+
"drowning",
|
|
242
|
+
"drowns",
|
|
243
|
+
"fail",
|
|
244
|
+
"failed",
|
|
245
|
+
"failing",
|
|
246
|
+
"fails",
|
|
247
|
+
"fix",
|
|
248
|
+
"fixed",
|
|
249
|
+
"fixes",
|
|
250
|
+
"hurt",
|
|
251
|
+
"hurting",
|
|
252
|
+
"hurts",
|
|
253
|
+
"outsource",
|
|
254
|
+
"outsourced",
|
|
255
|
+
"outsources",
|
|
256
|
+
"outsourcing",
|
|
257
|
+
"poison",
|
|
258
|
+
"poisoned",
|
|
259
|
+
"poisoning",
|
|
260
|
+
"poisons",
|
|
261
|
+
"rot",
|
|
262
|
+
"rots",
|
|
263
|
+
"rotting",
|
|
264
|
+
"ruin",
|
|
265
|
+
"ruined",
|
|
266
|
+
"ruining",
|
|
267
|
+
"ruins",
|
|
268
|
+
"sabotage",
|
|
269
|
+
"sabotaged",
|
|
270
|
+
"sabotages",
|
|
271
|
+
"sabotaging",
|
|
272
|
+
"steer",
|
|
273
|
+
"steered",
|
|
274
|
+
"steering",
|
|
275
|
+
"steers",
|
|
276
|
+
"stop",
|
|
277
|
+
"stopped",
|
|
278
|
+
"stopping",
|
|
279
|
+
"stops",
|
|
280
|
+
"tank",
|
|
281
|
+
"tanked",
|
|
282
|
+
"tanking",
|
|
283
|
+
"tanks",
|
|
284
|
+
"throttle",
|
|
285
|
+
"throttled",
|
|
286
|
+
"throttles",
|
|
287
|
+
"throttling",
|
|
288
|
+
"violate",
|
|
289
|
+
"violates",
|
|
290
|
+
"violating",
|
|
291
|
+
"wrong"
|
|
292
|
+
],
|
|
293
|
+
"backgroundActionWords": [
|
|
294
|
+
"carve",
|
|
295
|
+
"carved",
|
|
296
|
+
"carves",
|
|
297
|
+
"carving",
|
|
298
|
+
"did",
|
|
299
|
+
"do",
|
|
300
|
+
"does",
|
|
301
|
+
"doing",
|
|
302
|
+
"embedded",
|
|
303
|
+
"everywhere",
|
|
304
|
+
"humming",
|
|
305
|
+
"live",
|
|
306
|
+
"lived",
|
|
307
|
+
"lives",
|
|
308
|
+
"living",
|
|
309
|
+
"made",
|
|
310
|
+
"make",
|
|
311
|
+
"makes",
|
|
312
|
+
"making",
|
|
313
|
+
"manage",
|
|
314
|
+
"managed",
|
|
315
|
+
"manages",
|
|
316
|
+
"managing",
|
|
317
|
+
"operate",
|
|
318
|
+
"operated",
|
|
319
|
+
"operates",
|
|
320
|
+
"operating",
|
|
321
|
+
"pay",
|
|
322
|
+
"paying",
|
|
323
|
+
"pays",
|
|
324
|
+
"perform",
|
|
325
|
+
"performed",
|
|
326
|
+
"performing",
|
|
327
|
+
"performs",
|
|
328
|
+
"power",
|
|
329
|
+
"powered",
|
|
330
|
+
"powering",
|
|
331
|
+
"powers",
|
|
332
|
+
"probe",
|
|
333
|
+
"probed",
|
|
334
|
+
"probes",
|
|
335
|
+
"probing",
|
|
336
|
+
"process",
|
|
337
|
+
"processed",
|
|
338
|
+
"processes",
|
|
339
|
+
"processing",
|
|
340
|
+
"run",
|
|
341
|
+
"running",
|
|
342
|
+
"runs",
|
|
343
|
+
"solve",
|
|
344
|
+
"solved",
|
|
345
|
+
"solves",
|
|
346
|
+
"solving",
|
|
347
|
+
"use",
|
|
348
|
+
"used",
|
|
349
|
+
"uses",
|
|
350
|
+
"using",
|
|
351
|
+
"work",
|
|
352
|
+
"worked",
|
|
353
|
+
"working",
|
|
354
|
+
"works"
|
|
355
|
+
],
|
|
356
|
+
"backgroundSignificanceWords": [
|
|
357
|
+
"around",
|
|
358
|
+
"background",
|
|
359
|
+
"behalf",
|
|
360
|
+
"behind",
|
|
361
|
+
"bill",
|
|
362
|
+
"easier",
|
|
363
|
+
"entire",
|
|
364
|
+
"everything",
|
|
365
|
+
"everywhere",
|
|
366
|
+
"half",
|
|
367
|
+
"hardest",
|
|
368
|
+
"important",
|
|
369
|
+
"incredible",
|
|
370
|
+
"industries",
|
|
371
|
+
"infrastructure",
|
|
372
|
+
"internet",
|
|
373
|
+
"life",
|
|
374
|
+
"many",
|
|
375
|
+
"model",
|
|
376
|
+
"most",
|
|
377
|
+
"readable",
|
|
378
|
+
"real",
|
|
379
|
+
"scenes",
|
|
380
|
+
"sideways",
|
|
381
|
+
"time",
|
|
382
|
+
"trillion",
|
|
383
|
+
"trillions",
|
|
384
|
+
"whole",
|
|
385
|
+
"wisdom",
|
|
386
|
+
"wrong"
|
|
387
|
+
],
|
|
388
|
+
"trendActionWords": [
|
|
389
|
+
"adopt",
|
|
390
|
+
"adopted",
|
|
391
|
+
"adopting",
|
|
392
|
+
"adopts",
|
|
393
|
+
"build",
|
|
394
|
+
"building",
|
|
395
|
+
"builds",
|
|
396
|
+
"built",
|
|
397
|
+
"create",
|
|
398
|
+
"created",
|
|
399
|
+
"creates",
|
|
400
|
+
"creating",
|
|
401
|
+
"drop",
|
|
402
|
+
"dropped",
|
|
403
|
+
"dropping",
|
|
404
|
+
"drops",
|
|
405
|
+
"integrate",
|
|
406
|
+
"integrated",
|
|
407
|
+
"integrates",
|
|
408
|
+
"integrating",
|
|
409
|
+
"kill",
|
|
410
|
+
"killed",
|
|
411
|
+
"killing",
|
|
412
|
+
"kills",
|
|
413
|
+
"replace",
|
|
414
|
+
"replaced",
|
|
415
|
+
"replaces",
|
|
416
|
+
"replacing",
|
|
417
|
+
"stop",
|
|
418
|
+
"stopped",
|
|
419
|
+
"stopping",
|
|
420
|
+
"stops",
|
|
421
|
+
"take",
|
|
422
|
+
"takes",
|
|
423
|
+
"taking",
|
|
424
|
+
"took",
|
|
425
|
+
"use",
|
|
426
|
+
"used",
|
|
427
|
+
"uses",
|
|
428
|
+
"using"
|
|
429
|
+
],
|
|
430
|
+
"trendSubjectWords": [
|
|
431
|
+
"agents",
|
|
432
|
+
"companies",
|
|
433
|
+
"developers",
|
|
434
|
+
"group",
|
|
435
|
+
"groups",
|
|
436
|
+
"industry",
|
|
437
|
+
"models",
|
|
438
|
+
"organizations",
|
|
439
|
+
"platform",
|
|
440
|
+
"platforms",
|
|
441
|
+
"products",
|
|
442
|
+
"publisher",
|
|
443
|
+
"publishers",
|
|
444
|
+
"site",
|
|
445
|
+
"sites",
|
|
446
|
+
"systems",
|
|
447
|
+
"team",
|
|
448
|
+
"teams",
|
|
449
|
+
"technologies",
|
|
450
|
+
"technology",
|
|
451
|
+
"tools",
|
|
452
|
+
"web"
|
|
453
|
+
],
|
|
454
|
+
"titleContextWords": [
|
|
455
|
+
"circled",
|
|
456
|
+
"includes",
|
|
457
|
+
"lists",
|
|
458
|
+
"named",
|
|
459
|
+
"performed",
|
|
460
|
+
"phrase",
|
|
461
|
+
"quoted",
|
|
462
|
+
"titled"
|
|
463
|
+
],
|
|
464
|
+
"normalMannerWords": [
|
|
465
|
+
"applaud",
|
|
466
|
+
"applauded",
|
|
467
|
+
"applauding",
|
|
468
|
+
"ask",
|
|
469
|
+
"asked",
|
|
470
|
+
"asking",
|
|
471
|
+
"breathe",
|
|
472
|
+
"breathed",
|
|
473
|
+
"breathing",
|
|
474
|
+
"close",
|
|
475
|
+
"closed",
|
|
476
|
+
"closing",
|
|
477
|
+
"enter",
|
|
478
|
+
"entered",
|
|
479
|
+
"entering",
|
|
480
|
+
"fall",
|
|
481
|
+
"falling",
|
|
482
|
+
"falls",
|
|
483
|
+
"flew",
|
|
484
|
+
"fly",
|
|
485
|
+
"flying",
|
|
486
|
+
"lay",
|
|
487
|
+
"leave",
|
|
488
|
+
"leaves",
|
|
489
|
+
"leaving",
|
|
490
|
+
"lie",
|
|
491
|
+
"look",
|
|
492
|
+
"looked",
|
|
493
|
+
"looking",
|
|
494
|
+
"move",
|
|
495
|
+
"moved",
|
|
496
|
+
"moving",
|
|
497
|
+
"open",
|
|
498
|
+
"opened",
|
|
499
|
+
"opening",
|
|
500
|
+
"play",
|
|
501
|
+
"played",
|
|
502
|
+
"playing",
|
|
503
|
+
"read",
|
|
504
|
+
"rest",
|
|
505
|
+
"rested",
|
|
506
|
+
"resting",
|
|
507
|
+
"said",
|
|
508
|
+
"sat",
|
|
509
|
+
"say",
|
|
510
|
+
"saying",
|
|
511
|
+
"sing",
|
|
512
|
+
"singing",
|
|
513
|
+
"sit",
|
|
514
|
+
"sitting",
|
|
515
|
+
"speak",
|
|
516
|
+
"speaking",
|
|
517
|
+
"spoke",
|
|
518
|
+
"stand",
|
|
519
|
+
"standing",
|
|
520
|
+
"stood",
|
|
521
|
+
"wait",
|
|
522
|
+
"waited",
|
|
523
|
+
"waiting",
|
|
524
|
+
"walk",
|
|
525
|
+
"walked",
|
|
526
|
+
"walking",
|
|
527
|
+
"watch",
|
|
528
|
+
"watched",
|
|
529
|
+
"watching"
|
|
530
|
+
],
|
|
531
|
+
"privateActionWords": [
|
|
532
|
+
"approved",
|
|
533
|
+
"approving",
|
|
534
|
+
"assume",
|
|
535
|
+
"assumed",
|
|
536
|
+
"assuming",
|
|
537
|
+
"counted",
|
|
538
|
+
"counting",
|
|
539
|
+
"donated",
|
|
540
|
+
"edited",
|
|
541
|
+
"editing",
|
|
542
|
+
"investigated",
|
|
543
|
+
"investigating",
|
|
544
|
+
"interviewed",
|
|
545
|
+
"interviewing",
|
|
546
|
+
"launched",
|
|
547
|
+
"launching",
|
|
548
|
+
"negotiated",
|
|
549
|
+
"negotiating",
|
|
550
|
+
"order",
|
|
551
|
+
"ordered",
|
|
552
|
+
"ordering",
|
|
553
|
+
"relied",
|
|
554
|
+
"relying",
|
|
555
|
+
"removed",
|
|
556
|
+
"removing",
|
|
557
|
+
"resigned",
|
|
558
|
+
"settled",
|
|
559
|
+
"settling"
|
|
560
|
+
],
|
|
561
|
+
"specifiedTechnicalWords": [
|
|
562
|
+
"desync",
|
|
563
|
+
"desynced",
|
|
564
|
+
"desyncs",
|
|
565
|
+
"disagreed",
|
|
566
|
+
"disagrees",
|
|
567
|
+
"drop",
|
|
568
|
+
"dropped",
|
|
569
|
+
"dropping",
|
|
570
|
+
"drops",
|
|
571
|
+
"fail",
|
|
572
|
+
"failed",
|
|
573
|
+
"failing",
|
|
574
|
+
"fails",
|
|
575
|
+
"fix",
|
|
576
|
+
"fixed",
|
|
577
|
+
"fixes",
|
|
578
|
+
"fixing",
|
|
579
|
+
"ignored",
|
|
580
|
+
"ignores",
|
|
581
|
+
"misalign",
|
|
582
|
+
"misaligned",
|
|
583
|
+
"misaligns",
|
|
584
|
+
"miscounted",
|
|
585
|
+
"miscounts",
|
|
586
|
+
"passed",
|
|
587
|
+
"passes",
|
|
588
|
+
"stop",
|
|
589
|
+
"stopped",
|
|
590
|
+
"stopping",
|
|
591
|
+
"stops",
|
|
592
|
+
"sync",
|
|
593
|
+
"synced",
|
|
594
|
+
"syncing",
|
|
595
|
+
"truncated",
|
|
596
|
+
"truncates",
|
|
597
|
+
"truncating",
|
|
598
|
+
"wrong"
|
|
599
|
+
],
|
|
600
|
+
"technicalEvidenceWords": [
|
|
601
|
+
"alarm",
|
|
602
|
+
"application",
|
|
603
|
+
"audit",
|
|
604
|
+
"because",
|
|
605
|
+
"canonical",
|
|
606
|
+
"channel",
|
|
607
|
+
"code",
|
|
608
|
+
"controller",
|
|
609
|
+
"database",
|
|
610
|
+
"dba",
|
|
611
|
+
"error",
|
|
612
|
+
"events",
|
|
613
|
+
"field",
|
|
614
|
+
"index",
|
|
615
|
+
"logged",
|
|
616
|
+
"maintenance",
|
|
617
|
+
"malformed",
|
|
618
|
+
"mechanism",
|
|
619
|
+
"mode",
|
|
620
|
+
"multiprocessing",
|
|
621
|
+
"process",
|
|
622
|
+
"rate",
|
|
623
|
+
"records",
|
|
624
|
+
"rows",
|
|
625
|
+
"setting",
|
|
626
|
+
"snapshot",
|
|
627
|
+
"strict",
|
|
628
|
+
"string",
|
|
629
|
+
"windows"
|
|
630
|
+
],
|
|
631
|
+
"hiddenHarmPairGroups": [
|
|
632
|
+
{
|
|
633
|
+
"actions": ["accept", "accepted", "accepting", "accepts"],
|
|
634
|
+
"markers": ["just", "way"]
|
|
635
|
+
},
|
|
636
|
+
{
|
|
637
|
+
"actions": ["fall", "falling", "falls", "fell"],
|
|
638
|
+
"markers": ["apart"]
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
"actions": ["go", "goes", "going", "gone", "went"],
|
|
642
|
+
"markers": ["wrong"]
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
"actions": ["inherit", "inherited", "inheriting", "inherits"],
|
|
646
|
+
"markers": [
|
|
647
|
+
"code",
|
|
648
|
+
"file",
|
|
649
|
+
"instruction",
|
|
650
|
+
"instructions",
|
|
651
|
+
"problem",
|
|
652
|
+
"problems",
|
|
653
|
+
"added"
|
|
654
|
+
]
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
"actions": ["take", "takes", "taking", "took"],
|
|
658
|
+
"markers": ["money", "most", "time", "cost", "costs"]
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
"actions": ["cost", "costing", "costs"],
|
|
662
|
+
"markers": ["money", "most", "time"]
|
|
663
|
+
}
|
|
664
|
+
],
|
|
665
|
+
"detachedResultWords": [
|
|
666
|
+
"arrive",
|
|
667
|
+
"arrived",
|
|
668
|
+
"arrives",
|
|
669
|
+
"complete",
|
|
670
|
+
"completed",
|
|
671
|
+
"completes",
|
|
672
|
+
"finish",
|
|
673
|
+
"finished",
|
|
674
|
+
"finishes"
|
|
675
|
+
],
|
|
676
|
+
"abstractChangePairGroups": [
|
|
677
|
+
{
|
|
678
|
+
"actions": ["continue", "continued", "continues", "continuing"],
|
|
679
|
+
"markers": ["exist", "not"]
|
|
680
|
+
}
|
|
681
|
+
],
|
|
682
|
+
"trendPhraseGroups": [
|
|
683
|
+
{
|
|
684
|
+
"actions": ["build", "building", "builds", "built"],
|
|
685
|
+
"markers": ["different", "something"]
|
|
686
|
+
}
|
|
687
|
+
],
|
|
688
|
+
"backgroundPhraseGroups": [
|
|
689
|
+
{
|
|
690
|
+
"actions": ["sit", "sits", "sitting", "sat"],
|
|
691
|
+
"markers": ["suddenly", "until"]
|
|
692
|
+
}
|
|
693
|
+
]
|
|
694
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
const BOUNDARY_WORDS = new Set([
|
|
2
|
+
"after",
|
|
3
|
+
"although",
|
|
4
|
+
"because",
|
|
5
|
+
"before",
|
|
6
|
+
"but",
|
|
7
|
+
"if",
|
|
8
|
+
"once",
|
|
9
|
+
"since",
|
|
10
|
+
"so",
|
|
11
|
+
"that",
|
|
12
|
+
"though",
|
|
13
|
+
"unless",
|
|
14
|
+
"when",
|
|
15
|
+
"whenever",
|
|
16
|
+
"where",
|
|
17
|
+
"whereas",
|
|
18
|
+
"while",
|
|
19
|
+
"which",
|
|
20
|
+
"who"
|
|
21
|
+
]);
|
|
22
|
+
function hasBoundaryPunctuation(text, left, right) {
|
|
23
|
+
const between = text.slice(left.end, right.start);
|
|
24
|
+
return (between.includes(";") ||
|
|
25
|
+
between.includes(":") ||
|
|
26
|
+
between.includes(".") ||
|
|
27
|
+
between.includes("!") ||
|
|
28
|
+
between.includes("?"));
|
|
29
|
+
}
|
|
30
|
+
export function quietlyClauseFor(text, tokens, index) {
|
|
31
|
+
let start = 0;
|
|
32
|
+
for (let cursor = index - 1; cursor >= 0; cursor -= 1) {
|
|
33
|
+
const token = tokens[cursor];
|
|
34
|
+
const next = tokens[cursor + 1];
|
|
35
|
+
if (token === undefined ||
|
|
36
|
+
next === undefined ||
|
|
37
|
+
BOUNDARY_WORDS.has(token.normalized) ||
|
|
38
|
+
hasBoundaryPunctuation(text, token, next)) {
|
|
39
|
+
start = cursor + 1;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
let end = tokens.length;
|
|
44
|
+
for (let cursor = index + 1; cursor < tokens.length; cursor += 1) {
|
|
45
|
+
const previous = tokens[cursor - 1];
|
|
46
|
+
const token = tokens[cursor];
|
|
47
|
+
if (previous === undefined ||
|
|
48
|
+
token === undefined ||
|
|
49
|
+
BOUNDARY_WORDS.has(token.normalized) ||
|
|
50
|
+
hasBoundaryPunctuation(text, previous, token)) {
|
|
51
|
+
end = cursor;
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
index: index - start,
|
|
57
|
+
tokens: tokens.slice(start, end)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=quietly-clause.js.map
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { wordTokens } from "../../../shared/text/tokens.js";
|
|
2
|
+
import quietlyContextVocabulary from "../data/quietly-context.json" with { type: "json" };
|
|
3
|
+
import { quietlyClauseFor } from "./quietly-clause.js";
|
|
4
|
+
import { hasDetachedCompanion, hasInformativeChangeEvidence, hasLinkedTechnicalEvidence, hasSpecifiedTechnicalEvidence } from "./quietly-evidence.js";
|
|
5
|
+
const TARGET = "quietly";
|
|
6
|
+
const DETACHED_EXPLANATION_WORDS = new Set(quietlyContextVocabulary.detachedExplanationWords);
|
|
7
|
+
const DETACHED_RESULT_WORDS = new Set(quietlyContextVocabulary.detachedResultWords);
|
|
8
|
+
const AUXILIARIES = new Set(quietlyContextVocabulary.auxiliaries);
|
|
9
|
+
const EVALUATIVE_WORDS = new Set(quietlyContextVocabulary.evaluativeWords);
|
|
10
|
+
const ABSTRACT_CHANGE_WORDS = new Set(quietlyContextVocabulary.abstractChangeWords);
|
|
11
|
+
const STRONG_ABSTRACT_CHANGE_WORDS = new Set(quietlyContextVocabulary.strongAbstractChangeWords);
|
|
12
|
+
const ABSTRACT_SUBJECT_WORDS = new Set(quietlyContextVocabulary.abstractSubjectWords);
|
|
13
|
+
const HIDDEN_HARM_WORDS = new Set(quietlyContextVocabulary.hiddenHarmWords);
|
|
14
|
+
const BACKGROUND_ACTION_WORDS = new Set(quietlyContextVocabulary.backgroundActionWords);
|
|
15
|
+
const BACKGROUND_SIGNIFICANCE_WORDS = new Set(quietlyContextVocabulary.backgroundSignificanceWords);
|
|
16
|
+
const TREND_ACTION_WORDS = new Set(quietlyContextVocabulary.trendActionWords);
|
|
17
|
+
const TREND_SUBJECT_WORDS = new Set(quietlyContextVocabulary.trendSubjectWords);
|
|
18
|
+
const TITLE_CONTEXT_WORDS = new Set(quietlyContextVocabulary.titleContextWords);
|
|
19
|
+
const NORMAL_MANNER_WORDS = new Set(quietlyContextVocabulary.normalMannerWords);
|
|
20
|
+
const PRIVATE_ACTION_WORDS = new Set(quietlyContextVocabulary.privateActionWords);
|
|
21
|
+
const SPECIFIED_TECHNICAL_WORDS = new Set(quietlyContextVocabulary.specifiedTechnicalWords);
|
|
22
|
+
function containsAny(words, candidates) {
|
|
23
|
+
return words.some((word) => candidates.has(word));
|
|
24
|
+
}
|
|
25
|
+
function governingWords(tokens, index) {
|
|
26
|
+
const words = [];
|
|
27
|
+
const after = nextMeaningfulWord(tokens, index);
|
|
28
|
+
if (after !== undefined) {
|
|
29
|
+
words.push(after);
|
|
30
|
+
}
|
|
31
|
+
for (let cursor = index - 1; cursor >= Math.max(0, index - 3); cursor -= 1) {
|
|
32
|
+
const word = tokens[cursor]?.normalized;
|
|
33
|
+
if (word === undefined || AUXILIARIES.has(word)) {
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
words.push(word);
|
|
37
|
+
}
|
|
38
|
+
return words;
|
|
39
|
+
}
|
|
40
|
+
function wordsNear(tokens, index, radius) {
|
|
41
|
+
return tokens
|
|
42
|
+
.slice(Math.max(0, index - radius), index + radius + 1)
|
|
43
|
+
.map((token) => token.normalized);
|
|
44
|
+
}
|
|
45
|
+
function matchesPairGroup(localWords, allWords, groups) {
|
|
46
|
+
return groups.some(({ actions, markers }) => actions.some((word) => localWords.includes(word)) &&
|
|
47
|
+
markers.some((word) => allWords.includes(word)));
|
|
48
|
+
}
|
|
49
|
+
function matchesRequiredPairGroup(localWords, allWords, groups) {
|
|
50
|
+
return groups.some(({ actions, markers }) => actions.some((word) => localWords.includes(word)) &&
|
|
51
|
+
markers.every((word) => allWords.includes(word)));
|
|
52
|
+
}
|
|
53
|
+
function isFirstPersonBuild(tokens, index, localWords, sentenceWords) {
|
|
54
|
+
const before = tokens.slice(0, index).map((token) => token.normalized);
|
|
55
|
+
return (containsAny(localWords, TREND_ACTION_WORDS) &&
|
|
56
|
+
containsAny(sentenceWords, TREND_SUBJECT_WORDS) &&
|
|
57
|
+
(before.includes("i") ||
|
|
58
|
+
before.includes("i've") ||
|
|
59
|
+
before.includes("my") ||
|
|
60
|
+
before.includes("we") ||
|
|
61
|
+
before.includes("we've")));
|
|
62
|
+
}
|
|
63
|
+
function nextMeaningfulWord(tokens, index) {
|
|
64
|
+
for (let cursor = index + 1; cursor < tokens.length; cursor += 1) {
|
|
65
|
+
const word = tokens[cursor]?.normalized;
|
|
66
|
+
if (word !== undefined && !AUXILIARIES.has(word)) {
|
|
67
|
+
return word;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
function isAbstractChangeContext(tokens, index, localWords, contextWords, sentenceWords, sentenceTokens, sentenceIndex) {
|
|
73
|
+
const hasChangePattern = containsAny(localWords, STRONG_ABSTRACT_CHANGE_WORDS) ||
|
|
74
|
+
(containsAny(localWords, ABSTRACT_CHANGE_WORDS) &&
|
|
75
|
+
containsAny(contextWords, ABSTRACT_SUBJECT_WORDS)) ||
|
|
76
|
+
matchesRequiredPairGroup(localWords, sentenceWords, quietlyContextVocabulary.abstractChangePairGroups);
|
|
77
|
+
return (hasChangePattern &&
|
|
78
|
+
!hasInformativeChangeEvidence(tokens, index, sentenceTokens, sentenceIndex));
|
|
79
|
+
}
|
|
80
|
+
function isNormalUse(text, tokens, index, label, sentenceTokens, sentenceIndex) {
|
|
81
|
+
const allWords = tokens.map((token) => token.normalized);
|
|
82
|
+
if (containsAny(wordsNear(tokens, index, 5), TITLE_CONTEXT_WORDS)) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
const localWords = governingWords(tokens, index);
|
|
86
|
+
if ((label === undefined && containsAny(localWords, NORMAL_MANNER_WORDS)) ||
|
|
87
|
+
containsAny(localWords, PRIVATE_ACTION_WORDS)) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
return (containsAny(localWords, SPECIFIED_TECHNICAL_WORDS) &&
|
|
91
|
+
(hasSpecifiedTechnicalEvidence(allWords) ||
|
|
92
|
+
hasLinkedTechnicalEvidence(text, sentenceTokens, sentenceIndex)));
|
|
93
|
+
}
|
|
94
|
+
function contextClassFor(text, tokens, index, sentenceTokens, sentenceIndex) {
|
|
95
|
+
const words = tokens.map((token) => token.normalized);
|
|
96
|
+
const sentenceWords = sentenceTokens.map((token) => token.normalized);
|
|
97
|
+
if (sentenceTokens.length === 1) {
|
|
98
|
+
return "detached-emphasis";
|
|
99
|
+
}
|
|
100
|
+
if (hasDetachedCompanion(text, tokens, index) &&
|
|
101
|
+
(tokens.length <= 8 || containsAny(words, DETACHED_EXPLANATION_WORDS))) {
|
|
102
|
+
return "detached-emphasis";
|
|
103
|
+
}
|
|
104
|
+
const localWords = governingWords(tokens, index);
|
|
105
|
+
const contextWords = wordsNear(tokens, index, 5);
|
|
106
|
+
const token = tokens[index];
|
|
107
|
+
const isTrailingResult = token !== undefined &&
|
|
108
|
+
containsAny(localWords, DETACHED_RESULT_WORDS) &&
|
|
109
|
+
(index === tokens.length - 1 ||
|
|
110
|
+
text.slice(token.end).trimStart().startsWith(":"));
|
|
111
|
+
if (isTrailingResult) {
|
|
112
|
+
return "detached-emphasis";
|
|
113
|
+
}
|
|
114
|
+
const nextWord = nextMeaningfulWord(tokens, index);
|
|
115
|
+
if (nextWord !== undefined && EVALUATIVE_WORDS.has(nextWord)) {
|
|
116
|
+
return "evaluative-intensifier";
|
|
117
|
+
}
|
|
118
|
+
if (containsAny(localWords, HIDDEN_HARM_WORDS) ||
|
|
119
|
+
matchesPairGroup(localWords, wordsNear(tokens, index, 8), quietlyContextVocabulary.hiddenHarmPairGroups)) {
|
|
120
|
+
return "hidden-harm";
|
|
121
|
+
}
|
|
122
|
+
if (isAbstractChangeContext(tokens, index, localWords, contextWords, words, sentenceTokens, sentenceIndex)) {
|
|
123
|
+
return "abstract-change";
|
|
124
|
+
}
|
|
125
|
+
if (containsAny(localWords, BACKGROUND_ACTION_WORDS) &&
|
|
126
|
+
containsAny(contextWords, BACKGROUND_SIGNIFICANCE_WORDS)) {
|
|
127
|
+
return "background-significance";
|
|
128
|
+
}
|
|
129
|
+
if (matchesRequiredPairGroup(localWords, words, quietlyContextVocabulary.backgroundPhraseGroups)) {
|
|
130
|
+
return "background-significance";
|
|
131
|
+
}
|
|
132
|
+
if ((containsAny(words, TREND_SUBJECT_WORDS) &&
|
|
133
|
+
(containsAny(localWords, TREND_ACTION_WORDS) ||
|
|
134
|
+
(index <= 2 && containsAny(words, TREND_ACTION_WORDS)))) ||
|
|
135
|
+
isFirstPersonBuild(tokens, index, localWords, sentenceWords) ||
|
|
136
|
+
matchesRequiredPairGroup(localWords, words, quietlyContextVocabulary.trendPhraseGroups)) {
|
|
137
|
+
return "unannounced-trend";
|
|
138
|
+
}
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
export function findQuietlyContextMatches(text) {
|
|
142
|
+
const tokens = wordTokens(text);
|
|
143
|
+
const matches = [];
|
|
144
|
+
for (let index = 0; index < tokens.length; index += 1) {
|
|
145
|
+
const token = tokens[index];
|
|
146
|
+
if (token?.normalized !== TARGET) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const clause = quietlyClauseFor(text, tokens, index);
|
|
150
|
+
const label = contextClassFor(text, clause.tokens, clause.index, tokens, index);
|
|
151
|
+
if (label === undefined ||
|
|
152
|
+
isNormalUse(text, clause.tokens, clause.index, label, tokens, index)) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
matches.push({
|
|
156
|
+
evidence: token.text,
|
|
157
|
+
label,
|
|
158
|
+
range: { end: token.end, start: token.start }
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return matches;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=quietly-context.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import quietlyContextVocabulary from "../data/quietly-context.json" with { type: "json" };
|
|
2
|
+
const ABSTRACT_CHANGE_WORDS = new Set(quietlyContextVocabulary.abstractChangeWords);
|
|
3
|
+
const STRONG_ABSTRACT_CHANGE_WORDS = new Set(quietlyContextVocabulary.strongAbstractChangeWords);
|
|
4
|
+
const DETACHED_COMPANION_WORDS = new Set(quietlyContextVocabulary.detachedCompanionWords);
|
|
5
|
+
const TECHNICAL_EVIDENCE_WORDS = new Set(quietlyContextVocabulary.technicalEvidenceWords);
|
|
6
|
+
function startsWithDigit(word) {
|
|
7
|
+
const first = word.at(0);
|
|
8
|
+
return first !== undefined && first >= "0" && first <= "9";
|
|
9
|
+
}
|
|
10
|
+
export function hasSpecifiedTechnicalEvidence(words) {
|
|
11
|
+
const evidenceCount = words.filter((word) => TECHNICAL_EVIDENCE_WORDS.has(word)).length;
|
|
12
|
+
return (words.some(startsWithDigit) ||
|
|
13
|
+
words.includes("because") ||
|
|
14
|
+
evidenceCount >= 2);
|
|
15
|
+
}
|
|
16
|
+
export function hasLinkedTechnicalEvidence(text, tokens, index) {
|
|
17
|
+
const following = tokens.slice(index + 1);
|
|
18
|
+
const boundaryIndex = following.findIndex((token) => ["after", "because", "when"].includes(token.normalized));
|
|
19
|
+
const quietToken = tokens[index];
|
|
20
|
+
const colonIndex = quietToken === undefined ? -1 : text.indexOf(":", quietToken.end);
|
|
21
|
+
const evidence = boundaryIndex >= 0
|
|
22
|
+
? following.slice(boundaryIndex + 1)
|
|
23
|
+
: colonIndex >= 0
|
|
24
|
+
? following.filter((token) => token.start > colonIndex)
|
|
25
|
+
: [];
|
|
26
|
+
return ((following[boundaryIndex]?.normalized === "because" &&
|
|
27
|
+
evidence.length >= 3) ||
|
|
28
|
+
hasSpecifiedTechnicalEvidence(evidence.map((token) => token.normalized)));
|
|
29
|
+
}
|
|
30
|
+
export function hasDetachedCompanion(text, tokens, index) {
|
|
31
|
+
const companion = tokens
|
|
32
|
+
.slice(0, index)
|
|
33
|
+
.findLast((token) => DETACHED_COMPANION_WORDS.has(token.normalized));
|
|
34
|
+
const target = tokens[index];
|
|
35
|
+
return (companion !== undefined &&
|
|
36
|
+
target !== undefined &&
|
|
37
|
+
text.slice(companion.end, target.start).includes(","));
|
|
38
|
+
}
|
|
39
|
+
export function hasInformativeChangeEvidence(clauseTokens, clauseIndex, sentenceTokens, sentenceIndex) {
|
|
40
|
+
const clauseWords = clauseTokens.map((token) => token.normalized);
|
|
41
|
+
if (clauseWords.includes("from") && clauseWords.includes("to")) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
const actionIndices = clauseWords.flatMap((word, index) => ABSTRACT_CHANGE_WORDS.has(word) || STRONG_ABSTRACT_CHANGE_WORDS.has(word)
|
|
45
|
+
? [index]
|
|
46
|
+
: []);
|
|
47
|
+
const actionIndex = actionIndices.reduce((nearest, candidate) => nearest === undefined ||
|
|
48
|
+
Math.abs(candidate - clauseIndex) < Math.abs(nearest - clauseIndex)
|
|
49
|
+
? candidate
|
|
50
|
+
: nearest, undefined);
|
|
51
|
+
if (actionIndex !== undefined &&
|
|
52
|
+
clauseWords.slice(actionIndex + 1, actionIndex + 7).some(startsWithDigit)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (actionIndex === undefined) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const sentenceActionIndex = sentenceTokens.findIndex((token) => token.start === clauseTokens[actionIndex]?.start);
|
|
59
|
+
if (sentenceActionIndex < 0) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
const explanation = sentenceTokens.slice(sentenceActionIndex + 1);
|
|
63
|
+
const boundaryIndex = explanation.findIndex((token) => token.normalized === "after" || token.normalized === "because");
|
|
64
|
+
return (sentenceActionIndex <= sentenceIndex &&
|
|
65
|
+
boundaryIndex >= 0 &&
|
|
66
|
+
explanation.length - boundaryIndex > 4);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=quietly-evidence.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { oneToOneRule } from "../private/textlint-rule-builders.js";
|
|
2
|
+
import { findQuietlyContextMatches } from "./private/quietly-context.js";
|
|
3
|
+
const RULE_ID = "words:quietly-filler";
|
|
4
|
+
const rule = oneToOneRule({
|
|
5
|
+
detect: (unit) => findQuietlyContextMatches(unit.text).map((match) => ({
|
|
6
|
+
data: { contextClass: match.label },
|
|
7
|
+
evidence: match.evidence,
|
|
8
|
+
label: match.label,
|
|
9
|
+
range: match.range
|
|
10
|
+
})),
|
|
11
|
+
family: "words",
|
|
12
|
+
formatMessage: (report) => {
|
|
13
|
+
const contextClass = report.detections[0]?.data?.["contextClass"];
|
|
14
|
+
return `"quietly" adds vague hidden significance (${contextClass}). Name the concrete change or remove the adverb.`;
|
|
15
|
+
},
|
|
16
|
+
ruleId: RULE_ID,
|
|
17
|
+
severity: 1,
|
|
18
|
+
unitKind: "sentence"
|
|
19
|
+
});
|
|
20
|
+
export default rule;
|
|
21
|
+
//# sourceMappingURL=quietly-filler.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { allDocumentParagraphs } from "./sections.js";
|
|
2
2
|
function trimStartLength(text) {
|
|
3
3
|
return text.length - text.trimStart().length;
|
|
4
4
|
}
|
|
@@ -6,7 +6,7 @@ export function documentSourceText(document) {
|
|
|
6
6
|
const paragraphs = [];
|
|
7
7
|
const textParts = [];
|
|
8
8
|
let outputStart = 0;
|
|
9
|
-
for (const paragraph of
|
|
9
|
+
for (const paragraph of allDocumentParagraphs(document)) {
|
|
10
10
|
const text = paragraph.text.trim();
|
|
11
11
|
if (text.length === 0) {
|
|
12
12
|
continue;
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { splitSentences } from "./sentences.js";
|
|
2
|
-
import { proseSourceText
|
|
2
|
+
import { proseSourceText } from "./traverse.js";
|
|
3
3
|
function isParagraphNode(node) {
|
|
4
4
|
return node.type === "Paragraph";
|
|
5
5
|
}
|
|
6
6
|
function isParentNode(node) {
|
|
7
7
|
return "children" in node;
|
|
8
8
|
}
|
|
9
|
-
function
|
|
9
|
+
function collectRuleParagraphs(node, paragraphs) {
|
|
10
|
+
if (isParagraphNode(node)) {
|
|
11
|
+
paragraphs.push(node);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (!isParentNode(node)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
for (const child of node.children) {
|
|
18
|
+
collectRuleParagraphs(child, paragraphs);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function collectDocumentParagraphs(node, paragraphs) {
|
|
10
22
|
if (isParagraphNode(node)) {
|
|
11
23
|
paragraphs.push(node);
|
|
12
24
|
return;
|
|
@@ -15,13 +27,20 @@ function collectParagraphs(node, paragraphs) {
|
|
|
15
27
|
return;
|
|
16
28
|
}
|
|
17
29
|
for (const child of node.children) {
|
|
18
|
-
|
|
30
|
+
collectDocumentParagraphs(child, paragraphs);
|
|
19
31
|
}
|
|
20
32
|
}
|
|
21
|
-
function
|
|
33
|
+
function sectionRuleParagraphs(section) {
|
|
22
34
|
const paragraphs = [];
|
|
23
35
|
for (const node of section) {
|
|
24
|
-
|
|
36
|
+
collectRuleParagraphs(node, paragraphs);
|
|
37
|
+
}
|
|
38
|
+
return paragraphs;
|
|
39
|
+
}
|
|
40
|
+
function sectionDocumentParagraphs(section) {
|
|
41
|
+
const paragraphs = [];
|
|
42
|
+
for (const node of section) {
|
|
43
|
+
collectDocumentParagraphs(node, paragraphs);
|
|
25
44
|
}
|
|
26
45
|
return paragraphs;
|
|
27
46
|
}
|
|
@@ -44,7 +63,7 @@ function documentSections(document) {
|
|
|
44
63
|
return sections;
|
|
45
64
|
}
|
|
46
65
|
function paragraphSentences(paragraph) {
|
|
47
|
-
const source =
|
|
66
|
+
const source = proseSourceText(paragraph);
|
|
48
67
|
return splitSentences(source.text).map((sentence) => ({
|
|
49
68
|
paragraph,
|
|
50
69
|
sentence,
|
|
@@ -54,16 +73,16 @@ function paragraphSentences(paragraph) {
|
|
|
54
73
|
export function allParagraphSentences(document) {
|
|
55
74
|
const sentences = [];
|
|
56
75
|
for (const section of documentSections(document)) {
|
|
57
|
-
for (const paragraph of
|
|
76
|
+
for (const paragraph of sectionRuleParagraphs(section)) {
|
|
58
77
|
sentences.push(...paragraphSentences(paragraph));
|
|
59
78
|
}
|
|
60
79
|
}
|
|
61
80
|
return sentences;
|
|
62
81
|
}
|
|
63
|
-
|
|
82
|
+
function mappedParagraphs(document, select) {
|
|
64
83
|
const paragraphs = [];
|
|
65
84
|
for (const section of documentSections(document)) {
|
|
66
|
-
for (const paragraph of
|
|
85
|
+
for (const paragraph of select(section)) {
|
|
67
86
|
const source = proseSourceText(paragraph);
|
|
68
87
|
paragraphs.push({
|
|
69
88
|
paragraph,
|
|
@@ -74,10 +93,16 @@ export function allParagraphs(document) {
|
|
|
74
93
|
}
|
|
75
94
|
return paragraphs;
|
|
76
95
|
}
|
|
96
|
+
export function allDocumentParagraphs(document) {
|
|
97
|
+
return mappedParagraphs(document, sectionDocumentParagraphs);
|
|
98
|
+
}
|
|
99
|
+
export function allParagraphs(document) {
|
|
100
|
+
return mappedParagraphs(document, sectionRuleParagraphs);
|
|
101
|
+
}
|
|
77
102
|
export function sectionFirstSentences(document) {
|
|
78
103
|
const sentences = [];
|
|
79
104
|
for (const section of documentSections(document)) {
|
|
80
|
-
const firstParagraph =
|
|
105
|
+
const firstParagraph = sectionRuleParagraphs(section).at(0);
|
|
81
106
|
if (firstParagraph === undefined) {
|
|
82
107
|
continue;
|
|
83
108
|
}
|
|
@@ -91,7 +116,7 @@ export function sectionFirstSentences(document) {
|
|
|
91
116
|
export function sectionLastSentences(document) {
|
|
92
117
|
const sentences = [];
|
|
93
118
|
for (const section of documentSections(document)) {
|
|
94
|
-
const lastParagraph =
|
|
119
|
+
const lastParagraph = sectionRuleParagraphs(section).at(-1);
|
|
95
120
|
if (lastParagraph === undefined) {
|
|
96
121
|
continue;
|
|
97
122
|
}
|
|
@@ -15,10 +15,19 @@ function normalizeNode(node, includeImageAlt) {
|
|
|
15
15
|
}
|
|
16
16
|
if ((node.type === "Image" || node.type === "ImageReference") &&
|
|
17
17
|
!includeImageAlt) {
|
|
18
|
+
const alt = "alt" in node && typeof node.alt === "string" ? node.alt : "";
|
|
18
19
|
return {
|
|
19
20
|
...node,
|
|
20
21
|
type: "Str",
|
|
21
|
-
value: ""
|
|
22
|
+
value: " ".repeat(alt.length)
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (node.type === "Code" && !includeImageAlt) {
|
|
26
|
+
const value = "value" in node && typeof node.value === "string" ? node.value : "";
|
|
27
|
+
return {
|
|
28
|
+
...node,
|
|
29
|
+
type: "Str",
|
|
30
|
+
value: " ".repeat(value.length)
|
|
22
31
|
};
|
|
23
32
|
}
|
|
24
33
|
if (isHtmlNode(node) && !includeImageAlt) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopless",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.30",
|
|
4
4
|
"description": "Deterministic textlint rules and CLI for catching prose slop in English Markdown.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"textlint",
|
|
@@ -112,6 +112,7 @@
|
|
|
112
112
|
"./rules/words/llm-vocabulary": "./dist/rules/words/llm-vocabulary.js",
|
|
113
113
|
"./rules/words/simplicity": "./dist/rules/words/simplicity.js",
|
|
114
114
|
"./rules/words/prohibited-words": "./dist/rules/words/prohibited-words.js",
|
|
115
|
+
"./rules/words/quietly-filler": "./dist/rules/words/quietly-filler.js",
|
|
115
116
|
"./rules/words/quietly-overuse": "./dist/rules/words/quietly-overuse.js"
|
|
116
117
|
},
|
|
117
118
|
"dependencies": {
|