book-kit 0.0.0-stage → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +72 -0
  3. package/README.md +251 -2
  4. package/bin/book-kit.js +115 -0
  5. package/commands/_emoji_io.py +32 -0
  6. package/commands/audit-chapter-lengths.js +244 -0
  7. package/commands/check-epub-size.js +68 -0
  8. package/commands/check-pdf-page-count.js +162 -0
  9. package/commands/composite-kindle-emoji.py +85 -0
  10. package/commands/composite-print-emoji.py +98 -0
  11. package/commands/conventions.js +76 -0
  12. package/commands/convert-pdfx.sh +194 -0
  13. package/commands/download-icc-profile.sh +105 -0
  14. package/commands/fonts.py +212 -0
  15. package/commands/generate-reference-docx.py +344 -0
  16. package/commands/kindle-fonts.js +173 -0
  17. package/commands/links-to-footnotes.js +366 -0
  18. package/commands/markdownlint.js +25 -0
  19. package/commands/minify-css.js +43 -0
  20. package/commands/optimize-images.js +73 -0
  21. package/commands/parity.sh +150 -0
  22. package/commands/postprocess-epub.js +541 -0
  23. package/commands/prep-print-src.js +77 -0
  24. package/commands/prose.js +38 -0
  25. package/commands/release-files.js +89 -0
  26. package/commands/reorder-print-frontmatter.js +79 -0
  27. package/commands/strip-page-rules.js +1168 -0
  28. package/commands/strip-property-rules.js +93 -0
  29. package/commands/update-key-takeaways.js +314 -0
  30. package/commands/validate.js +283 -0
  31. package/configs/markdownlint-cli2.jsonc +98 -0
  32. package/configs/textlintrc.json +22 -0
  33. package/css/theme/01-tokens.css +83 -0
  34. package/css/theme/02-fonts.css +79 -0
  35. package/css/theme/03-prose.css +53 -0
  36. package/css/theme/04-base.css +226 -0
  37. package/css/theme/05-components.css +546 -0
  38. package/css/theme/06-utilities.css +40 -0
  39. package/css/theme/07-ereader.css +245 -0
  40. package/css/theme/08-epub.css +865 -0
  41. package/css/theme/09-back-matter.css +47 -0
  42. package/css/theme/10-dark.css +302 -0
  43. package/css/theme/11-print.css +1229 -0
  44. package/css/theme.css +38 -0
  45. package/defaults/book.config.yml +318 -0
  46. package/defaults/pandoc-base.yml +19 -0
  47. package/defaults/pandoc-docx.yml +6 -0
  48. package/defaults/pandoc-epub-fonts.yml +6 -0
  49. package/defaults/pandoc-epub.yml +15 -0
  50. package/defaults/pandoc-kindle.yml +6 -0
  51. package/emoji/1f382.png +0 -0
  52. package/emoji/1f389.png +0 -0
  53. package/emoji/1f440.png +0 -0
  54. package/emoji/1f44d.png +0 -0
  55. package/emoji/1f44f.png +0 -0
  56. package/emoji/1f454.png +0 -0
  57. package/emoji/1f4a1.png +0 -0
  58. package/emoji/1f4bb.png +0 -0
  59. package/emoji/1f602.png +0 -0
  60. package/emoji/1f603.png +0 -0
  61. package/emoji/1f604.png +0 -0
  62. package/emoji/1f60a.png +0 -0
  63. package/emoji/1f60f.png +0 -0
  64. package/emoji/1f64c.png +0 -0
  65. package/emoji/1f64f.png +0 -0
  66. package/emoji/1f914.png +0 -0
  67. package/emoji/1f923.png +0 -0
  68. package/emoji/2714.png +0 -0
  69. package/emoji/274c.png +0 -0
  70. package/filters/add-div-titles.lua +196 -0
  71. package/filters/arc-notice.lua +36 -0
  72. package/filters/body-emoji-images.lua +48 -0
  73. package/filters/callout-classes.lua +40 -0
  74. package/filters/lib/book_kit.lua +110 -0
  75. package/filters/revision.lua +17 -0
  76. package/filters/strip-comments.lua +40 -0
  77. package/filters/strip-emoji-kindle.lua +134 -0
  78. package/fonts/LICENSE-source-code-pro.md +93 -0
  79. package/fonts/LICENSE-source-sans.md +93 -0
  80. package/fonts/LICENSE-source-serif.md +93 -0
  81. package/fonts/recipe.json +41 -0
  82. package/just/book-kit.just +229 -0
  83. package/lib/acronyms.js +47 -0
  84. package/lib/callouts.js +17 -0
  85. package/lib/config.js +211 -0
  86. package/lib/is-main.js +21 -0
  87. package/lib/lint.js +148 -0
  88. package/lib/pandoc.js +148 -0
  89. package/lib/paragraphs.js +173 -0
  90. package/lib/revision.js +35 -0
  91. package/lib/structure.js +39 -0
  92. package/lib/textlint-github-formatter.js +58 -0
  93. package/lib/validate.js +202 -0
  94. package/package.json +98 -4
  95. package/presets/business-nonfiction/CONVENTIONS.md +35 -0
  96. package/presets/business-nonfiction/preset.yml +128 -0
  97. package/profiles/pdfx-def.ps +42 -0
  98. package/requirements.txt +14 -0
  99. package/rules/no-ai-like-patterns.js +209 -0
  100. package/rules/no-assumptive.js +76 -0
  101. package/rules/no-bare-acronyms.js +129 -0
  102. package/rules/no-cliches.js +544 -0
  103. package/rules/no-cultural-idioms.js +422 -0
  104. package/rules/no-vague-intensifiers.js +94 -0
  105. package/templates/template-epub.html +79 -0
  106. package/templates/template.html +73 -0
  107. package/toolchain.json +42 -0
  108. package/validators/acronym-expansion.js +94 -0
  109. package/validators/bold-keywords.js +56 -0
  110. package/validators/callout-balance.js +74 -0
  111. package/validators/callout-divs.js +66 -0
  112. package/validators/callout-labels.js +102 -0
  113. package/validators/chapter-lengths.js +14 -0
  114. package/validators/chapter.js +57 -0
  115. package/validators/cross-references.js +45 -0
  116. package/validators/doubled-words.js +76 -0
  117. package/validators/duplicate-headings.js +52 -0
  118. package/validators/em-dashes.js +73 -0
  119. package/validators/escaped-smallcaps.js +46 -0
  120. package/validators/footnotes.js +78 -0
  121. package/validators/heading-hierarchy.js +58 -0
  122. package/validators/hypothetical-hooks.js +103 -0
  123. package/validators/index-integrity.js +28 -0
  124. package/validators/index.js +73 -0
  125. package/validators/list-punctuation.js +123 -0
  126. package/validators/min-opener-length.js +87 -0
  127. package/validators/no-bare-url-link-text.js +38 -0
  128. package/validators/no-todo-markers.js +49 -0
  129. package/validators/no-transition-todos.js +34 -0
  130. package/validators/number-range-dashes.js +72 -0
  131. package/validators/paragraph-length.js +62 -0
  132. package/validators/quote-punctuation.js +85 -0
  133. package/validators/section-intro-final-lead.js +90 -0
  134. package/validators/section-intro-has-lead.js +41 -0
  135. package/validators/section-intro-no-tldr.js +37 -0
  136. package/validators/section-intros.js +33 -0
  137. package/validators/sentence-starters.js +132 -0
  138. package/validators/smallcaps.js +67 -0
  139. package/validators/tldr-length.js +58 -0
