ai-text-check 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,19 +14,21 @@ Node.js 20+ is required. The package ships dual **ESM and CommonJS** builds with
14
14
 
15
15
  ## What it checks
16
16
 
17
- | Engine | What it catches |
18
- | ------------------- | ---------------------------------------------------------------------------------------------------------- |
19
- | **polish** | Custom AI tells (`delve`, `in today's world`, antithesis), readability, markdown structure/SEO, typography |
20
- | **slop-gate** | Vocabulary pack (`nestled`, `treasure trove`, `leverage`, …) |
21
- | **write-good** | Weasel words, clichés, wordy phrases, passive voice |
22
- | **retext** | Passive voice, readability grade, simplify, repeated words |
23
- | **is-this-ai-slop** | Clichés, buzzwords, em-dash spam, antithesis, sycophancy |
24
- | **veldica** | Stock LLM transitions and AI-style markers |
25
- | **clean-writing** | Banned constructions, marketing adjectives, filler, intensifiers |
26
- | **vale** | Vendored styles: write-good, Google, AiTextCheck, ai-tells, signs-of-ai-writing |
17
+ | Engine | What it catches |
18
+ | ------------------- | ------------------------------------------------------------------------------------------------------------------ |
19
+ | **polish** | Custom AI tells (`delve`, emojis, `in today's world`, antithesis), readability, markdown structure/SEO, typography |
20
+ | **slop-gate** | Vocabulary pack (`nestled`, `treasure trove`, `leverage`, …) |
21
+ | **write-good** | Weasel words, clichés, wordy phrases, passive voice |
22
+ | **retext** | Passive voice, readability grade, simplify, repeated words |
23
+ | **is-this-ai-slop** | Clichés, buzzwords, em-dash spam, antithesis, sycophancy |
24
+ | **veldica** | Stock LLM transitions and AI-style markers |
25
+ | **clean-writing** | Banned constructions, marketing adjectives, filler, intensifiers |
26
+ | **vale** | Vendored styles: write-good, Google, AiTextCheck, ai-tells, signs-of-ai-writing |
27
27
 
28
28
  Safe auto-fixes can strip filler openers and collapse extra whitespace without rewriting code fences.
29
29
 
30
+ Emoji in prose is treated as an AI tell (`ai-emojis`). Set `ignoreEmojis: true` or pass `--ignore-emojis` to allow them; the ignore flag is off by default.
31
+
30
32
  ## TypeScript
31
33
 
