ai-text-check 1.0.0 → 1.2.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 +21 -11
- package/SOURCES.md +8 -3
- package/dist/cli.js +312 -38
- package/dist/index.cjs +280 -25
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +280 -25
- package/dist/node.cjs +286 -31
- package/dist/node.d.cts +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +288 -33
- package/dist/{types-BlvvRFG5.d.cts → types-B6cMXIul.d.cts} +7 -1
- package/dist/{types-BlvvRFG5.d.ts → types-B6cMXIul.d.ts} +7 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import '
|
|
2
|
-
import '
|
|
1
|
+
import { lintText } from 'ai-slop-linter';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
3
4
|
import 'url';
|
|
4
5
|
import { analyze } from 'is-this-ai-slop';
|
|
5
6
|
import { createRequire } from 'module';
|
|
@@ -565,6 +566,9 @@ var ENGINE_PRESETS = {
|
|
|
565
566
|
isThisAiSlop: true,
|
|
566
567
|
veldica: true,
|
|
567
568
|
cleanWriting: true,
|
|
569
|
+
aiSlopLinter: true,
|
|
570
|
+
slopDetector: true,
|
|
571
|
+
proseSlop: true,
|
|
568
572
|
vale: true
|
|
569
573
|
},
|
|
570
574
|
strict: {
|
|
@@ -575,6 +579,9 @@ var ENGINE_PRESETS = {
|
|
|
575
579
|
isThisAiSlop: true,
|
|
576
580
|
veldica: true,
|
|
577
581
|
cleanWriting: true,
|
|
582
|
+
aiSlopLinter: true,
|
|
583
|
+
slopDetector: true,
|
|
584
|
+
proseSlop: true,
|
|
578
585
|
vale: true
|
|
579
586
|
},
|
|
580
587
|
ai: {
|
|
@@ -585,6 +592,9 @@ var ENGINE_PRESETS = {
|
|
|
585
592
|
isThisAiSlop: true,
|
|
586
593
|
veldica: true,
|
|
587
594
|
cleanWriting: true,
|
|
595
|
+
aiSlopLinter: true,
|
|
596
|
+
slopDetector: true,
|
|
597
|
+
proseSlop: true,
|
|
588
598
|
vale: true
|
|
589
599
|
},
|
|
590
600
|
grammar: {
|
|
@@ -595,6 +605,9 @@ var ENGINE_PRESETS = {
|
|
|
595
605
|
isThisAiSlop: false,
|
|
596
606
|
veldica: false,
|
|
597
607
|
cleanWriting: true,
|
|
608
|
+
aiSlopLinter: false,
|
|
609
|
+
slopDetector: false,
|
|
610
|
+
proseSlop: false,
|
|
598
611
|
vale: true
|
|
599
612
|
}
|
|
600
613
|
};
|
|
@@ -615,6 +628,9 @@ var ENGINE_KEYS = [
|
|
|
615
628
|
"isThisAiSlop",
|
|
616
629
|
"veldica",
|
|
617
630
|
"cleanWriting",
|
|
631
|
+
"aiSlopLinter",
|
|
632
|
+
"slopDetector",
|
|
633
|
+
"proseSlop",
|
|
618
634
|
"vale"
|
|
619
635
|
];
|
|
620
636
|
function isObject(value) {
|
|
@@ -734,6 +750,14 @@ function validateUserConfig(value) {
|
|
|
734
750
|
config.ignoreRules = value.ignoreRules;
|
|
735
751
|
}
|
|
736
752
|
}
|
|
753
|
+
const ignoreEmojis = expectBoolean(
|
|
754
|
+
value.ignoreEmojis,
|
|
755
|
+
"ignoreEmojis",
|
|
756
|
+
errors
|
|
757
|
+
);
|
|
758
|
+
if (ignoreEmojis !== void 0) {
|
|
759
|
+
config.ignoreEmojis = ignoreEmojis;
|
|
760
|
+
}
|
|
737
761
|
if (value.include !== void 0) {
|
|
738
762
|
if (!isStringArray(value.include)) {
|
|
739
763
|
errors.push("include must be an array of strings");
|
|
@@ -867,6 +891,7 @@ function validateUserConfig(value) {
|
|
|
867
891
|
"failOn",
|
|
868
892
|
"minScore",
|
|
869
893
|
"ignoreRules",
|
|
894
|
+
"ignoreEmojis",
|
|
870
895
|
"include",
|
|
871
896
|
"exclude",
|
|
872
897
|
"extensions",
|
|
@@ -890,7 +915,14 @@ function resolveConfig(user = {}) {
|
|
|
890
915
|
format: user.format ?? "auto",
|
|
891
916
|
failOn: user.failOn ?? "warn",
|
|
892
917
|
minScore: user.minScore ?? 0,
|
|
893
|
-
ignoreRules:
|
|
918
|
+
ignoreRules: (() => {
|
|
919
|
+
const rules = [...user.ignoreRules ?? []];
|
|
920
|
+
if (user.ignoreEmojis ?? false) {
|
|
921
|
+
rules.push("ai-emojis");
|
|
922
|
+
}
|
|
923
|
+
return rules;
|
|
924
|
+
})(),
|
|
925
|
+
ignoreEmojis: user.ignoreEmojis ?? false,
|
|
894
926
|
include: user.include ?? [],
|
|
895
927
|
exclude: user.exclude ?? [],
|
|
896
928
|
extensions: (user.extensions ?? DEFAULT_EXTENSIONS).map(
|
|
@@ -927,6 +959,27 @@ function defineConfig(config) {
|
|
|
927
959
|
function isStrictPreset(config) {
|
|
928
960
|
return config.preset === "strict";
|
|
929
961
|
}
|
|
962
|
+
function toSeverity(value) {
|
|
963
|
+
if (value === "error") return "error";
|
|
964
|
+
if (value === "warning" || value === "warn") return "warn";
|
|
965
|
+
return "info";
|
|
966
|
+
}
|
|
967
|
+
function runAiSlopLinter(text, options = {}) {
|
|
968
|
+
const result = lintText(options.source ?? "<text>", text, { floor: 0 });
|
|
969
|
+
return result.findings.map((finding) => {
|
|
970
|
+
const issue = {
|
|
971
|
+
rule: `asl-${finding.rule}`,
|
|
972
|
+
engine: "ai-slop-linter",
|
|
973
|
+
category: "ai",
|
|
974
|
+
severity: toSeverity(finding.severity),
|
|
975
|
+
message: finding.message,
|
|
976
|
+
line: finding.line,
|
|
977
|
+
column: finding.column,
|
|
978
|
+
excerpt: finding.excerpt
|
|
979
|
+
};
|
|
980
|
+
return issue;
|
|
981
|
+
});
|
|
982
|
+
}
|
|
930
983
|
|
|
931
984
|
// node_modules/clean-writing-lint/src/mask.js
|
|
932
985
|
function blank(text) {
|
|
@@ -1896,7 +1949,7 @@ var AI_RULES = /* @__PURE__ */ new Set([
|
|
|
1896
1949
|
"banned-construction",
|
|
1897
1950
|
"em-dash"
|
|
1898
1951
|
]);
|
|
1899
|
-
function
|
|
1952
|
+
function toSeverity2(value) {
|
|
1900
1953
|
if (value === "error") return "error";
|
|
1901
1954
|
if (value === "warn") return "warn";
|
|
1902
1955
|
return "info";
|
|
@@ -1916,7 +1969,7 @@ function runCleanWriting(text) {
|
|
|
1916
1969
|
rule: `cws-${violation.rule}`,
|
|
1917
1970
|
engine: "clean-writing",
|
|
1918
1971
|
category: AI_RULES.has(violation.rule) ? "ai" : "grammar",
|
|
1919
|
-
severity:
|
|
1972
|
+
severity: toSeverity2(violation.severity),
|
|
1920
1973
|
message: violation.message,
|
|
1921
1974
|
line: violation.line,
|
|
1922
1975
|
column: violation.column,
|
|
@@ -1943,6 +1996,33 @@ function runIsThisAiSlop(text) {
|
|
|
1943
1996
|
return issue;
|
|
1944
1997
|
});
|
|
1945
1998
|
}
|
|
1999
|
+
var require2 = createRequire(import.meta.url);
|
|
2000
|
+
var { check } = require2("prose-slop");
|
|
2001
|
+
function toSeverity3(value) {
|
|
2002
|
+
if (value === "error") return "error";
|
|
2003
|
+
if (value === "warning" || value === "warn") return "warn";
|
|
2004
|
+
return "info";
|
|
2005
|
+
}
|
|
2006
|
+
function runProseSlop(text, options = {}) {
|
|
2007
|
+
const findings = check(text, {
|
|
2008
|
+
format: options.format ?? "plain",
|
|
2009
|
+
lang: "en"
|
|
2010
|
+
});
|
|
2011
|
+
return findings.map((finding) => {
|
|
2012
|
+
const issue = {
|
|
2013
|
+
rule: `prose-${finding.ruleId}`,
|
|
2014
|
+
engine: "prose-slop",
|
|
2015
|
+
category: "ai",
|
|
2016
|
+
severity: toSeverity3(finding.severity),
|
|
2017
|
+
message: finding.message,
|
|
2018
|
+
line: finding.line,
|
|
2019
|
+
column: finding.column,
|
|
2020
|
+
excerpt: excerptAround(text, finding.index),
|
|
2021
|
+
match: finding.match
|
|
2022
|
+
};
|
|
2023
|
+
return issue;
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
1946
2026
|
|
|
1947
2027
|
// node_modules/nlcst-to-string/lib/index.js
|
|
1948
2028
|
var emptyNodes = [];
|
|
@@ -2904,10 +2984,10 @@ function anyFactory(tests) {
|
|
|
2904
2984
|
return false;
|
|
2905
2985
|
}
|
|
2906
2986
|
}
|
|
2907
|
-
function propertiesFactory(
|
|
2987
|
+
function propertiesFactory(check2) {
|
|
2908
2988
|
const checkAsRecord = (
|
|
2909
2989
|
/** @type {Record<string, unknown>} */
|
|
2910
|
-
|
|
2990
|
+
check2
|
|
2911
2991
|
);
|
|
2912
2992
|
return castFactory(all);
|
|
2913
2993
|
function all(node) {
|
|
@@ -2917,21 +2997,21 @@ function propertiesFactory(check) {
|
|
|
2917
2997
|
node
|
|
2918
2998
|
);
|
|
2919
2999
|
let key;
|
|
2920
|
-
for (key in
|
|
3000
|
+
for (key in check2) {
|
|
2921
3001
|
if (nodeAsRecord[key] !== checkAsRecord[key]) return false;
|
|
2922
3002
|
}
|
|
2923
3003
|
return true;
|
|
2924
3004
|
}
|
|
2925
3005
|
}
|
|
2926
|
-
function typeFactory(
|
|
3006
|
+
function typeFactory(check2) {
|
|
2927
3007
|
return castFactory(type);
|
|
2928
3008
|
function type(node) {
|
|
2929
|
-
return node && node.type ===
|
|
3009
|
+
return node && node.type === check2;
|
|
2930
3010
|
}
|
|
2931
3011
|
}
|
|
2932
3012
|
function castFactory(testFunction) {
|
|
2933
|
-
return
|
|
2934
|
-
function
|
|
3013
|
+
return check2;
|
|
3014
|
+
function check2(value, index2, parent) {
|
|
2935
3015
|
return Boolean(
|
|
2936
3016
|
looksLikeANode(value) && testFunction.call(
|
|
2937
3017
|
this,
|
|
@@ -2960,14 +3040,14 @@ var CONTINUE = true;
|
|
|
2960
3040
|
var EXIT = false;
|
|
2961
3041
|
var SKIP = "skip";
|
|
2962
3042
|
function visitParents(tree, test, visitor, reverse) {
|
|
2963
|
-
let
|
|
3043
|
+
let check2;
|
|
2964
3044
|
if (typeof test === "function" && typeof visitor !== "function") {
|
|
2965
3045
|
reverse = visitor;
|
|
2966
3046
|
visitor = test;
|
|
2967
3047
|
} else {
|
|
2968
|
-
|
|
3048
|
+
check2 = test;
|
|
2969
3049
|
}
|
|
2970
|
-
const is2 = convert(
|
|
3050
|
+
const is2 = convert(check2);
|
|
2971
3051
|
const step = reverse ? -1 : 1;
|
|
2972
3052
|
factory(tree, void 0, [])();
|
|
2973
3053
|
function factory(node, index2, parents) {
|
|
@@ -9860,9 +9940,9 @@ var VFile = class {
|
|
|
9860
9940
|
* @returns {undefined}
|
|
9861
9941
|
* Nothing.
|
|
9862
9942
|
*/
|
|
9863
|
-
set dirname(
|
|
9943
|
+
set dirname(dirname4) {
|
|
9864
9944
|
assertPath2(this.basename, "dirname");
|
|
9865
|
-
this.path = minpath.join(
|
|
9945
|
+
this.path = minpath.join(dirname4 || "", this.basename);
|
|
9866
9946
|
}
|
|
9867
9947
|
/**
|
|
9868
9948
|
* Get the extname (including dot) (example: `'.js'`).
|
|
@@ -10885,6 +10965,160 @@ function runRetext(text) {
|
|
|
10885
10965
|
return issue;
|
|
10886
10966
|
});
|
|
10887
10967
|
}
|
|
10968
|
+
var WEIGHT_WORD = 0.5;
|
|
10969
|
+
var WEIGHT_PATTERN = 0.2;
|
|
10970
|
+
var WEIGHT_TRIGRAM = 0.12;
|
|
10971
|
+
var WEIGHT_TROPE = 0.18;
|
|
10972
|
+
var WORD_MULTIPLIER = 1e3;
|
|
10973
|
+
var TRIGRAM_MULTIPLIER = 1e3;
|
|
10974
|
+
var CONTRAST_PATTERN = /\b(?:it(?:'s| is)|this is|that(?:'s| is)|(?:it|this|that) isn'?t)\s+(?:just |only |merely |simply )?[a-z][\s\S]{0,80}?\b(?:it(?:'s| is)|this is|that(?:'s| is)|but)\b/gi;
|
|
10975
|
+
var NOT_BUT_PATTERN = /\bnot\b[\s\S]{0,60}?\bbut\b/gi;
|
|
10976
|
+
var require3 = createRequire(import.meta.url);
|
|
10977
|
+
var assetsDir = join(
|
|
10978
|
+
dirname(require3.resolve("slop-detector/package.json")),
|
|
10979
|
+
"dist",
|
|
10980
|
+
"assets"
|
|
10981
|
+
);
|
|
10982
|
+
var cachedAssets = null;
|
|
10983
|
+
function computeRange(values) {
|
|
10984
|
+
if (values.length === 0) return { min: 0, max: 1 };
|
|
10985
|
+
const min = Math.min(...values);
|
|
10986
|
+
const max = Math.max(...values);
|
|
10987
|
+
const range = max - min || 1;
|
|
10988
|
+
return { min: min - range * 0.1, max: max + range * 0.1 };
|
|
10989
|
+
}
|
|
10990
|
+
function loadAssets() {
|
|
10991
|
+
if (cachedAssets) return cachedAssets;
|
|
10992
|
+
const wordsRaw = JSON.parse(
|
|
10993
|
+
readFileSync(join(assetsDir, "slop_list.json"), "utf8")
|
|
10994
|
+
);
|
|
10995
|
+
const trigramsRaw = JSON.parse(
|
|
10996
|
+
readFileSync(join(assetsDir, "slop_list_trigrams.json"), "utf8")
|
|
10997
|
+
);
|
|
10998
|
+
const leaderboard = JSON.parse(
|
|
10999
|
+
readFileSync(join(assetsDir, "leaderboard_results.json"), "utf8")
|
|
11000
|
+
);
|
|
11001
|
+
const words = /* @__PURE__ */ new Set();
|
|
11002
|
+
for (const item of wordsRaw) {
|
|
11003
|
+
if (Array.isArray(item) && item[0]) words.add(item[0].toLowerCase());
|
|
11004
|
+
}
|
|
11005
|
+
const trigrams = /* @__PURE__ */ new Set();
|
|
11006
|
+
for (const item of trigramsRaw) {
|
|
11007
|
+
if (Array.isArray(item) && item[0]) trigrams.add(item[0].toLowerCase());
|
|
11008
|
+
}
|
|
11009
|
+
const metrics = {
|
|
11010
|
+
slop_words: [],
|
|
11011
|
+
slop_trigrams: [],
|
|
11012
|
+
contrast: []
|
|
11013
|
+
};
|
|
11014
|
+
for (const res of leaderboard.results ?? []) {
|
|
11015
|
+
if (!res.metrics) continue;
|
|
11016
|
+
metrics.slop_words.push(res.metrics.slop_list_matches_per_1k_words || 0);
|
|
11017
|
+
metrics.slop_trigrams.push(
|
|
11018
|
+
res.metrics.slop_trigram_matches_per_1k_words || 0
|
|
11019
|
+
);
|
|
11020
|
+
metrics.contrast.push(res.metrics.not_x_but_y_per_1k_chars || 0);
|
|
11021
|
+
}
|
|
11022
|
+
cachedAssets = {
|
|
11023
|
+
words,
|
|
11024
|
+
trigrams,
|
|
11025
|
+
normalizationRanges: {
|
|
11026
|
+
slop_words: computeRange(metrics.slop_words),
|
|
11027
|
+
slop_trigrams: computeRange(metrics.slop_trigrams),
|
|
11028
|
+
contrast: computeRange(metrics.contrast)
|
|
11029
|
+
}
|
|
11030
|
+
};
|
|
11031
|
+
return cachedAssets;
|
|
11032
|
+
}
|
|
11033
|
+
function normalizeValue(value, range) {
|
|
11034
|
+
const normalized = (value - range.min) / (range.max - range.min);
|
|
11035
|
+
return Math.max(0, Math.min(1, normalized));
|
|
11036
|
+
}
|
|
11037
|
+
function toPlainText(text) {
|
|
11038
|
+
return text.replace(/```[\s\S]*?```/g, " ").replace(/`[^`\n]+`/g, " ").replace(/<[^>]+>/g, " ").replace(/!\[[^\]]*]\([^)]*\)/g, " ").replace(/\[[^\]]*]\([^)]*\)/g, " ").replace(/^#{1,6}\s+/gm, "").replace(/[*_~>#-]+/g, " ");
|
|
11039
|
+
}
|
|
11040
|
+
function tokenize(text) {
|
|
11041
|
+
return text.toLowerCase().match(/[a-z]+(?:'[a-z]+)?/g) ?? [];
|
|
11042
|
+
}
|
|
11043
|
+
function collectMatches(pattern, text) {
|
|
11044
|
+
return [...text.matchAll(pattern)].map((match) => match[0] ?? "");
|
|
11045
|
+
}
|
|
11046
|
+
function runSlopDetector(text) {
|
|
11047
|
+
if (!text.trim()) return [];
|
|
11048
|
+
const assets = loadAssets();
|
|
11049
|
+
const plain = toPlainText(text);
|
|
11050
|
+
const tokens = tokenize(plain);
|
|
11051
|
+
const nTokens = tokens.length || 1;
|
|
11052
|
+
let wordHitCount = 0;
|
|
11053
|
+
const wordHitMap = /* @__PURE__ */ new Map();
|
|
11054
|
+
for (const token of tokens) {
|
|
11055
|
+
if (!assets.words.has(token)) continue;
|
|
11056
|
+
wordHitCount++;
|
|
11057
|
+
wordHitMap.set(token, (wordHitMap.get(token) || 0) + 1);
|
|
11058
|
+
}
|
|
11059
|
+
let trigramHitCount = 0;
|
|
11060
|
+
if (tokens.length >= 3) {
|
|
11061
|
+
for (let i = 0; i < tokens.length - 2; i++) {
|
|
11062
|
+
const tg = `${tokens[i]} ${tokens[i + 1]} ${tokens[i + 2]}`;
|
|
11063
|
+
if (assets.trigrams.has(tg)) trigramHitCount++;
|
|
11064
|
+
}
|
|
11065
|
+
}
|
|
11066
|
+
const contrastMatches = [
|
|
11067
|
+
.../* @__PURE__ */ new Set([
|
|
11068
|
+
...collectMatches(CONTRAST_PATTERN, plain),
|
|
11069
|
+
...collectMatches(NOT_BUT_PATTERN, plain)
|
|
11070
|
+
])
|
|
11071
|
+
];
|
|
11072
|
+
const emDashCount = (text.match(/—/g) ?? []).length;
|
|
11073
|
+
const tropeRate = emDashCount / Math.max(plain.length, 1) * 1e3;
|
|
11074
|
+
const wordScore = wordHitCount / nTokens * WORD_MULTIPLIER;
|
|
11075
|
+
const trigramScore = trigramHitCount / nTokens * TRIGRAM_MULTIPLIER;
|
|
11076
|
+
const contrastScore = contrastMatches.length / Math.max(plain.length, 1) * 1e3;
|
|
11077
|
+
const rawSlopScore = (normalizeValue(wordScore, assets.normalizationRanges.slop_words) * WEIGHT_WORD + normalizeValue(contrastScore, assets.normalizationRanges.contrast) * WEIGHT_PATTERN + normalizeValue(trigramScore, assets.normalizationRanges.slop_trigrams) * WEIGHT_TRIGRAM + normalizeValue(tropeRate, { min: 0, max: 5 }) * WEIGHT_TROPE) * 100;
|
|
11078
|
+
const slopScore = Math.round(rawSlopScore * 10) / 10;
|
|
11079
|
+
const issues = [];
|
|
11080
|
+
if (slopScore >= 40) {
|
|
11081
|
+
issues.push({
|
|
11082
|
+
rule: "eqbench-slop-score",
|
|
11083
|
+
engine: "slop-detector",
|
|
11084
|
+
category: "ai",
|
|
11085
|
+
severity: slopScore >= 60 ? "warn" : "info",
|
|
11086
|
+
message: `EQBench SLOP score ${slopScore}/100 (higher = more AI-like).`,
|
|
11087
|
+
suggestion: slopScore >= 60 ? "Rewrite stock phrasing and contrast constructions." : "Review flagged vocabulary and contrast patterns."
|
|
11088
|
+
});
|
|
11089
|
+
}
|
|
11090
|
+
for (const [word2, count] of [...wordHitMap.entries()].sort((a, b) => b[1] - a[1]).slice(0, 8)) {
|
|
11091
|
+
issues.push({
|
|
11092
|
+
rule: `eqbench-word-${word2.replace(/\s+/g, "-")}`,
|
|
11093
|
+
engine: "slop-detector",
|
|
11094
|
+
category: "ai",
|
|
11095
|
+
severity: "info",
|
|
11096
|
+
message: `EQBench slop vocabulary: \u201C${word2}\u201D (${count}\xD7).`,
|
|
11097
|
+
match: word2
|
|
11098
|
+
});
|
|
11099
|
+
}
|
|
11100
|
+
for (const match of contrastMatches.slice(0, 5)) {
|
|
11101
|
+
issues.push({
|
|
11102
|
+
rule: "eqbench-contrast",
|
|
11103
|
+
engine: "slop-detector",
|
|
11104
|
+
category: "ai",
|
|
11105
|
+
severity: "info",
|
|
11106
|
+
message: `EQBench contrast pattern: \u201C${match.trim()}\u201D`,
|
|
11107
|
+
match
|
|
11108
|
+
});
|
|
11109
|
+
}
|
|
11110
|
+
if (emDashCount >= 3) {
|
|
11111
|
+
issues.push({
|
|
11112
|
+
rule: "eqbench-trope-em-dash",
|
|
11113
|
+
engine: "slop-detector",
|
|
11114
|
+
category: "ai",
|
|
11115
|
+
severity: "info",
|
|
11116
|
+
message: `EQBench typography trope: ${emDashCount} em dash(es).`,
|
|
11117
|
+
match: "\u2014"
|
|
11118
|
+
});
|
|
11119
|
+
}
|
|
11120
|
+
return issues;
|
|
11121
|
+
}
|
|
10888
11122
|
|
|
10889
11123
|
// src/engines/tag.ts
|
|
10890
11124
|
function tagEngine(issues, engine) {
|
|
@@ -11256,7 +11490,7 @@ function countListItems(input) {
|
|
|
11256
11490
|
function countBlockquotes(input) {
|
|
11257
11491
|
return getLineMetadata(input).blockquote_count;
|
|
11258
11492
|
}
|
|
11259
|
-
function
|
|
11493
|
+
function tokenize2(text) {
|
|
11260
11494
|
const blocks = splitParagraphBlocks(text);
|
|
11261
11495
|
const paragraphs2 = blocks.map((block) => block.text);
|
|
11262
11496
|
const sentences2 = splitSentencesFromBlocks(blocks);
|
|
@@ -11278,7 +11512,7 @@ function tokenize(text) {
|
|
|
11278
11512
|
}
|
|
11279
11513
|
};
|
|
11280
11514
|
}
|
|
11281
|
-
var tokenizeProse =
|
|
11515
|
+
var tokenizeProse = tokenize2;
|
|
11282
11516
|
|
|
11283
11517
|
// node_modules/@veldica/prose-analyzer/dist/utils.js
|
|
11284
11518
|
function round(value, decimals = 4) {
|
|
@@ -12022,7 +12256,7 @@ function inventoryMarkers(text, options = {}) {
|
|
|
12022
12256
|
}
|
|
12023
12257
|
|
|
12024
12258
|
// src/engines/veldica.ts
|
|
12025
|
-
function
|
|
12259
|
+
function toSeverity4(value) {
|
|
12026
12260
|
if (value === "high") return "warn";
|
|
12027
12261
|
return "info";
|
|
12028
12262
|
}
|
|
@@ -12037,7 +12271,7 @@ function runVeldica(text) {
|
|
|
12037
12271
|
rule: `veldica-${match.category || "marker"}`,
|
|
12038
12272
|
engine: "veldica",
|
|
12039
12273
|
category: "ai",
|
|
12040
|
-
severity:
|
|
12274
|
+
severity: toSeverity4(match.severity),
|
|
12041
12275
|
message: `AI-style marker (${match.category}): \u201C${match.matched_text}\u201D`,
|
|
12042
12276
|
excerpt: excerptAround(text, offset),
|
|
12043
12277
|
match: match.matched_text
|
|
@@ -12050,8 +12284,8 @@ function runVeldica(text) {
|
|
|
12050
12284
|
return issue;
|
|
12051
12285
|
});
|
|
12052
12286
|
}
|
|
12053
|
-
var
|
|
12054
|
-
var writeGood =
|
|
12287
|
+
var require4 = createRequire(import.meta.url);
|
|
12288
|
+
var writeGood = require4("write-good");
|
|
12055
12289
|
function runWriteGood(text) {
|
|
12056
12290
|
const suggestions = writeGood(text, {
|
|
12057
12291
|
so: false,
|
|
@@ -12275,6 +12509,14 @@ var AI_PATTERN_RULES = [
|
|
|
12275
12509
|
severity: "info",
|
|
12276
12510
|
minCount: ({ words }) => Math.max(6, words / 250)
|
|
12277
12511
|
},
|
|
12512
|
+
{
|
|
12513
|
+
id: "ai-emojis",
|
|
12514
|
+
category: "ai",
|
|
12515
|
+
pattern: new RegExp("\\p{Extended_Pictographic}", "gu"),
|
|
12516
|
+
message: "Emoji can read as chatty or AI-styled in formal prose.",
|
|
12517
|
+
severity: "info",
|
|
12518
|
+
suggestion: "Prefer plain prose, or set ignoreEmojis: true to allow them."
|
|
12519
|
+
},
|
|
12278
12520
|
{
|
|
12279
12521
|
id: "double-space",
|
|
12280
12522
|
category: "typography",
|
|
@@ -13143,7 +13385,7 @@ function computeStats(body, titleLength, descriptionLength, issues) {
|
|
|
13143
13385
|
descriptionLength
|
|
13144
13386
|
};
|
|
13145
13387
|
}
|
|
13146
|
-
function collectIssues(body, frontmatter, format, config) {
|
|
13388
|
+
function collectIssues(body, frontmatter, format, config, source2) {
|
|
13147
13389
|
const ignoreRules = new Set(config.ignoreRules);
|
|
13148
13390
|
const issues = [];
|
|
13149
13391
|
const enginesRun = [];
|
|
@@ -13216,6 +13458,18 @@ function collectIssues(body, frontmatter, format, config) {
|
|
|
13216
13458
|
enginesRun.push("clean-writing");
|
|
13217
13459
|
issues.push(...runCleanWriting(body));
|
|
13218
13460
|
}
|
|
13461
|
+
if (config.engines.aiSlopLinter && config.checks.ai) {
|
|
13462
|
+
enginesRun.push("ai-slop-linter");
|
|
13463
|
+
issues.push(...runAiSlopLinter(body, { source: source2 }));
|
|
13464
|
+
}
|
|
13465
|
+
if (config.engines.slopDetector && config.checks.ai) {
|
|
13466
|
+
enginesRun.push("slop-detector");
|
|
13467
|
+
issues.push(...runSlopDetector(body));
|
|
13468
|
+
}
|
|
13469
|
+
if (config.engines.proseSlop && config.checks.ai) {
|
|
13470
|
+
enginesRun.push("prose-slop");
|
|
13471
|
+
issues.push(...runProseSlop(body, { format }));
|
|
13472
|
+
}
|
|
13219
13473
|
return {
|
|
13220
13474
|
issues: issues.filter((issue) => !ignoreRules.has(issue.rule)),
|
|
13221
13475
|
enginesRun: uniqueEngines(enginesRun)
|
|
@@ -13231,7 +13485,8 @@ function checkText(text, options = {}) {
|
|
|
13231
13485
|
body,
|
|
13232
13486
|
parsed.frontmatter,
|
|
13233
13487
|
format,
|
|
13234
|
-
config
|
|
13488
|
+
config,
|
|
13489
|
+
source2
|
|
13235
13490
|
);
|
|
13236
13491
|
const title = String(parsed.frontmatter.title ?? pathBasename(source2));
|
|
13237
13492
|
const report = {
|