@@ -0,0 +1,544 @@
1
+ /**
2
+ * textlint rule: no-cliches
3
+ *
4
+ * Detects corporate clichés and buzzwords that plain-language style guides
5
+ * recommend avoiding. These are phrases that obscure meaning
6
+ * and should be replaced with specific, direct language.
7
+ *
8
+ * Catches:
9
+ * - Corporate buzzwords ("leverage", "synergy", "paradigm shift")
10
+ * - Business clichés ("circle back", "touch base", "low-hanging fruit")
11
+ * - Vague corporate terms ("best practices", "alignment", "going forward")
12
+ * - Filler phrases ("at the end of the day", "move the needle")
13
+ */
14
+
15
+ const PATTERNS = [
16
+ // === Corporate buzzwords ===
17
+ {
18
+ pattern: /\bleverag(?:e[sd]?|ing)\b/i,
19
+ message: '"Leverage" is a buzzword — use "use", "apply", "build on", or be specific about how.'
20
+ },
21
+ {
22
+ pattern: /\bsynerg(?:y|ies|ize|ized|izing)\b/i,
23
+ message: '"Synergy" is a buzzword — use "collaboration", "combined effect", or describe the actual benefit.'
24
+ },
25
+ {
26
+ pattern: /\bparadigm shift\b/i,
27
+ message: '"Paradigm shift" is a buzzword — use "significant change", "fundamental change", or describe what\'s changing.'
28
+ },
29
+ {
30
+ pattern: /\bgame[- ]?changer\b/i,
31
+ message: '"Game-changer" is a buzzword — describe the specific impact or benefit.'
32
+ },
33
+ {
34
+ pattern: /\bseamless(?:ly)?\b/i,
35
+ message: '"Seamless" is a buzzword — use "smooth", "integrated", or describe the actual experience.'
36
+ },
37
+ {
38
+ pattern: /\brobust\b/i,
39
+ message: '"Robust" is a buzzword — use "reliable", "well-tested", or be specific.'
40
+ },
41
+ {
42
+ pattern: /\bworld[- ]?class\b/i,
43
+ message: '"World-class" is a buzzword — provide actual evidence or metrics.'
44
+ },
45
+ {
46
+ pattern: /\bbest[- ]?in[- ]?class\b/i,
47
+ message: '"Best-in-class" is a buzzword — provide actual evidence or metrics.'
48
+ },
49
+ {
50
+ pattern: /\bcutting[- ]?edge\b/i,
51
+ message: '"Cutting-edge" is a buzzword — describe what\'s new or advanced about it specifically.'
52
+ },
53
+ {
54
+ pattern: /\bvalue[- ]?add\b/i,
55
+ message: '"Value-add" is a buzzword — describe the actual value or benefit.'
56
+ },
57
+ {
58
+ pattern: /\bholistic(?:ally)?\b/i,
59
+ message: '"Holistic" is a buzzword — use "comprehensive", "complete", or describe the scope specifically.'
60
+ },
61
+
62
+ // === Business clichés ===
63
+ {
64
+ pattern: /\bcircle back\b/i,
65
+ message: '"Circle back" is a cliché — use "follow up", "return to", or "discuss later".'
66
+ },
67
+ {
68
+ pattern: /\btouch base\b/i,
69
+ message: '"Touch base" is a cliché — use "check in", "discuss", or "meet".'
70
+ },
71
+ {
72
+ pattern: /\blow[- ]?hanging fruit\b/i,
73
+ message: '"Low-hanging fruit" is a cliché — use "easy wins", "quick improvements", or be specific.'
74
+ },
75
+ {
76
+ pattern: /\bmove the needle\b/i,
77
+ message: '"Move the needle" is a cliché — describe the specific impact or metric.'
78
+ },
79
+ {
80
+ pattern: /\bdeep dive\b/i,
81
+ message: '"Deep dive" is a cliché — use "detailed analysis", "thorough review", or "examine closely".'
82
+ },
83
+ {
84
+ pattern: /\bdrill down\b/i,
85
+ message: '"Drill down" is a cliché — use "examine in detail" or "look closer at".'
86
+ },
87
+ {
88
+ pattern: /\bloop(?:ed|ing)? (?:you |them |us |him |her )?in\b/i,
89
+ message: '"Loop in" is a cliché — use "include", "inform", or "add to the conversation".'
90
+ },
91
+ {
92
+ pattern: /\btake (?:it|this|that) offline\b/i,
93
+ message: '"Take it offline" is a cliché — use "discuss separately", "continue in private", or be specific.'
94
+ },
95
+ {
96
+ pattern: /\bboil the ocean\b/i,
97
+ message: '"Boil the ocean" is a cliché — use "take on too much", "overreach", or describe the scope problem specifically.'
98
+ },
99
+
100
+ // === Vague corporate filler ===
101
+ {
102
+ pattern: /\bbest practice(?:s)?\b/i,
103
+ message: '"Best practice(s)" is vague — use "proven practice(s)", "effective approach", or be specific about what works.'
104
+ },
105
+ {
106
+ pattern: /\bunique opportunity\b/i,
107
+ message: '"Unique opportunity" is a cliché — explain what makes it unique and what the opportunity is.'
108
+ },
109
+ {
110
+ pattern: /\binnovative\b/i,
111
+ message: '"Innovative" is a buzzword — describe what makes it new or different specifically.'
112
+ },
113
+
114
+ // === Metaphorical clichés ===
115
+ {
116
+ pattern: /(?:^|(?<=\. ))at the end of the day\b/im,
117
+ message: '"At the end of the day" is a cliché — use "ultimately" or state the point directly.'
118
+ },
119
+ {
120
+ pattern: /\bthink outside the box\b/i,
121
+ message: '"Think outside the box" is a cliché — describe the creative approach you mean.'
122
+ },
123
+ {
124
+ pattern: /\bon the same page\b/i,
125
+ message: '"On the same page" is a cliché — use "in agreement", "aligned", or be specific.'
126
+ },
127
+ {
128
+ pattern: /\bpain point(?:s)?\b/i,
129
+ message: '"Pain point(s)" is a cliché — describe the specific problem or frustration.'
130
+ },
131
+ {
132
+ pattern: /\bvalue proposition\b/i,
133
+ message: '"Value proposition" is a cliché — describe the actual benefit or value.'
134
+ },
135
+ {
136
+ pattern: /(?:not|n't) a (?:\w+ )?bug[—–\-,;:]\s*it'?s (?:a |the |an )?(?:\w+ )?feature/i,
137
+ message: '"Not a bug, it\'s a feature" is a cliché — say what you mean directly: "by design", "the whole point", or describe the actual advantage.'
138
+ },
139
+ {
140
+ pattern: /\ba feature[,;:—–-]?\s*not (?:a )?bug\b/i,
141
+ message: '"A feature, not a bug" is a cliché — say what you mean directly: "by design", "the whole point", or describe the actual advantage.'
142
+ },
143
+
144
+ // === General business clichés ===
145
+ {
146
+ pattern: /\bback to square one\b/i,
147
+ message: '"Back to square one" is a cliché — use "restart", "start over", or describe what failed.'
148
+ },
149
+ {
150
+ pattern: /\bback to the drawing board\b/i,
151
+ message: '"Back to the drawing board" is a cliché — use "rethink", "redesign", or describe the pivot.'
152
+ },
153
+ {
154
+ pattern: /\bbite the bullet\b/i,
155
+ message: '"Bite the bullet" is a cliché — use "commit", "decide", or describe the difficult choice.'
156
+ },
157
+ {
158
+ pattern: /\bcrystal clear\b/i,
159
+ message: '"Crystal clear" is a cliché — use "clear", "obvious", or "unambiguous".'
160
+ },
161
+ {
162
+ pattern: /\beasier said than done\b/i,
163
+ message: '"Easier said than done" is a cliché — describe the specific difficulty.'
164
+ },
165
+ {
166
+ pattern: /\bfor all intents and purposes\b/i,
167
+ message: '"For all intents and purposes" is a cliché — use "effectively", "in practice", or cut entirely.'
168
+ },
169
+ {
170
+ pattern: /\b(?:it )?goes without saying\b/i,
171
+ message: '"Goes without saying" is a cliché — cut it and just say the thing.'
172
+ },
173
+ {
174
+ pattern: /\bneedless to say\b/i,
175
+ message: '"Needless to say" is a cliché — cut it and just say it.'
176
+ },
177
+ {
178
+ pattern: /\bin a nutshell\b/i,
179
+ message: '"In a nutshell" is a cliché — use "briefly", "in short", or just state it.'
180
+ },
181
+ {
182
+ pattern: /\bin this day and age\b/i,
183
+ message: '"In this day and age" is a cliché — use "today", "now", or be specific about the era.'
184
+ },
185
+ {
186
+ pattern: /\blast but not least\b/i,
187
+ message: '"Last but not least" is a cliché — just list the item; no fanfare needed.'
188
+ },
189
+ {
190
+ pattern: /\bit is what it is\b/i,
191
+ message: '"It is what it is" is meaningless filler — describe what "it" actually is.'
192
+ },
193
+ {
194
+ pattern: /\bbottom line\b(?! up front)/i,
195
+ message: '"Bottom line" is a cliché — use "the key point", "what matters", or state the point directly.'
196
+ },
197
+
198
+ // === Metaphorical clichés common in professional writing ===
199
+ {
200
+ pattern: /\btip of the iceberg\b/i,
201
+ message: '"Tip of the iceberg" is a cliché — use "a small part of a larger problem" or describe the scope.'
202
+ },
203
+ {
204
+ pattern: /\bperfect storm\b/i,
205
+ message: '"Perfect storm" is a cliché — describe the specific confluence of factors.'
206
+ },
207
+ {
208
+ pattern: /\buphill battle\b/i,
209
+ message: '"Uphill battle" is a cliché — use "difficult effort" or describe the obstacles.'
210
+ },
211
+ {
212
+ pattern: /\blight at the end of the tunnel\b/i,
213
+ message: '"Light at the end of the tunnel" is a cliché — use "signs of progress" or describe what\'s improving.'
214
+ },
215
+ {
216
+ pattern: /\breinvent(?:ing)? the wheel\b/i,
217
+ message: '"Reinvent the wheel" is a cliché — use "duplicate existing work" or "rebuild what already exists".'
218
+ },
219
+ {
220
+ pattern: /\b(?:open(?:ing|ed|s)? )?a can of worms\b/i,
221
+ message: '"Can of worms" is a cliché — use "create complications" or describe the risks.'
222
+ },
223
+ {
224
+ pattern: /\bpar for the course\b/i,
225
+ message: '"Par for the course" is a cliché — use "expected", "typical", or "normal".'
226
+ },
227
+ {
228
+ pattern: /\bcut to the chase\b/i,
229
+ message: '"Cut to the chase" is a cliché — just get to the point instead of announcing it.'
230
+ },
231
+ {
232
+ pattern: /\bwater under the bridge\b/i,
233
+ message: '"Water under the bridge" is a cliché — use "past", "resolved", or "behind us".'
234
+ },
235
+ {
236
+ pattern: /\bwhen push comes to shove\b/i,
237
+ message: '"When push comes to shove" is a cliché — use "when it matters", "under pressure", or be specific.'
238
+ },
239
+ {
240
+ pattern: /\bread between the lines\b/i,
241
+ message: '"Read between the lines" is a cliché — use "infer", "interpret the subtext", or describe what\'s implicit.'
242
+ },
243
+ {
244
+ pattern: /\bshed(?:s|ding)? (?:some |more )?light on\b/i,
245
+ message: '"Shed some light on" is a cliché — use "clarify", "explain", or "illuminate".'
246
+ },
247
+ {
248
+ pattern: /\belephant in the room\b/i,
249
+ message: '"Elephant in the room" is a cliché — name the actual issue directly.'
250
+ },
251
+ {
252
+ pattern: /\braise the bar\b/i,
253
+ message: '"Raise the bar" is a cliché — use "increase standards" or describe the specific improvement.'
254
+ },
255
+ {
256
+ pattern: /\bhit the ground running\b/i,
257
+ message: '"Hit the ground running" is a cliché — use "start immediately", "begin productively", or describe the onboarding expectation.'
258
+ },
259
+ {
260
+ pattern: /\bsilver lining\b/i,
261
+ message: '"Silver lining" is a cliché — describe the actual benefit or upside.'
262
+ },
263
+ {
264
+ pattern: /\bbreath of fresh air\b/i,
265
+ message: '"Breath of fresh air" is a cliché — describe what\'s refreshing about it specifically.'
266
+ },
267
+
268
+ // === Tech/management clichés ===
269
+ {
270
+ pattern: /\bone[- ]size[- ]fits[- ]all\b/i,
271
+ message: '"One size fits all" is a cliché — use "universal", "generic", or describe the limitation.'
272
+ },
273
+ {
274
+ pattern: /\bcall(?:s|ing|ed)? the shots\b/i,
275
+ message: '"Call the shots" is a cliché — use "make decisions", "direct", or be specific.'
276
+ },
277
+ {
278
+ pattern: /\bphon(?:e[sd]?|ing) it in\b/i,
279
+ message: '"Phone it in" is a cliché — use "do the minimum", "not invest effort", or describe the lack of engagement.'
280
+ },
281
+ {
282
+ pattern: /\bgo(?:ing|es|ne)? the extra mile\b/i,
283
+ message: '"Go the extra mile" is a cliché — describe the specific extra effort.'
284
+ },
285
+ {
286
+ pattern: /\bfrom the ground up\b/i,
287
+ message: '"From the ground up" is a cliché — use "from scratch", "entirely new", or describe what\'s new.'
288
+ },
289
+ {
290
+ pattern: /\bon (?:the |my |our |your )?radar\b/i,
291
+ message: '"On the radar" is a cliché — use "aware of", "tracking", or "monitoring".'
292
+ },
293
+ {
294
+ pattern: /\bdrop(?:ped|ping|s)? the ball\b/i,
295
+ message: '"Drop the ball" is a cliché — use "miss", "fail to follow through", or describe what was missed.'
296
+ },
297
+ {
298
+ pattern: /\bget(?:ting)? the ball rolling\b/i,
299
+ message: '"Get the ball rolling" is a cliché — use "start", "begin", or "initiate".'
300
+ },
301
+ {
302
+ pattern: /\brun(?:ning)? it up the flagpole\b/i,
303
+ message: '"Run it up the flagpole" is a cliché — use "propose", "share for feedback", or "test the idea".'
304
+ },
305
+ {
306
+ pattern: /\bpush(?:ing|es|ed)? the envelope\b/i,
307
+ message: '"Push the envelope" is a cliché — describe the specific boundary being tested.'
308
+ },
309
+ {
310
+ pattern: /\bmov(?:e[sd]?|ing) the goalposts?\b/i,
311
+ message: '"Move the goalposts" is a cliché — use "change requirements" or describe what changed.'
312
+ },
313
+ {
314
+ pattern: /\bskin in the game\b/i,
315
+ message: '"Skin in the game" is a cliché — use "personal stake", "accountability", or describe the incentive.'
316
+ },
317
+ {
318
+ pattern: /\ball hands on deck\b/i,
319
+ message: '"All hands on deck" is a cliché — use "everyone contributing", "full team effort", or describe who\'s needed.'
320
+ },
321
+ {
322
+ pattern: /\brubber[- ]stamp(?:ed|ing|s)?\b/i,
323
+ message: '"Rubber stamp" is a cliché — use "approve without review" or describe the lack of scrutiny.'
324
+ },
325
+ {
326
+ pattern: /\btake (?:it |this |things )?to the next level\b/i,
327
+ message: '"Take it to the next level" is a cliché — describe the specific improvement.'
328
+ },
329
+ // === AI-characteristic buzzwords ===
330
+ {
331
+ pattern: /\btapestry\b/i,
332
+ message: '"Tapestry" is an AI-characteristic metaphor — describe the actual mix or variety.'
333
+ },
334
+ {
335
+ pattern: /\btestament to\b/i,
336
+ message: '"Testament to" is an AI cliché — use "shows", "proves", or state the evidence directly.'
337
+ },
338
+ {
339
+ pattern: /\bmyriad\b/i,
340
+ message: '"Myriad" is AI-characteristic — use "many" or give the actual number.'
341
+ },
342
+ {
343
+ pattern: /\bplethora\b/i,
344
+ message: '"Plethora" is AI-characteristic — use "many", "too many", or be specific.'
345
+ },
346
+ {
347
+ pattern: /\bnorth star\b/i,
348
+ message: '"North star" is a buzzword — use "guiding goal", "primary objective", or name it.'
349
+ },
350
+ {
351
+ pattern: /\bsecret sauce\b/i,
352
+ message: '"Secret sauce" is a cliché — describe the actual differentiator.'
353
+ },
354
+ {
355
+ pattern: /\bfuture[- ]?proof\b/i,
356
+ message: '"Future-proof" is a buzzword — describe how it adapts to specific changes.'
357
+ },
358
+ {
359
+ pattern: /\bsupercharg(?:e[sd]?|ing)\b/i,
360
+ message: '"Supercharge" is a buzzword — use "speed up", "improve", or describe the specific gain.'
361
+ },
362
+ {
363
+ pattern: /\bunleash(?:e[sd]|ing)?\b/i,
364
+ message: '"Unleash" is a buzzword — use "release", "enable", or describe the effect.'
365
+ },
366
+ {
367
+ pattern: /\bunderscor(?:e[sd]?|ing)\b/i,
368
+ message: '"Underscore" is AI-characteristic importance-inflation — use "shows", "emphasizes", or state the point directly.'
369
+ },
370
+ {
371
+ pattern: /\bnavigate the complexit(?:y|ies)\b/i,
372
+ message: '"Navigate the complexities" is an AI cliché — describe the specific difficulty.'
373
+ },
374
+ // === Common clichés ===
375
+ {
376
+ pattern: /\bdouble[- ]edged sword\b/i,
377
+ message: '"Double-edged sword" is a cliché — name the specific upside and downside.'
378
+ },
379
+ {
380
+ pattern: /\bwin[- ]win\b/i,
381
+ message: '"Win-win" is a cliché — describe who gains what.'
382
+ },
383
+ {
384
+ pattern: /\bno[- ]brainer\b/i,
385
+ message: '"No-brainer" is a cliché — explain why the choice is obvious.'
386
+ },
387
+ {
388
+ pattern: /\bneedle in a haystack\b/i,
389
+ message: '"Needle in a haystack" is a cliché — use "hard to find" or describe the search problem.'
390
+ },
391
+ {
392
+ pattern: /\bthe name of the game\b/i,
393
+ message: '"The name of the game" is a cliché — state what actually matters.'
394
+ },
395
+ {
396
+ pattern: /\bsay goodbye to\b/i,
397
+ message: '"Say goodbye to" is marketing-speak — use "eliminate", "end", or describe what changes.'
398
+ },
399
+ {
400
+ pattern: /\bdouble[- ]click(?:ing)?\b(?! (?:the|on the|a) (?:mouse|button|icon|link|file))/i,
401
+ message: '"Double-click" (as a metaphor) is corporate-speak — use "examine closely", "dig into", or "go deeper on".'
402
+ },
403
+ {
404
+ pattern: /\bmoving parts\b/i,
405
+ message: '"Moving parts" is a cliché — describe the actual components or dependencies.'
406
+ },
407
+
408
+ // === Additional corporate buzzwords ===
409
+ {
410
+ pattern: /\bthought[- ]leader(?:ship|s)?\b/i,
411
+ message: '"Thought leader(ship)" is a buzzword — describe the actual expertise, ideas, or influence.'
412
+ },
413
+ {
414
+ pattern: /\bgame plan\b/i,
415
+ message: '"Game plan" is a cliché — use "plan", "strategy", or "approach".'
416
+ },
417
+ {
418
+ pattern: /\bmission[- ]critical\b/i,
419
+ message: '"Mission-critical" is a buzzword — use "essential", "required", or describe what breaks without it.'
420
+ },
421
+ {
422
+ pattern: /\bgold standard\b/i,
423
+ message: '"Gold standard" is a cliché — name the actual benchmark or describe what makes it the reference.'
424
+ },
425
+ {
426
+ pattern: /\bstate[- ]of[- ]the[- ]art\b/i,
427
+ message: '"State-of-the-art" is a buzzword — describe what\'s actually advanced about it.'
428
+ },
429
+ {
430
+ pattern: /\bbleeding[- ]edge\b/i,
431
+ message: '"Bleeding-edge" is a buzzword — describe what\'s new or unproven about it specifically.'
432
+ },
433
+ {
434
+ pattern: /\bturnkey\b/i,
435
+ message: '"Turnkey" is a buzzword — use "ready to use", "fully set up", or describe what\'s included.'
436
+ },
437
+ {
438
+ pattern: /\bmoonshot\b/i,
439
+ message: '"Moonshot" is a buzzword — describe the ambitious goal and why it\'s a stretch.'
440
+ },
441
+ {
442
+ pattern: /\blift and shift\b/i,
443
+ message: '"Lift and shift" is jargon — use "migrate as-is", "move without changes", or be specific.'
444
+ },
445
+ {
446
+ pattern: /\bblue[- ]sky(?:[- ]thinking)?\b/i,
447
+ message: '"Blue-sky thinking" is a cliché — use "open-ended brainstorming" or describe the goal.'
448
+ },
449
+ {
450
+ pattern: /\bdo(?:ing)? more with less\b/i,
451
+ message: '"Do more with less" is a cliché — describe the actual constraint and trade-off.'
452
+ },
453
+ {
454
+ pattern: /\btrim the fat\b/i,
455
+ message: '"Trim the fat" is a cliché — use "cut what\'s unnecessary" or name what to remove.'
456
+ },
457
+
458
+ // === Additional metaphorical clichés ===
459
+ {
460
+ pattern: /\bsilver bullet\b/i,
461
+ message: '"Silver bullet" is a cliché — use "simple fix", "single solution", or describe why none exists.'
462
+ },
463
+ {
464
+ pattern: /\bmagic bullet\b/i,
465
+ message: '"Magic bullet" is a cliché — use "simple fix" or describe why none exists.'
466
+ },
467
+ {
468
+ pattern: /\bholy grail\b/i,
469
+ message: '"Holy grail" is a cliché — describe the actual goal or ideal outcome.'
470
+ },
471
+ {
472
+ pattern: /\bsecret weapon\b/i,
473
+ message: '"Secret weapon" is a cliché — name the actual advantage.'
474
+ },
475
+ {
476
+ pattern: /\bivory tower\b/i,
477
+ message: '"Ivory tower" is a cliché — describe the actual disconnect from day-to-day work.'
478
+ },
479
+ {
480
+ pattern: /\bin the weeds\b/i,
481
+ message: '"In the weeds" is a cliché — use "lost in detail", "overwhelmed", or be specific.'
482
+ },
483
+ {
484
+ pattern: /\bherding cats\b/i,
485
+ message: '"Herding cats" is a cliché — describe the actual coordination difficulty.'
486
+ },
487
+ {
488
+ pattern: /\bsea change\b/i,
489
+ message: '"Sea change" is a cliché — use "major shift" or describe what changed.'
490
+ },
491
+ {
492
+ pattern: /\bwear(?:s|ing)? many hats\b/i,
493
+ message: '"Wear many hats" is a cliché — describe the actual range of responsibilities.'
494
+ },
495
+ {
496
+ pattern: /\bbring(?:s|ing)? (?:\w+ )?to the table\b/i,
497
+ message: '"Bring to the table" is a cliché — use "contribute", "offer", or name what they add.'
498
+ },
499
+ {
500
+ pattern: /\bknee[- ]jerk\b/i,
501
+ message: '"Knee-jerk" is a cliché — use "reflexive", "reactive", or "unconsidered".'
502
+ },
503
+ {
504
+ pattern: /\blay of the land\b/i,
505
+ message: '"Lay of the land" is a cliché — use "the current situation" or "how things work here".'
506
+ }
507
+ ];
508
+
509
+ /**
510
+ * @param {import("@textlint/types").TextlintRuleContext} context
511
+ * @param {Object} options
512
+ * @param {string[]} [options.allow] - Patterns to skip (by message substring)
513
+ */
514
+ function reporter(context, options = {}) {
515
+ const { Syntax, getSource, report, RuleError } = context;
516
+ const allow = options.allow || [];
517
+
518
+ return {
519
+ [Syntax.Paragraph](node) {
520
+ const text = getSource(node);
521
+
522
+ for (const { pattern, message } of PATTERNS) {
523
+ if (allow.some(a => message.includes(a))) {
524
+ continue;
525
+ }
526
+
527
+ // Reset regex state for global/multiline patterns
528
+ pattern.lastIndex = 0;
529
+ const match = pattern.exec(text);
530
+
531
+ if (match) {
532
+ const index = match.index;
533
+ report(node, new RuleError(message, { index }));
534
+ }
535
+ }
536
+ }
537
+ };
538
+ }
539
+
540
+ const rule = {
541
+ linter: reporter
542
+ };
543
+
544
+ export default rule;