32
34
  ```ts
@@ -111,6 +113,7 @@ npx ai-text-check init
111
113
  | `--no-slop` | Skip slop-gate and is-this-ai-slop |
112
114
  | `--no-write-good` | Skip write-good |
113
115
  | `--no-retext` | Skip retext |
116
+ | `--ignore-emojis` | Allow emojis (skip `ai-emojis`) |
114
117
  | `--ignore-rule ID` | Skip a rule (repeatable) |
115
118
 
116
119
  Exit code `1` when issues meet the fail threshold.
@@ -126,6 +129,7 @@ Exit code `1` when issues meet the fail threshold.
126
129
  "minScore": 0,
127
130
  "extensions": [".md", ".mdx", ".markdown", ".txt"],
128
131
  "ignoreRules": [],
132
+ "ignoreEmojis": false,
129
133
  "checks": {
130
134
  "ai": true,
131
135
  "grammar": true,
package/dist/cli.js CHANGED
@@ -736,6 +736,14 @@ function validateUserConfig(value) {
736
736
  config.ignoreRules = value.ignoreRules;
737
737
  }
738
738
  }
739
+ const ignoreEmojis = expectBoolean(
740
+ value.ignoreEmojis,
741
+ "ignoreEmojis",
742
+ errors
743
+ );
744
+ if (ignoreEmojis !== void 0) {
745
+ config.ignoreEmojis = ignoreEmojis;
746
+ }
739
747
  if (value.include !== void 0) {
740
748
  if (!isStringArray(value.include)) {
741
749
  errors.push("include must be an array of strings");
@@ -869,6 +877,7 @@ function validateUserConfig(value) {
869
877
  "failOn",
870
878
  "minScore",
871
879
  "ignoreRules",
880
+ "ignoreEmojis",
872
881
  "include",
873
882
  "exclude",
874
883
  "extensions",
@@ -892,7 +901,14 @@ function resolveConfig(user = {}) {
892
901
  format: user.format ?? "auto",
893
902
  failOn: user.failOn ?? "warn",
894
903
  minScore: user.minScore ?? 0,
895
- ignoreRules: user.ignoreRules ?? [],
904
+ ignoreRules: (() => {
905
+ const rules = [...user.ignoreRules ?? []];
906
+ if (user.ignoreEmojis ?? false) {
907
+ rules.push("ai-emojis");
908
+ }
909
+ return rules;
910
+ })(),
911
+ ignoreEmojis: user.ignoreEmojis ?? false,
896
912
  include: user.include ?? [],
897
913
  exclude: user.exclude ?? [],
898
914
  extensions: (user.extensions ?? DEFAULT_EXTENSIONS).map(
@@ -12088,6 +12104,14 @@ var AI_PATTERN_RULES = [
12088
12104
  severity: "info",
12089
12105
  minCount: ({ words }) => Math.max(6, words / 250)
12090
12106
  },
12107
+ {
12108
+ id: "ai-emojis",
12109
+ category: "ai",
12110
+ pattern: new RegExp("\\p{Extended_Pictographic}", "gu"),
12111
+ message: "Emoji can read as chatty or AI-styled in formal prose.",
12112
+ severity: "info",
12113
+ suggestion: "Prefer plain prose, or set ignoreEmojis: true to allow them."
12114
+ },
12091
12115
  {
12092
12116
  id: "double-space",
12093
12117
  category: "typography",
@@ -13435,6 +13459,7 @@ Options:
13435
13459
  --no-slop Skip slop-gate vocabulary and is-this-ai-slop
13436
13460
  --no-write-good Skip the write-good grammar engine
13437
13461
  --no-retext Skip retext (passive, readability, simplify, repeats)
13462
+ --ignore-emojis Allow emojis (skip the ai-emojis rule; off by default)
13438
13463
  --ignore-rule ID Ignore a rule (repeatable)
13439
13464
  --config PATH Path to ai-text-check.config.json
13440
13465
  --help, -h Show this help
@@ -13442,7 +13467,8 @@ Options:
13442
13467
  -- Extra flags after -- are passed to Vale
13443
13468
 
13444
13469
  By default every local engine runs: polish, slop-gate, write-good, retext,
13445
- is-this-ai-slop, Veldica, clean-writing, and Vale.
13470
+ is-this-ai-slop, Veldica, clean-writing, and Vale. Emoji in prose is flagged
13471
+ as an AI tell unless --ignore-emojis (or ignoreEmojis: true) is set.
13446
13472
 
13447
13473
  Examples:
13448
13474
  ai-text-check content
@@ -13463,6 +13489,7 @@ function parseArgs(argv) {
13463
13489
  slop: true,
13464
13490
  writeGood: true,
13465
13491
  retext: true,
13492
+ ignoreEmojis: false,
13466
13493
  ignoreRules: [],
13467
13494
  valeArgs: []
13468
13495
  };
@@ -13528,6 +13555,9 @@ function parseArgs(argv) {
13528
13555
  case "--no-retext":
13529
13556
  options.retext = false;
13530
13557
  break;
13558
+ case "--ignore-emojis":
13559
+ options.ignoreEmojis = true;
13560
+ break;
13531
13561
  case "--min-score": {
13532
13562
  const value = Number(args[++i]);
13533
13563
  if (!Number.isFinite(value)) {
@@ -13588,6 +13618,7 @@ function toUserConfig(options) {
13588
13618
  if (options.failOn) config.failOn = options.failOn;
13589
13619
  if (options.minScore !== void 0) config.minScore = options.minScore;
13590
13620
  if (options.ignoreRules.length > 0) config.ignoreRules = options.ignoreRules;
13621
+ if (options.ignoreEmojis) config.ignoreEmojis = true;
13591
13622
  const engines = {};
13592
13623
  if (!options.vale) engines.vale = false;
13593
13624
  if (!options.slop) {
@@ -13648,7 +13679,8 @@ var SAMPLE_CONFIG = `{
13648
13679
  "failOn": "warn",
13649
13680
  "minScore": 0,
13650
13681
  "extensions": [".md", ".mdx", ".markdown", ".txt"],
13651
- "ignoreRules": []
13682
+ "ignoreRules": [],
13683
+ "ignoreEmojis": false
13652
13684
  }
13653
13685
  `;
13654
13686
  function initProject(cwd, withVale) {
package/dist/index.cjs CHANGED
@@ -737,6 +737,14 @@ function validateUserConfig(value) {
737
737
  config.ignoreRules = value.ignoreRules;
738
738
  }
739
739
  }
740
+ const ignoreEmojis = expectBoolean(
741
+ value.ignoreEmojis,
742
+ "ignoreEmojis",
743
+ errors
744
+ );
745
+ if (ignoreEmojis !== void 0) {
746
+ config.ignoreEmojis = ignoreEmojis;
747
+ }
740
748
  if (value.include !== void 0) {
741
749
  if (!isStringArray(value.include)) {
742
750
  errors.push("include must be an array of strings");
@@ -870,6 +878,7 @@ function validateUserConfig(value) {
870
878
  "failOn",
871
879
  "minScore",
872
880
  "ignoreRules",
881
+ "ignoreEmojis",
873
882
  "include",
874
883
  "exclude",
875
884
  "extensions",
@@ -893,7 +902,14 @@ function resolveConfig(user = {}) {
893
902
  format: user.format ?? "auto",
894
903
  failOn: user.failOn ?? "warn",
895
904
  minScore: user.minScore ?? 0,
896
- ignoreRules: user.ignoreRules ?? [],
905
+ ignoreRules: (() => {
906
+ const rules = [...user.ignoreRules ?? []];
907
+ if (user.ignoreEmojis ?? false) {
908
+ rules.push("ai-emojis");
909
+ }
910
+ return rules;
911
+ })(),
912
+ ignoreEmojis: user.ignoreEmojis ?? false,
897
913
  include: user.include ?? [],
898
914
  exclude: user.exclude ?? [],
899
915
  extensions: (user.extensions ?? DEFAULT_EXTENSIONS).map(
@@ -12278,6 +12294,14 @@ var AI_PATTERN_RULES = [
12278
12294
  severity: "info",
12279
12295
  minCount: ({ words }) => Math.max(6, words / 250)
12280
12296
  },
12297
+ {
12298
+ id: "ai-emojis",
12299
+ category: "ai",
12300
+ pattern: new RegExp("\\p{Extended_Pictographic}", "gu"),
12301
+ message: "Emoji can read as chatty or AI-styled in formal prose.",
12302
+ severity: "info",
12303
+ suggestion: "Prefer plain prose, or set ignoreEmojis: true to allow them."
12304
+ },
12281
12305
  {
12282
12306
  id: "double-space",
12283
12307
  category: "typography",
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CheckOptions, a as CheckReport, U as UserConfig, R as ResolvedConfig, b as ReplacementStats, S as SanitizeOptions, c as Severity, I as Issue } from './types-BlvvRFG5.cjs';
2
- export { d as Category, e as CheckName, f as CheckSummary, g as ChecksConfig, E as EngineName, h as EnginesConfig, M as MarkdownConfig, P as PatternRule, i as PresetName, j as ReadabilityThresholds, k as SeoThresholds, T as TextFormat, l as TextStats } from './types-BlvvRFG5.cjs';
1
+ import { C as CheckOptions, a as CheckReport, U as UserConfig, R as ResolvedConfig, b as ReplacementStats, S as SanitizeOptions, c as Severity, I as Issue } from './types-BC0TjlU0.cjs';
2
+ export { d as Category, e as CheckName, f as CheckSummary, g as ChecksConfig, E as EngineName, h as EnginesConfig, M as MarkdownConfig, P as PatternRule, i as PresetName, j as ReadabilityThresholds, k as SeoThresholds, T as TextFormat, l as TextStats } from './types-BC0TjlU0.cjs';
3
3
 
4
4
  declare function checkText(text: string, options?: CheckOptions): CheckReport;
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as CheckOptions, a as CheckReport, U as UserConfig, R as ResolvedConfig, b as ReplacementStats, S as SanitizeOptions, c as Severity, I as Issue } from './types-BlvvRFG5.js';
2
- export { d as Category, e as CheckName, f as CheckSummary, g as ChecksConfig, E as EngineName, h as EnginesConfig, M as MarkdownConfig, P as PatternRule, i as PresetName, j as ReadabilityThresholds, k as SeoThresholds, T as TextFormat, l as TextStats } from './types-BlvvRFG5.js';
1
+ import { C as CheckOptions, a as CheckReport, U as UserConfig, R as ResolvedConfig, b as ReplacementStats, S as SanitizeOptions, c as Severity, I as Issue } from './types-BC0TjlU0.js';
2
+ export { d as Category, e as CheckName, f as CheckSummary, g as ChecksConfig, E as EngineName, h as EnginesConfig, M as MarkdownConfig, P as PatternRule, i as PresetName, j as ReadabilityThresholds, k as SeoThresholds, T as TextFormat, l as TextStats } from './types-BC0TjlU0.js';
3
3
 
4
4
  declare function checkText(text: string, options?: CheckOptions): CheckReport;
5
5
 
package/dist/index.js CHANGED
@@ -734,6 +734,14 @@ function validateUserConfig(value) {
734
734
  config.ignoreRules = value.ignoreRules;
735
735
  }
736
736
  }
737
+ const ignoreEmojis = expectBoolean(
738
+ value.ignoreEmojis,
739
+ "ignoreEmojis",
740
+ errors
741
+ );
742
+ if (ignoreEmojis !== void 0) {
743
+ config.ignoreEmojis = ignoreEmojis;
744
+ }
737
745
  if (value.include !== void 0) {
738
746
  if (!isStringArray(value.include)) {
739
747
  errors.push("include must be an array of strings");
@@ -867,6 +875,7 @@ function validateUserConfig(value) {
867
875
  "failOn",
868
876
  "minScore",
869
877
  "ignoreRules",
878
+ "ignoreEmojis",
870
879
  "include",
871
880
  "exclude",
872
881
  "extensions",
@@ -890,7 +899,14 @@ function resolveConfig(user = {}) {
890
899
  format: user.format ?? "auto",
891
900
  failOn: user.failOn ?? "warn",
892
901
  minScore: user.minScore ?? 0,
893
- ignoreRules: user.ignoreRules ?? [],
902
+ ignoreRules: (() => {
903
+ const rules = [...user.ignoreRules ?? []];
904
+ if (user.ignoreEmojis ?? false) {
905
+ rules.push("ai-emojis");
906
+ }
907
+ return rules;
908
+ })(),
909
+ ignoreEmojis: user.ignoreEmojis ?? false,
894
910
  include: user.include ?? [],
895
911
  exclude: user.exclude ?? [],
896
912
  extensions: (user.extensions ?? DEFAULT_EXTENSIONS).map(
@@ -12275,6 +12291,14 @@ var AI_PATTERN_RULES = [
12275
12291
  severity: "info",
12276
12292
  minCount: ({ words }) => Math.max(6, words / 250)
12277
12293
  },
12294
+ {
12295
+ id: "ai-emojis",
12296
+ category: "ai",
12297
+ pattern: new RegExp("\\p{Extended_Pictographic}", "gu"),
12298
+ message: "Emoji can read as chatty or AI-styled in formal prose.",
12299
+ severity: "info",
12300
+ suggestion: "Prefer plain prose, or set ignoreEmojis: true to allow them."
12301
+ },
12278
12302
  {
12279
12303
  id: "double-space",
12280
12304
  category: "typography",
package/dist/node.cjs CHANGED
@@ -742,6 +742,14 @@ function validateUserConfig(value) {
742
742
  config.ignoreRules = value.ignoreRules;
743
743
  }
744
744
  }
745
+ const ignoreEmojis = expectBoolean(
746
+ value.ignoreEmojis,
747
+ "ignoreEmojis",
748
+ errors
749
+ );
750
+ if (ignoreEmojis !== void 0) {
751
+ config.ignoreEmojis = ignoreEmojis;
752
+ }
745
753
  if (value.include !== void 0) {
746
754
  if (!isStringArray(value.include)) {
747
755
  errors.push("include must be an array of strings");
@@ -875,6 +883,7 @@ function validateUserConfig(value) {
875
883
  "failOn",
876
884
  "minScore",
877
885
  "ignoreRules",
886
+ "ignoreEmojis",
878
887
  "include",
879
888
  "exclude",
880
889
  "extensions",
@@ -898,7 +907,14 @@ function resolveConfig(user = {}) {
898
907
  format: user.format ?? "auto",
899
908
  failOn: user.failOn ?? "warn",
900
909
  minScore: user.minScore ?? 0,
901
- ignoreRules: user.ignoreRules ?? [],
910
+ ignoreRules: (() => {
911
+ const rules = [...user.ignoreRules ?? []];
912
+ if (user.ignoreEmojis ?? false) {
913
+ rules.push("ai-emojis");
914
+ }
915
+ return rules;
916
+ })(),
917
+ ignoreEmojis: user.ignoreEmojis ?? false,
902
918
  include: user.include ?? [],
903
919
  exclude: user.exclude ?? [],
904
920
  extensions: (user.extensions ?? DEFAULT_EXTENSIONS).map(
@@ -12373,6 +12389,14 @@ var AI_PATTERN_RULES = [
12373
12389
  severity: "info",
12374
12390
  minCount: ({ words }) => Math.max(6, words / 250)
12375
12391
  },
12392
+ {
12393
+ id: "ai-emojis",
12394
+ category: "ai",
12395
+ pattern: new RegExp("\\p{Extended_Pictographic}", "gu"),
12396
+ message: "Emoji can read as chatty or AI-styled in formal prose.",
12397
+ severity: "info",
12398
+ suggestion: "Prefer plain prose, or set ignoreEmojis: true to allow them."
12399
+ },
12376
12400
  {
12377
12401
  id: "double-space",
12378
12402
  category: "typography",
package/dist/node.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { U as UserConfig, R as ResolvedConfig, C as CheckOptions, a as CheckReport, f as CheckSummary } from './types-BlvvRFG5.cjs';
1
+ import { U as UserConfig, R as ResolvedConfig, C as CheckOptions, a as CheckReport, f as CheckSummary } from './types-BC0TjlU0.cjs';
2
2
 
3
3
  declare class ConfigError extends Error {
4
4
  readonly name = "ConfigError";
package/dist/node.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { U as UserConfig, R as ResolvedConfig, C as CheckOptions, a as CheckReport, f as CheckSummary } from './types-BlvvRFG5.js';
1
+ import { U as UserConfig, R as ResolvedConfig, C as CheckOptions, a as CheckReport, f as CheckSummary } from './types-BC0TjlU0.js';
2
2
 
3
3
  declare class ConfigError extends Error {
4
4
  readonly name = "ConfigError";
package/dist/node.js CHANGED
@@ -734,6 +734,14 @@ function validateUserConfig(value) {
734
734
  config.ignoreRules = value.ignoreRules;
735
735
  }
736
736
  }
737
+ const ignoreEmojis = expectBoolean(
738
+ value.ignoreEmojis,
739
+ "ignoreEmojis",
740
+ errors
741
+ );
742
+ if (ignoreEmojis !== void 0) {
743
+ config.ignoreEmojis = ignoreEmojis;
744
+ }
737
745
  if (value.include !== void 0) {
738
746
  if (!isStringArray(value.include)) {
739
747
  errors.push("include must be an array of strings");
@@ -867,6 +875,7 @@ function validateUserConfig(value) {
867
875
  "failOn",
868
876
  "minScore",
869
877
  "ignoreRules",
878
+ "ignoreEmojis",
870
879
  "include",
871
880
  "exclude",
872
881
  "extensions",
@@ -890,7 +899,14 @@ function resolveConfig(user = {}) {
890
899
  format: user.format ?? "auto",
891
900
  failOn: user.failOn ?? "warn",
892
901
  minScore: user.minScore ?? 0,
893
- ignoreRules: user.ignoreRules ?? [],
902
+ ignoreRules: (() => {
903
+ const rules = [...user.ignoreRules ?? []];
904
+ if (user.ignoreEmojis ?? false) {
905
+ rules.push("ai-emojis");
906
+ }
907
+ return rules;
908
+ })(),
909
+ ignoreEmojis: user.ignoreEmojis ?? false,
894
910
  include: user.include ?? [],
895
911
  exclude: user.exclude ?? [],
896
912
  extensions: (user.extensions ?? DEFAULT_EXTENSIONS).map(
@@ -12365,6 +12381,14 @@ var AI_PATTERN_RULES = [
12365
12381
  severity: "info",
12366
12382
  minCount: ({ words }) => Math.max(6, words / 250)
12367
12383
  },
12384
+ {
12385
+ id: "ai-emojis",
12386
+ category: "ai",
12387
+ pattern: new RegExp("\\p{Extended_Pictographic}", "gu"),
12388
+ message: "Emoji can read as chatty or AI-styled in formal prose.",
12389
+ severity: "info",
12390
+ suggestion: "Prefer plain prose, or set ignoreEmojis: true to allow them."
12391
+ },
12368
12392
  {
12369
12393
  id: "double-space",
12370
12394
  category: "typography",
@@ -90,6 +90,8 @@ type UserConfig = {
90
90
  failOn?: Severity;
91
91
  minScore?: number;
92
92
  ignoreRules?: string[];
93
+ /** When true, skip the ai-emojis rule. Default false (emojis are flagged). */
94
+ ignoreEmojis?: boolean;
93
95
  include?: string[];
94
96
  exclude?: string[];
95
97
  extensions?: string[];
@@ -105,6 +107,7 @@ type ResolvedConfig = {
105
107
  failOn: Severity;
106
108
  minScore: number;
107
109
  ignoreRules: string[];
110
+ ignoreEmojis: boolean;
108
111
  include: string[];
109
112
  exclude: string[];
110
113
  extensions: string[];
@@ -90,6 +90,8 @@ type UserConfig = {
90
90
  failOn?: Severity;
91
91
  minScore?: number;
92
92
  ignoreRules?: string[];
93
+ /** When true, skip the ai-emojis rule. Default false (emojis are flagged). */
94
+ ignoreEmojis?: boolean;
93
95
  include?: string[];
94
96
  exclude?: string[];
95
97
  extensions?: string[];
@@ -105,6 +107,7 @@ type ResolvedConfig = {
105
107
  failOn: Severity;
106
108
  minScore: number;
107
109
  ignoreRules: string[];
110
+ ignoreEmojis: boolean;
108
111
  include: string[];
109
112
  exclude: string[];
110
113
  extensions: string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-text-check",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Detect AI-generated writing tells, grammar issues, and synthetic typography in JavaScript and TypeScript projects.",
5
5
  "license": "MIT",
6
6
  "author": "Pritam Ghosh <contact.meghoshpritam@gmail.com>",