@domandigital/craft 0.15.0 → 0.17.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/CHANGELOG.md +18 -0
- package/CHARACTER.md +51 -0
- package/COPY.md +5 -0
- package/README.md +8 -0
- package/REGISTERS.md +163 -0
- package/dist/{audit-MTUC24XU.js → audit-4SFSLCKY.js} +3 -2
- package/dist/audit.cjs +1 -1
- package/dist/audit.d.cts +7 -0
- package/dist/audit.d.ts +7 -0
- package/dist/audit.js +1 -1
- package/dist/chunk-4QWEAL4G.js +1595 -0
- package/dist/{chunk-YDURAOYR.js → chunk-6TSDYETQ.js} +4 -2
- package/dist/{chunk-2IQ5OXFR.js → chunk-DARKHE6A.js} +7 -5
- package/dist/{cli-FCKHYAVZ.js → chunk-NTIPJ5U7.js} +2 -185
- package/dist/{chunk-MUVFECFC.js → chunk-O5B5ELJH.js} +46 -21
- package/dist/chunk-QIEDBL4J.js +9 -0
- package/dist/{chunk-QU6Q2QZZ.js → chunk-RJVG5KA6.js} +8 -6
- package/dist/{chunk-OUQ25LY2.js → chunk-SL5VZJ2J.js} +1 -1
- package/dist/{chunk-LFNSB6W7.js → chunk-WFB6F3BN.js} +66 -1633
- package/dist/{chunk-RXXRXV3V.js → chunk-ZUYERAFM.js} +178 -18
- package/dist/{cli-FLG3ZCAF.js → cli-BN4IT6N2.js} +13 -5
- package/dist/{cli-22TSWAX6.js → cli-GXIW7F3E.js} +7 -5
- package/dist/cli-JB4X5LAG.js +1573 -0
- package/dist/{cli-5ACKICBO.js → cli-JZRQBCD4.js} +7 -5
- package/dist/cli-MDW7JTEF.js +246 -0
- package/dist/cli-V44QEVS6.js +193 -0
- package/dist/{cli-7OZCYOQY.js → cli-Y7Y5IROK.js} +8 -5
- package/dist/cli.js +4 -2
- package/dist/index.cjs +1597 -101
- package/dist/index.d.cts +311 -2
- package/dist/index.d.ts +311 -2
- package/dist/index.js +1569 -101
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
CHOICE_KEYS: () => CHOICE_KEYS,
|
|
34
34
|
COMPONENT_ROLES: () => COMPONENT_ROLES,
|
|
35
35
|
CONSIDERATION: () => CONSIDERATION,
|
|
36
|
+
CONTENT_FEATURES: () => CONTENT_FEATURES,
|
|
36
37
|
CONVENTION: () => CONVENTION,
|
|
37
38
|
CUSTOMER_KINDS: () => CUSTOMER_KINDS,
|
|
38
39
|
DEFAULT_IGNORE: () => DEFAULT_IGNORE,
|
|
@@ -49,6 +50,7 @@ __export(index_exports, {
|
|
|
49
50
|
ESTATE_VERSION: () => ESTATE_VERSION,
|
|
50
51
|
EXIT_RATIO: () => EXIT_RATIO,
|
|
51
52
|
FINGERPRINT_VERSION: () => FINGERPRINT_VERSION,
|
|
53
|
+
FLAGGED_TARGET: () => FLAGGED_TARGET,
|
|
52
54
|
FUNCTION_WORDS: () => FUNCTION_WORDS,
|
|
53
55
|
GROUND_SCALE: () => GROUND_SCALE,
|
|
54
56
|
GROUND_SHARED: () => GROUND_SHARED,
|
|
@@ -59,11 +61,15 @@ __export(index_exports, {
|
|
|
59
61
|
HOUSE_BUDGET: () => HOUSE_BUDGET,
|
|
60
62
|
HOUSE_LOCKED: () => HOUSE_LOCKED,
|
|
61
63
|
HOUSE_TYPE: () => HOUSE_TYPE,
|
|
64
|
+
HUMAN_TYPICAL_TARGET: () => HUMAN_TYPICAL_TARGET,
|
|
62
65
|
IMAGERY_TELLS: () => IMAGERY_TELLS,
|
|
63
66
|
JSON_SCHEMA_VERSION: () => JSON_SCHEMA_VERSION,
|
|
67
|
+
LABELS: () => LABELS2,
|
|
68
|
+
LEXICAL_FEATURES: () => LEXICAL_FEATURES,
|
|
64
69
|
LICENCES: () => LICENCES,
|
|
65
70
|
LIGHTNESS_CURVE: () => LIGHTNESS_CURVE,
|
|
66
71
|
MIN_DECIDED: () => MIN_DECIDED,
|
|
72
|
+
MIN_PARAGRAPHS: () => MIN_PARAGRAPHS,
|
|
67
73
|
MIN_RUNS: () => MIN_RUNS,
|
|
68
74
|
MOOD: () => MOOD,
|
|
69
75
|
NEGATIVE_REASSURANCE: () => NEGATIVE_REASSURANCE,
|
|
@@ -72,6 +78,9 @@ __export(index_exports, {
|
|
|
72
78
|
PILL_LIMIT: () => PILL_LIMIT,
|
|
73
79
|
PLAINER_WORDS: () => PLAINER_WORDS,
|
|
74
80
|
PREFERENCE: () => PREFERENCE,
|
|
81
|
+
PROFILE: () => PROFILE,
|
|
82
|
+
PROFILE_MEASURED: () => PROFILE_MEASURED,
|
|
83
|
+
PROFILE_PARAGRAPHS: () => PROFILE_PARAGRAPHS,
|
|
75
84
|
PROMO_BADGE: () => PROMO_BADGE,
|
|
76
85
|
PROOF_NAMES: () => PROOF_NAMES,
|
|
77
86
|
PROPOSED: () => PROPOSED,
|
|
@@ -80,6 +89,10 @@ __export(index_exports, {
|
|
|
80
89
|
READABLE_SNAPSHOT_VERSIONS: () => READABLE_SNAPSHOT_VERSIONS,
|
|
81
90
|
REFLEX_FONTS_1: () => REFLEX_FONTS_1,
|
|
82
91
|
REFLEX_FONTS_2: () => REFLEX_FONTS_2,
|
|
92
|
+
REGISTERS: () => REGISTERS,
|
|
93
|
+
REGISTER_BASELINE: () => REGISTER_BASELINE,
|
|
94
|
+
REGISTER_FEATURES: () => REGISTER_FEATURES,
|
|
95
|
+
REGISTER_IDS: () => REGISTER_IDS,
|
|
83
96
|
RENDERED_PATHS: () => RENDERED_PATHS,
|
|
84
97
|
RENDERED_TELLS: () => RENDERED_TELLS,
|
|
85
98
|
REVEAL_LIMIT: () => REVEAL_LIMIT,
|
|
@@ -101,6 +114,7 @@ __export(index_exports, {
|
|
|
101
114
|
STOCK_FIGURES: () => STOCK_FIGURES,
|
|
102
115
|
STOCK_PHOTO_HOSTS: () => STOCK_PHOTO_HOSTS,
|
|
103
116
|
STOCK_PHRASES: () => STOCK_PHRASES,
|
|
117
|
+
STUDY_WORDS: () => STUDY_WORDS,
|
|
104
118
|
TELL_HEAVY: () => TELL_HEAVY,
|
|
105
119
|
TRADE_NOUNS: () => TRADE_NOUNS,
|
|
106
120
|
TYPE_STEPS: () => TYPE_STEPS,
|
|
@@ -114,12 +128,14 @@ __export(index_exports, {
|
|
|
114
128
|
applySeverity: () => applySeverity,
|
|
115
129
|
auditSnapshot: () => auditSnapshot,
|
|
116
130
|
briefTerms: () => briefTerms,
|
|
131
|
+
calibrate: () => calibrate,
|
|
117
132
|
catalogueTable: () => catalogueTable,
|
|
118
133
|
characterReport: () => characterReport,
|
|
119
134
|
checkCopy: () => checkCopy,
|
|
120
135
|
checkOrder: () => checkOrder,
|
|
121
136
|
checkPair: () => checkPair,
|
|
122
137
|
checkReason: () => checkReason,
|
|
138
|
+
checkRegister: () => checkRegister,
|
|
123
139
|
checkRestraint: () => checkRestraint,
|
|
124
140
|
choicesOf: () => choicesOf,
|
|
125
141
|
clauseDepth: () => clauseDepth,
|
|
@@ -143,6 +159,8 @@ __export(index_exports, {
|
|
|
143
159
|
deltaEOkHex: () => deltaEOkHex,
|
|
144
160
|
densityCss: () => densityCss,
|
|
145
161
|
densityTokens: () => densityTokens,
|
|
162
|
+
designTells: () => designTells,
|
|
163
|
+
documentParagraphs: () => documentParagraphs,
|
|
146
164
|
emitCss: () => emitCss,
|
|
147
165
|
emptyEstate: () => emptyEstate,
|
|
148
166
|
estateComponentPairs: () => estateComponentPairs,
|
|
@@ -150,6 +168,7 @@ __export(index_exports, {
|
|
|
150
168
|
exitDuration: () => exitDuration,
|
|
151
169
|
extractHtml: () => extractHtml,
|
|
152
170
|
faceLicence: () => faceLicence,
|
|
171
|
+
featureLabel: () => featureLabel,
|
|
153
172
|
findClaims: () => findClaims,
|
|
154
173
|
findColours: () => findColours,
|
|
155
174
|
findingKey: () => findingKey,
|
|
@@ -159,12 +178,14 @@ __export(index_exports, {
|
|
|
159
178
|
fluidSpace: () => fluidSpace,
|
|
160
179
|
fluidType: () => fluidType,
|
|
161
180
|
fontClass: () => fontClass,
|
|
181
|
+
formatCalibration: () => formatCalibration,
|
|
162
182
|
formatClaims: () => formatClaims,
|
|
163
183
|
formatComparison: () => formatComparison,
|
|
164
184
|
formatCompetitor: () => formatCompetitor,
|
|
165
185
|
formatDirectionMatches: () => formatDirectionMatches,
|
|
166
186
|
formatHex: () => formatHex,
|
|
167
187
|
formatReport: () => formatReport,
|
|
188
|
+
getRegister: () => getRegister,
|
|
168
189
|
globToRegExp: () => globToRegExp,
|
|
169
190
|
groundName: () => groundName,
|
|
170
191
|
harvest: () => harvest,
|
|
@@ -183,8 +204,10 @@ __export(index_exports, {
|
|
|
183
204
|
isBlurb: () => isBlurb,
|
|
184
205
|
isCategoryLabel: () => isCategoryLabel,
|
|
185
206
|
isCream: () => isCream,
|
|
207
|
+
isFlagged: () => isFlagged,
|
|
186
208
|
jobWords: () => jobWords,
|
|
187
209
|
layoutDistance: () => layoutDistance,
|
|
210
|
+
lexicalOf: () => lexicalOf,
|
|
188
211
|
licencesJson: () => licencesJson,
|
|
189
212
|
makeSnapshot: () => makeSnapshot,
|
|
190
213
|
motionTokens: () => motionTokens,
|
|
@@ -209,6 +232,9 @@ __export(index_exports, {
|
|
|
209
232
|
ramp: () => ramp,
|
|
210
233
|
rampFromAnchors: () => rampFromAnchors,
|
|
211
234
|
readSnapshot: () => readSnapshot,
|
|
235
|
+
registerBrief: () => registerBrief,
|
|
236
|
+
registerOf: () => registerOf,
|
|
237
|
+
registersDoc: () => registersDoc,
|
|
212
238
|
renderedOrder: () => renderedOrder,
|
|
213
239
|
researchPrompt: () => researchPrompt,
|
|
214
240
|
retrofitPlan: () => retrofitPlan,
|
|
@@ -251,6 +277,8 @@ __export(index_exports, {
|
|
|
251
277
|
validateJob: () => validateJob,
|
|
252
278
|
visibleText: () => visibleText,
|
|
253
279
|
visualMeasures: () => visualMeasures,
|
|
280
|
+
vocabulary: () => vocabulary,
|
|
281
|
+
vocabularyCounts: () => vocabularyCounts,
|
|
254
282
|
wcagContrast: () => wcagContrast,
|
|
255
283
|
wordListsJson: () => wordListsJson
|
|
256
284
|
});
|
|
@@ -1015,10 +1043,10 @@ function stripLayers(css, ignored) {
|
|
|
1015
1043
|
const names = new Set(ignored.map((n) => n.trim().toLowerCase()));
|
|
1016
1044
|
let out = "";
|
|
1017
1045
|
let i = 0;
|
|
1018
|
-
const
|
|
1046
|
+
const pattern2 = /@layer\s+([a-zA-Z0-9_-]+)\s*\{/gi;
|
|
1019
1047
|
while (i < css.length) {
|
|
1020
|
-
|
|
1021
|
-
const match =
|
|
1048
|
+
pattern2.lastIndex = i;
|
|
1049
|
+
const match = pattern2.exec(css);
|
|
1022
1050
|
if (match === null) {
|
|
1023
1051
|
out += css.slice(i);
|
|
1024
1052
|
break;
|
|
@@ -1048,12 +1076,12 @@ var CSS_WIDE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
|
1048
1076
|
]);
|
|
1049
1077
|
function atRuleBodies(css, prelude) {
|
|
1050
1078
|
const out = [];
|
|
1051
|
-
const
|
|
1079
|
+
const pattern2 = new RegExp(
|
|
1052
1080
|
prelude.source,
|
|
1053
1081
|
prelude.flags.includes("g") ? prelude.flags : `${prelude.flags}g`
|
|
1054
1082
|
);
|
|
1055
1083
|
let match;
|
|
1056
|
-
while ((match =
|
|
1084
|
+
while ((match = pattern2.exec(css)) !== null) {
|
|
1057
1085
|
const start = match.index + match[0].length;
|
|
1058
1086
|
let depth = 1;
|
|
1059
1087
|
let i = start;
|
|
@@ -1063,7 +1091,7 @@ function atRuleBodies(css, prelude) {
|
|
|
1063
1091
|
i += 1;
|
|
1064
1092
|
}
|
|
1065
1093
|
out.push(css.slice(start, i - 1));
|
|
1066
|
-
|
|
1094
|
+
pattern2.lastIndex = i;
|
|
1067
1095
|
}
|
|
1068
1096
|
return out;
|
|
1069
1097
|
}
|
|
@@ -1096,9 +1124,9 @@ function isVarOnlyList(value) {
|
|
|
1096
1124
|
return parts2.length > 1 && parts2.every((part) => /^\s*var\(\s*--[\w-]+\s*\)\s*$/.test(part));
|
|
1097
1125
|
}
|
|
1098
1126
|
function distinctValues(css, property, props, unresolved) {
|
|
1099
|
-
const
|
|
1127
|
+
const pattern2 = new RegExp(`(?:^|[;{\\s])${property}\\s*:\\s*([^;}]+)`, "gi");
|
|
1100
1128
|
const seen = /* @__PURE__ */ new Set();
|
|
1101
|
-
for (const match of css.matchAll(
|
|
1129
|
+
for (const match of css.matchAll(pattern2)) {
|
|
1102
1130
|
const raw = match[1].trim().replace(/\s+/g, " ").toLowerCase();
|
|
1103
1131
|
if (CSS_WIDE_KEYWORDS.has(raw)) continue;
|
|
1104
1132
|
const value = unwrapShadowColor(raw);
|
|
@@ -1517,14 +1545,14 @@ function linkSpans(text) {
|
|
|
1517
1545
|
return [...text.matchAll(LINK)].map((m) => [m.index ?? 0, (m.index ?? 0) + m[0].length]);
|
|
1518
1546
|
}
|
|
1519
1547
|
var insideLink = (spans, at) => spans.some(([a, b]) => at >= a && at < b);
|
|
1520
|
-
function phrases(
|
|
1548
|
+
function phrases(patterns2, label, source = (ctx) => ctx.blocks, skip = () => false) {
|
|
1521
1549
|
return (ctx) => {
|
|
1522
1550
|
const hits = [];
|
|
1523
1551
|
for (const block of source(ctx)) {
|
|
1524
1552
|
const spans = [];
|
|
1525
1553
|
const links = linkSpans(block.text);
|
|
1526
|
-
for (const
|
|
1527
|
-
const global = new RegExp(
|
|
1554
|
+
for (const pattern2 of patterns2) {
|
|
1555
|
+
const global = new RegExp(pattern2.source, pattern2.flags.includes("g") ? pattern2.flags : `${pattern2.flags}g`);
|
|
1528
1556
|
for (const m of block.text.matchAll(global)) {
|
|
1529
1557
|
if (skip(block, m[0], m.index ?? 0)) continue;
|
|
1530
1558
|
if (insideLink(links, m.index ?? 0)) continue;
|
|
@@ -2911,11 +2939,11 @@ function baseClass(cls) {
|
|
|
2911
2939
|
function bases(unit) {
|
|
2912
2940
|
return unit.classes.map(baseClass);
|
|
2913
2941
|
}
|
|
2914
|
-
function has(unit,
|
|
2915
|
-
return bases(unit).some((c) =>
|
|
2942
|
+
function has(unit, pattern2) {
|
|
2943
|
+
return bases(unit).some((c) => pattern2.test(c));
|
|
2916
2944
|
}
|
|
2917
|
-
function find(unit,
|
|
2918
|
-
return bases(unit).find((c) =>
|
|
2945
|
+
function find(unit, pattern2) {
|
|
2946
|
+
return bases(unit).find((c) => pattern2.test(c));
|
|
2919
2947
|
}
|
|
2920
2948
|
function arbitrary(cls) {
|
|
2921
2949
|
const m = cls.match(/\[(.*)\]$/);
|
|
@@ -2931,9 +2959,9 @@ function eachUnit(ctx, fn) {
|
|
|
2931
2959
|
}
|
|
2932
2960
|
return hits;
|
|
2933
2961
|
}
|
|
2934
|
-
function firstMatch(text,
|
|
2935
|
-
const m =
|
|
2936
|
-
|
|
2962
|
+
function firstMatch(text, pattern2) {
|
|
2963
|
+
const m = pattern2.exec(text);
|
|
2964
|
+
pattern2.lastIndex = 0;
|
|
2937
2965
|
return m ? m.index : -1;
|
|
2938
2966
|
}
|
|
2939
2967
|
var FRAMEWORK_PALETTE = /^--(?:color-)?(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-\d+$|^--tw-/;
|
|
@@ -3377,9 +3405,9 @@ function shadcnCardHits(ctx) {
|
|
|
3377
3405
|
}
|
|
3378
3406
|
function marqueeHits(ctx) {
|
|
3379
3407
|
const hits = [];
|
|
3380
|
-
const
|
|
3408
|
+
const pattern2 = /@keyframes\s+[\w-]*marquee|animate-(?:marquee|scroll-x|infinite-scroll)\b|<Marquee\b|["']react-fast-marquee["']|ui\/marquee["']|animation(?:-name)?\s*:\s*[^;]*marquee/i;
|
|
3381
3409
|
for (const file of ctx.files) {
|
|
3382
|
-
const at = firstMatch(file.text,
|
|
3410
|
+
const at = firstMatch(file.text, pattern2);
|
|
3383
3411
|
if (at !== -1) hits.push({ path: file.path, offset: at, message: "scrolling marquee" });
|
|
3384
3412
|
}
|
|
3385
3413
|
return hits;
|
|
@@ -4221,8 +4249,8 @@ function protectedFacts(text) {
|
|
|
4221
4249
|
const mask = (start, length) => {
|
|
4222
4250
|
rest = rest.slice(0, start) + " ".repeat(length) + rest.slice(start + length);
|
|
4223
4251
|
};
|
|
4224
|
-
for (const [kind,
|
|
4225
|
-
for (const m of [...rest.matchAll(
|
|
4252
|
+
for (const [kind, pattern2] of PATTERNS) {
|
|
4253
|
+
for (const m of [...rest.matchAll(pattern2)]) {
|
|
4226
4254
|
const value = m[0].replace(/[.,;:]+$/, "");
|
|
4227
4255
|
facts.push({ kind, value, key: `${kind}:${normalise(kind, value)}` });
|
|
4228
4256
|
mask(m.index ?? 0, m[0].length);
|
|
@@ -4548,7 +4576,7 @@ function side(page, other, brief) {
|
|
|
4548
4576
|
function compareCompetitor(ours, competitor, brief) {
|
|
4549
4577
|
return { ours: side(ours, competitor, brief), competitor: side(competitor, ours, brief), brief: Boolean(brief) };
|
|
4550
4578
|
}
|
|
4551
|
-
var pctOf = (
|
|
4579
|
+
var pctOf = (share2) => share2 === null ? "no sentences" : `${Math.round(share2 * 100)}%`;
|
|
4552
4580
|
function formatCompetitor(result) {
|
|
4553
4581
|
const row = (label, s) => ` ${label.padEnd(11)} ${s.interchangeable.length} of ${s.sentences} (${pctOf(s.share)}), ${s.perHundred} specifics per 100 words`;
|
|
4554
4582
|
const lines = [
|
|
@@ -4724,7 +4752,7 @@ var SPECIFICITY_COPY_TELLS = [
|
|
|
4724
4752
|
},
|
|
4725
4753
|
rendered: {
|
|
4726
4754
|
detect: (s) => {
|
|
4727
|
-
if (!s.firstScreenText || !HOME_URL.test(s.url)) return [];
|
|
4755
|
+
if (!s.firstScreenText || !(s.home ?? HOME_URL.test(s.url))) return [];
|
|
4728
4756
|
const text = s.firstScreenText.join("\n");
|
|
4729
4757
|
if (!text.trim() || !specificity(text).generic) return [];
|
|
4730
4758
|
const h1 = s.headings.find((h) => h.level === 1 && h.top < s.viewport.height);
|
|
@@ -4924,11 +4952,11 @@ function reflexFonts(list) {
|
|
|
4924
4952
|
for (const font of s.fonts) {
|
|
4925
4953
|
const name = wanted.get(normaliseFamily(font.family).toLowerCase());
|
|
4926
4954
|
if (!name || seen.has(name)) continue;
|
|
4927
|
-
const
|
|
4955
|
+
const share2 = font.chars / total;
|
|
4928
4956
|
const displayShare = font.displayChars / display;
|
|
4929
|
-
if (
|
|
4957
|
+
if (share2 >= 0.15 || displayShare >= 0.3) {
|
|
4930
4958
|
seen.add(name);
|
|
4931
|
-
hits.push(hit(s, `${name} sets ${pct(
|
|
4959
|
+
hits.push(hit(s, `${name} sets ${pct(share2)} of the text on the page${displayShare >= 0.3 ? ` and ${pct(displayShare)} of the headings` : ""}`));
|
|
4932
4960
|
}
|
|
4933
4961
|
}
|
|
4934
4962
|
return hits;
|
|
@@ -6131,8 +6159,8 @@ var IMPERATIVE = /^(?:Add|Use|Check|Make|Get|Set|Include|Create|Update|List|Keep
|
|
|
6131
6159
|
var atStart = (sentence, index) => /^[\s*_"“”’(>#|-]*(?:\d{1,3}[.)]\s*)?[\s*_]*(?:[\w ]+:\**\s*)?$/.test(sentence.slice(0, index)) || /\|\s*\**$/.test(sentence.slice(0, index));
|
|
6132
6160
|
function namedSources(sentence) {
|
|
6133
6161
|
const found = /* @__PURE__ */ new Set();
|
|
6134
|
-
ATTRIBUTION.forEach((
|
|
6135
|
-
for (const m of sentence.matchAll(
|
|
6162
|
+
ATTRIBUTION.forEach((pattern2, i) => {
|
|
6163
|
+
for (const m of sentence.matchAll(pattern2)) {
|
|
6136
6164
|
const raw = m[1].trim();
|
|
6137
6165
|
const word = !/\s/.test(raw) && !/[’']s$/.test(m[0].split(/\s+/)[0]);
|
|
6138
6166
|
if (i === 2 && word && atStart(sentence, m.index ?? 0)) continue;
|
|
@@ -6376,7 +6404,7 @@ function shapeOf(text) {
|
|
|
6376
6404
|
const ss = splitSentences(text);
|
|
6377
6405
|
const wordCount = words(text).length;
|
|
6378
6406
|
const per100 = (n) => wordCount === 0 ? 0 : 100 * n / wordCount;
|
|
6379
|
-
const
|
|
6407
|
+
const share2 = (re) => ss.length === 0 ? 0 : ss.filter((s) => re.test(s)).length / ss.length;
|
|
6380
6408
|
const tri = ss.flatMap(tricolons);
|
|
6381
6409
|
const commas = (text.match(/,/g) ?? []).length;
|
|
6382
6410
|
return {
|
|
@@ -6390,9 +6418,9 @@ function shapeOf(text) {
|
|
|
6390
6418
|
hedgeRate: per100(hedgeCount(text)),
|
|
6391
6419
|
hedgedClose: hedgedClose(ss),
|
|
6392
6420
|
nominalisationRate: per100(nominalisations(text)),
|
|
6393
|
-
pronounOpenerShare:
|
|
6394
|
-
transitionOpenerShare:
|
|
6395
|
-
impersonalOpenerShare:
|
|
6421
|
+
pronounOpenerShare: share2(PRONOUN_OPENER),
|
|
6422
|
+
transitionOpenerShare: share2(TRANSITION_OPENER),
|
|
6423
|
+
impersonalOpenerShare: share2(IMPERSONAL_OPENER),
|
|
6396
6424
|
commasPerSentence: ss.length === 0 ? 0 : commas / ss.length,
|
|
6397
6425
|
commasPer100: per100(commas),
|
|
6398
6426
|
participialRate: ss.length === 0 ? 0 : ss.reduce((s, x) => s + participialClauses(x), 0) / ss.length,
|
|
@@ -6419,6 +6447,1353 @@ function isBlurb(f4) {
|
|
|
6419
6447
|
return f4.sentences >= 2 && f4.sentences <= 8 && f4.words >= 20 && f4.words <= 160;
|
|
6420
6448
|
}
|
|
6421
6449
|
|
|
6450
|
+
// src/character/lexical.ts
|
|
6451
|
+
var JUZEK = "Juzek and Ward, arXiv:2412.11385, Appendix A (PubMed abstracts, 2020 to 2024)";
|
|
6452
|
+
var STUDY_WORDS = [
|
|
6453
|
+
"delves",
|
|
6454
|
+
"delved",
|
|
6455
|
+
"delving",
|
|
6456
|
+
"delve",
|
|
6457
|
+
"showcasing",
|
|
6458
|
+
"boasts",
|
|
6459
|
+
"underscores",
|
|
6460
|
+
"underscoring",
|
|
6461
|
+
"comprehending",
|
|
6462
|
+
"intricacies",
|
|
6463
|
+
"surpassing",
|
|
6464
|
+
"intricate"
|
|
6465
|
+
].map((word) => ({ word, source: JUZEK }));
|
|
6466
|
+
function vocabulary() {
|
|
6467
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6468
|
+
const out = [];
|
|
6469
|
+
const add = (word, source) => {
|
|
6470
|
+
const w = word.toLowerCase();
|
|
6471
|
+
if (seen.has(w)) return;
|
|
6472
|
+
seen.add(w);
|
|
6473
|
+
out.push({ word: w, source });
|
|
6474
|
+
};
|
|
6475
|
+
for (const s of STUDY_WORDS) add(s.word, s.source);
|
|
6476
|
+
for (const w of AI_WORDS) add(w, "AI_WORDS");
|
|
6477
|
+
for (const w of PLAINER_WORDS) add(w, "PLAINER_WORDS");
|
|
6478
|
+
for (const w of AI_PHRASES) add(w, "AI_PHRASES");
|
|
6479
|
+
for (const w of STOCK_PHRASES) add(w, "STOCK_PHRASES");
|
|
6480
|
+
for (const w of BUZZWORDS) add(w, "BUZZWORDS");
|
|
6481
|
+
return out;
|
|
6482
|
+
}
|
|
6483
|
+
var escape4 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6484
|
+
var pattern = (w) => new RegExp(`(?<![\\w-])${escape4(w).replace(/\s+/g, "\\s+")}(?![\\w-])`, "gi");
|
|
6485
|
+
var compiled = null;
|
|
6486
|
+
var patterns = () => compiled ?? (compiled = vocabulary().map((v) => ({ ...v, re: pattern(v.word) })));
|
|
6487
|
+
var plain = (text) => text.replace(/[’‘]/g, "'").replace(/\s+/g, " ");
|
|
6488
|
+
function vocabularyCounts(text) {
|
|
6489
|
+
const t = plain(text);
|
|
6490
|
+
const out = /* @__PURE__ */ new Map();
|
|
6491
|
+
for (const { word, re } of patterns()) {
|
|
6492
|
+
const n = (t.match(re) ?? []).length;
|
|
6493
|
+
if (n) out.set(word, n);
|
|
6494
|
+
}
|
|
6495
|
+
return out;
|
|
6496
|
+
}
|
|
6497
|
+
var LEXICAL_FEATURES = [
|
|
6498
|
+
"listRate",
|
|
6499
|
+
"studyRate",
|
|
6500
|
+
"hardPer100",
|
|
6501
|
+
"tradePer100",
|
|
6502
|
+
"specificsPer100",
|
|
6503
|
+
"generic",
|
|
6504
|
+
"figures",
|
|
6505
|
+
"names"
|
|
6506
|
+
];
|
|
6507
|
+
var STUDY = new Set(STUDY_WORDS.map((s) => s.word));
|
|
6508
|
+
var LISTED = new Set([...AI_WORDS, ...PLAINER_WORDS, ...AI_PHRASES, ...STOCK_PHRASES, ...BUZZWORDS].map((w) => w.toLowerCase()));
|
|
6509
|
+
var r3 = (n) => Math.round(n * 1e3) / 1e3;
|
|
6510
|
+
function lexicalOf(text, brief) {
|
|
6511
|
+
const words3 = Math.max(1, countWords2(text));
|
|
6512
|
+
const counts = vocabularyCounts(text);
|
|
6513
|
+
let list = 0;
|
|
6514
|
+
let study = 0;
|
|
6515
|
+
for (const [w, n] of counts) {
|
|
6516
|
+
if (STUDY.has(w)) study += n;
|
|
6517
|
+
if (LISTED.has(w)) list += n;
|
|
6518
|
+
}
|
|
6519
|
+
const s = specificity(text, brief);
|
|
6520
|
+
const kind = (...k) => s.specifics.filter((x) => k.includes(x.kind)).length;
|
|
6521
|
+
return {
|
|
6522
|
+
listRate: r3(list / words3 * 100),
|
|
6523
|
+
studyRate: r3(study / words3 * 100),
|
|
6524
|
+
hardPer100: r3(s.hard / words3 * 100),
|
|
6525
|
+
tradePer100: r3(s.trade / words3 * 100),
|
|
6526
|
+
specificsPer100: r3(s.perHundred),
|
|
6527
|
+
generic: s.generic ? 1 : 0,
|
|
6528
|
+
figures: kind("money", "date", "time", "number"),
|
|
6529
|
+
names: kind("name", "brief")
|
|
6530
|
+
};
|
|
6531
|
+
}
|
|
6532
|
+
|
|
6533
|
+
// src/register/features.ts
|
|
6534
|
+
var REGISTER_FEATURES = [
|
|
6535
|
+
"meanSentenceWords",
|
|
6536
|
+
"contractionsPer100",
|
|
6537
|
+
"youPer100",
|
|
6538
|
+
"firstPersonPer100",
|
|
6539
|
+
"passiveShare",
|
|
6540
|
+
"meanWordLength"
|
|
6541
|
+
];
|
|
6542
|
+
var norm = (w) => w.toLowerCase().replace(/’/g, "'");
|
|
6543
|
+
var YOU = /* @__PURE__ */ new Set(["you", "your", "yours", "yourself", "yourselves", "you'll", "you're", "you've", "you'd"]);
|
|
6544
|
+
var FIRST = /* @__PURE__ */ new Set(["i", "me", "my", "mine", "we", "us", "our", "ours", "i'm", "i'll", "i've", "i'd", "we're", "we'll", "we've", "we'd"]);
|
|
6545
|
+
var CONTRACTION2 = /^[a-z]+(?:n't|'ll|'re|'ve|'d|'m)$|^(?:it|that|there|here|what|who|where|how|he|she|let)'s$/;
|
|
6546
|
+
var BE = "(?:am|is|are|was|were|be|been|being|'s|'re|'m)";
|
|
6547
|
+
var IRREGULAR = "(?:made|done|given|taken|seen|known|shown|written|built|sent|paid|held|told|found|kept|left|brought|bought|thought|taught|caught|sold|put|set|run|cut|chosen|driven|eaten|fallen|forgotten|hidden|broken|spoken|stolen|worn|torn|grown|drawn|thrown|flown|begun|sung|won|lost|met|led|read|heard|meant|spent|built|lent|dealt|felt|sought|fed|bred|laid|said|struck|hung|shut|hit|hurt|let|quit|spread|bound|wound|ground|understood|withdrawn|overseen|undertaken)";
|
|
6548
|
+
var PASSIVE = new RegExp(`\\b${BE}\\s+(?:[a-z]+ly\\s+)?(?:[a-z]+ed|[a-z]+en|${IRREGULAR})\\b`, "i");
|
|
6549
|
+
var ADJECTIVAL = /* @__PURE__ */ new Set([
|
|
6550
|
+
"tired",
|
|
6551
|
+
"interested",
|
|
6552
|
+
"excited",
|
|
6553
|
+
"pleased",
|
|
6554
|
+
"worried",
|
|
6555
|
+
"concerned",
|
|
6556
|
+
"surprised",
|
|
6557
|
+
"bored",
|
|
6558
|
+
"scared",
|
|
6559
|
+
"married",
|
|
6560
|
+
"qualified",
|
|
6561
|
+
"experienced",
|
|
6562
|
+
"based",
|
|
6563
|
+
"located",
|
|
6564
|
+
"committed",
|
|
6565
|
+
"dedicated",
|
|
6566
|
+
"delighted",
|
|
6567
|
+
"disappointed",
|
|
6568
|
+
"involved",
|
|
6569
|
+
"prepared",
|
|
6570
|
+
"supposed",
|
|
6571
|
+
"used",
|
|
6572
|
+
"open",
|
|
6573
|
+
"often",
|
|
6574
|
+
"even",
|
|
6575
|
+
"seven",
|
|
6576
|
+
"eleven",
|
|
6577
|
+
"listen",
|
|
6578
|
+
"happen",
|
|
6579
|
+
"then",
|
|
6580
|
+
"when",
|
|
6581
|
+
"ten",
|
|
6582
|
+
"garden",
|
|
6583
|
+
"kitchen",
|
|
6584
|
+
"children",
|
|
6585
|
+
"women",
|
|
6586
|
+
"men",
|
|
6587
|
+
"red",
|
|
6588
|
+
"bed",
|
|
6589
|
+
"need",
|
|
6590
|
+
"indeed",
|
|
6591
|
+
"shed",
|
|
6592
|
+
"seed",
|
|
6593
|
+
"feed",
|
|
6594
|
+
"speed",
|
|
6595
|
+
"hundred"
|
|
6596
|
+
]);
|
|
6597
|
+
function isPassive(sentence) {
|
|
6598
|
+
const re = new RegExp(PASSIVE.source, "gi");
|
|
6599
|
+
for (const m of sentence.matchAll(re)) {
|
|
6600
|
+
const last = norm(m[0].trim().split(/\s+/).pop() ?? "");
|
|
6601
|
+
if (last === "given" && /given\s+that\b/i.test(sentence.slice(m.index ?? 0))) continue;
|
|
6602
|
+
if (!ADJECTIVAL.has(last)) return true;
|
|
6603
|
+
}
|
|
6604
|
+
return false;
|
|
6605
|
+
}
|
|
6606
|
+
function registerOf(text) {
|
|
6607
|
+
const ss = splitSentences(text);
|
|
6608
|
+
const ws = words(text).map(norm);
|
|
6609
|
+
const n = ws.length;
|
|
6610
|
+
const per100 = (k) => n === 0 ? 0 : 100 * k / n;
|
|
6611
|
+
const letters = ws.reduce((s, w) => s + w.replace(/[^a-z]/g, "").length, 0);
|
|
6612
|
+
return {
|
|
6613
|
+
meanSentenceWords: ss.length === 0 ? 0 : n / ss.length,
|
|
6614
|
+
contractionsPer100: per100(ws.filter((w) => CONTRACTION2.test(w)).length),
|
|
6615
|
+
youPer100: per100(ws.filter((w) => YOU.has(w)).length),
|
|
6616
|
+
firstPersonPer100: per100(ws.filter((w) => FIRST.has(w)).length),
|
|
6617
|
+
passiveShare: ss.length === 0 ? 0 : ss.filter(isPassive).length / ss.length,
|
|
6618
|
+
meanWordLength: n === 0 ? 0 : letters / n
|
|
6619
|
+
};
|
|
6620
|
+
}
|
|
6621
|
+
|
|
6622
|
+
// src/register/registers.ts
|
|
6623
|
+
var GOVUK = "GOV.UK writing guidelines";
|
|
6624
|
+
var MAILCHIMP = "Mailchimp Content Style Guide";
|
|
6625
|
+
var OGILVY = "Ogilvy, Ogilvy on Advertising (1983)";
|
|
6626
|
+
var CAPLES = "Caples, Tested Advertising Methods";
|
|
6627
|
+
var HOUSE2 = "house judgement";
|
|
6628
|
+
var ALWAYS = "Every register keeps the COPY.md blocking tier and the proof rule. Draft first, then run `craft copy <file>` on the draft.";
|
|
6629
|
+
var REGISTERS = [
|
|
6630
|
+
{
|
|
6631
|
+
id: "plain",
|
|
6632
|
+
name: "Plain and trustworthy",
|
|
6633
|
+
useFor: "Forms, policies, terms, instructions, and professional services where the reader must act correctly.",
|
|
6634
|
+
directives: [
|
|
6635
|
+
{ text: "Put the most important information first, then taper down to the detail.", from: GOVUK },
|
|
6636
|
+
{ text: "Split any sentence over 25 words into two.", from: GOVUK },
|
|
6637
|
+
{ text: "Choose the short, common word: buy, help, about.", from: GOVUK },
|
|
6638
|
+
{ text: "Write in the active voice, so the reader sees who does what.", from: GOVUK },
|
|
6639
|
+
{ text: 'Address the reader as "you", as one person you can actually help.', from: GOVUK },
|
|
6640
|
+
{ text: `Use positive contractions such as "you'll", and write negatives out in full: "do not", "cannot".`, from: GOVUK },
|
|
6641
|
+
{ text: "Write headings that say what the section tells the reader, starting with a verb where you can.", from: GOVUK },
|
|
6642
|
+
{ text: "Give each paragraph one job.", from: HOUSE2 }
|
|
6643
|
+
],
|
|
6644
|
+
example: {
|
|
6645
|
+
before: "Should you wish to apply for a residents' parking permit, an application form must be completed and submitted to the council prior to the commencement of the permit period.",
|
|
6646
|
+
after: "Apply for a residents' parking permit before you need it. Fill in the form online. It takes about 10 minutes.",
|
|
6647
|
+
why: "The action comes first, the council is no longer the subject, and each sentence does one thing."
|
|
6648
|
+
},
|
|
6649
|
+
sources: [
|
|
6650
|
+
{
|
|
6651
|
+
name: GOVUK,
|
|
6652
|
+
url: "https://guidance.publishing.service.gov.uk/writing-to-gov-uk-standards/writing-guidelines/",
|
|
6653
|
+
note: 'Clear language (the 25-word split, short words, active voice, contractions), clear structure (most important first, headings) and right tone (address the user as "you"). Checked against the live pages on 2026-09-30.'
|
|
6654
|
+
}
|
|
6655
|
+
]
|
|
6656
|
+
},
|
|
6657
|
+
{
|
|
6658
|
+
id: "persuasive",
|
|
6659
|
+
name: "Persuasive and concise",
|
|
6660
|
+
useFor: "Landing pages, service pages, adverts and sales emails: copy whose job is one action.",
|
|
6661
|
+
directives: [
|
|
6662
|
+
{ text: "Put the promise in the headline: what the reader gets, in words they would use.", from: OGILVY },
|
|
6663
|
+
{ text: "Back each claim with something the reader can check: a number, a name, a date, a price.", from: "COPY.md" },
|
|
6664
|
+
{ text: 'Write to one reader, as "you", about their problem before your service.', from: CAPLES },
|
|
6665
|
+
{ text: "Name the mechanism: how it works, how long it takes, what it costs.", from: "COPY.md" },
|
|
6666
|
+
{ text: "Answer the objection the reader already has, with evidence, in the sentence that follows the claim.", from: HOUSE2 },
|
|
6667
|
+
{ text: "Let the copy run as long as the facts last, and cut each sentence that carries none.", from: OGILVY },
|
|
6668
|
+
{ text: "Close with one specific action and what happens straight after it.", from: "COPY.md" }
|
|
6669
|
+
],
|
|
6670
|
+
example: {
|
|
6671
|
+
before: "Transform your garden with our premium landscaping solutions. Quality you can trust.",
|
|
6672
|
+
after: "We lay a 40 square metre Indian sandstone patio in three days, for \xA34,800 fitted. Every job since 2014 is on our reviews page. Book a free site visit and get a fixed quote within 48 hours.",
|
|
6673
|
+
why: "Size, material, time and price replace the adjectives, the proof sits next to the claim, and the close says what happens next. Fictional business."
|
|
6674
|
+
},
|
|
6675
|
+
sources: [
|
|
6676
|
+
{
|
|
6677
|
+
name: OGILVY,
|
|
6678
|
+
note: "Headlines carry the promise because far more people read the headline than the body; specific, informative copy outsells vague copy. Taken from the widely quoted principles; a page-by-page check against the book is still to do."
|
|
6679
|
+
},
|
|
6680
|
+
{
|
|
6681
|
+
name: CAPLES,
|
|
6682
|
+
note: "Headlines that appeal to the reader's self-interest, and copy judged by tested response rather than taste. A page-by-page check against the book is still to do."
|
|
6683
|
+
},
|
|
6684
|
+
{
|
|
6685
|
+
name: "COPY.md",
|
|
6686
|
+
note: "Writing directives (lead with the fact, name the mechanism, persuade with something checkable) and the CTA rule."
|
|
6687
|
+
}
|
|
6688
|
+
]
|
|
6689
|
+
},
|
|
6690
|
+
{
|
|
6691
|
+
id: "warm",
|
|
6692
|
+
name: "Warm and conversational",
|
|
6693
|
+
useFor: "Customer emails, replies to enquiries, newsletters and small-business updates.",
|
|
6694
|
+
directives: [
|
|
6695
|
+
{ text: "Write the way you would talk to a customer you like: contractions, everyday words.", from: MAILCHIMP },
|
|
6696
|
+
{ text: "Keep words and sentences simple; being clear matters more than being entertaining.", from: MAILCHIMP },
|
|
6697
|
+
{ text: "Say what the reader can do, in positive language.", from: MAILCHIMP },
|
|
6698
|
+
{ text: "Use the active voice.", from: MAILCHIMP },
|
|
6699
|
+
{ text: "Match the tone to how the reader feels right now: lighter for good news, calm and direct for a problem.", from: MAILCHIMP },
|
|
6700
|
+
{ text: "Keep humour dry and occasional, and only where it comes naturally.", from: MAILCHIMP },
|
|
6701
|
+
{ text: "Sign off as a person, with a name.", from: HOUSE2 }
|
|
6702
|
+
],
|
|
6703
|
+
example: {
|
|
6704
|
+
before: "Dear Valued Customer, We wish to inform you that your order has been dispatched and will be delivered in due course.",
|
|
6705
|
+
after: "Hi Sam, your order's on its way. It left our Leicester workshop this morning and should reach you on Thursday. Any questions, just reply to this email. Priya",
|
|
6706
|
+
why: 'A name at each end, a real day and place instead of "in due course", and a next step. Fictional business.'
|
|
6707
|
+
},
|
|
6708
|
+
sources: [
|
|
6709
|
+
{
|
|
6710
|
+
name: MAILCHIMP,
|
|
6711
|
+
url: "https://styleguide.mailchimp.com/voice-and-tone/",
|
|
6712
|
+
note: "Voice and tone (plainspoken, genuine, dry humour; clear before entertaining; adjust tone to the reader's state) and grammar and mechanics (active voice, contractions, positive language). Its allowance for emoji does not apply: emoji block under COPY.md. Checked against the live pages on 2026-09-30."
|
|
6713
|
+
}
|
|
6714
|
+
]
|
|
6715
|
+
},
|
|
6716
|
+
{
|
|
6717
|
+
id: "literary",
|
|
6718
|
+
name: "Elegant and literary",
|
|
6719
|
+
useFor: "Premium brands, makers, hospitality and anything sold on craft and taste rather than price.",
|
|
6720
|
+
directives: [
|
|
6721
|
+
{ text: "Choose one precise noun over two adjectives.", from: HOUSE2 },
|
|
6722
|
+
{ text: "Let sentence length follow the thought: a long sentence to build, a short one to land.", from: "COPY.md" },
|
|
6723
|
+
{ text: "Carry the detail in concrete facts: material, place, process, time.", from: HOUSE2 },
|
|
6724
|
+
{ text: "Trust the reader with one image, state it once, and move on.", from: HOUSE2 },
|
|
6725
|
+
{ text: "Keep claims quiet and exact, and let the facts carry the prestige.", from: HOUSE2 },
|
|
6726
|
+
{ text: "Draw any metaphor from the maker's own work, and hold it for the whole piece.", from: HOUSE2 },
|
|
6727
|
+
{ text: "Read the draft aloud and rework each line that trips the breath.", from: HOUSE2 }
|
|
6728
|
+
],
|
|
6729
|
+
example: {
|
|
6730
|
+
before: "Our luxurious, handcrafted candles create an unforgettable ambience of elegance and sophistication.",
|
|
6731
|
+
after: "Each candle is poured by hand in our Hebden Bridge workshop, forty to a batch. The wax is English rapeseed and the scent is cedar, cut with a little smoke. It burns for sixty hours, and the glass is yours to keep.",
|
|
6732
|
+
why: "Place, material, scent and burn time do the work the adjectives claimed. Fictional business."
|
|
6733
|
+
},
|
|
6734
|
+
sources: [
|
|
6735
|
+
{
|
|
6736
|
+
name: HOUSE2,
|
|
6737
|
+
note: "No public style authority exists for premium-brand prose. These directives are house judgement, to be revised as the estate grows."
|
|
6738
|
+
},
|
|
6739
|
+
{
|
|
6740
|
+
name: "Register separation, 2026-09-29",
|
|
6741
|
+
url: "calibration/copy-shape/report-registers.md",
|
|
6742
|
+
note: "Literary prose (Gutenberg) carries about twice the comma density of the other human registers, the one feature that separated it from all four. Longer, jointed sentences are normal here."
|
|
6743
|
+
}
|
|
6744
|
+
]
|
|
6745
|
+
}
|
|
6746
|
+
];
|
|
6747
|
+
var REGISTER_IDS = REGISTERS.map((r) => r.id);
|
|
6748
|
+
function getRegister(id) {
|
|
6749
|
+
return REGISTERS.find((r) => r.id === id);
|
|
6750
|
+
}
|
|
6751
|
+
function registerBrief(id) {
|
|
6752
|
+
const r = getRegister(id);
|
|
6753
|
+
if (!r) throw new Error(`unknown register "${id}". Registers: ${REGISTER_IDS.join(", ")}`);
|
|
6754
|
+
const lines = [`Register: ${r.name} (${r.id})`, `Use for: ${r.useFor}`, "", "Before you draft:"];
|
|
6755
|
+
r.directives.forEach((d, i) => lines.push(` ${i + 1}. ${d.text} [${d.from}]`));
|
|
6756
|
+
lines.push("", "Example (fictional):", ` Before: ${r.example.before}`, ` After: ${r.example.after}`, ` Why: ${r.example.why}`);
|
|
6757
|
+
lines.push("", "Sources:");
|
|
6758
|
+
for (const s of r.sources) lines.push(` - ${s.name}${s.url ? ` (${s.url})` : ""}: ${s.note}`);
|
|
6759
|
+
lines.push("", `Always: ${ALWAYS}`);
|
|
6760
|
+
return lines.join("\n");
|
|
6761
|
+
}
|
|
6762
|
+
function registersDoc() {
|
|
6763
|
+
const out = [];
|
|
6764
|
+
for (const r of REGISTERS) {
|
|
6765
|
+
out.push(`## ${r.name} (\`${r.id}\`)`, "", `**Use for:** ${r.useFor}`, "", "**Before you draft:**", "");
|
|
6766
|
+
r.directives.forEach((d, i) => out.push(`${i + 1}. ${d.text} *(${d.from})*`));
|
|
6767
|
+
out.push("", "**Example (fictional):**", "", `- Before: ${r.example.before}`, `- After: ${r.example.after}`, `- Why: ${r.example.why}`);
|
|
6768
|
+
out.push("", "**Sources:**", "");
|
|
6769
|
+
for (const s of r.sources) out.push(`- ${s.url ? `[${s.name}](${s.url})` : s.name}: ${s.note}`);
|
|
6770
|
+
out.push("");
|
|
6771
|
+
}
|
|
6772
|
+
out.push(`**Always:** ${ALWAYS}`);
|
|
6773
|
+
return out.join("\n");
|
|
6774
|
+
}
|
|
6775
|
+
|
|
6776
|
+
// src/register/check.ts
|
|
6777
|
+
var REGISTER_BASELINE = {
|
|
6778
|
+
plain: {
|
|
6779
|
+
baseline: "institutional",
|
|
6780
|
+
note: "Compared with Hansard: edited parliamentary debate, the closest free UK source, not plain writing itself."
|
|
6781
|
+
},
|
|
6782
|
+
persuasive: {
|
|
6783
|
+
baseline: "marketing",
|
|
6784
|
+
note: "Compared with 715 passages from UK small-business websites before 2021: a small sample."
|
|
6785
|
+
},
|
|
6786
|
+
warm: {
|
|
6787
|
+
baseline: "business-email",
|
|
6788
|
+
note: "Compared with Enron sent email, 1999 to 2002: corporate and American, not small-business email."
|
|
6789
|
+
},
|
|
6790
|
+
literary: {
|
|
6791
|
+
baseline: "literary",
|
|
6792
|
+
note: "Compared with English fiction and essays, 1726 to 1925: older than any premium brand's copy."
|
|
6793
|
+
}
|
|
6794
|
+
};
|
|
6795
|
+
var MIN_PARAGRAPHS = 5;
|
|
6796
|
+
var CONTENT_FEATURES = /* @__PURE__ */ new Set(["hardPer100", "specificsPer100", "tradePer100", "figures", "names", "generic"]);
|
|
6797
|
+
var usable = (f4, b) => !CONTENT_FEATURES.has(f4) && b.p90 > b.p10;
|
|
6798
|
+
var LABELS = {
|
|
6799
|
+
meanSentenceWords: "Words per sentence",
|
|
6800
|
+
contractionsPer100: "Contractions per 100 words",
|
|
6801
|
+
youPer100: '"You" per 100 words',
|
|
6802
|
+
firstPersonPer100: '"I" and "we" per 100 words',
|
|
6803
|
+
passiveShare: "Share of sentences in the passive",
|
|
6804
|
+
meanWordLength: "Letters per word",
|
|
6805
|
+
commasPer100: "Commas per 100 words",
|
|
6806
|
+
commasPerSentence: "Commas per sentence",
|
|
6807
|
+
clauseDepth: "Clauses per sentence",
|
|
6808
|
+
nominalisationRate: 'Nominalisations ("the provision of") per 100 words',
|
|
6809
|
+
pronounOpenerShare: "Share of sentences opening with a pronoun",
|
|
6810
|
+
impersonalOpenerShare: 'Share of sentences opening impersonally ("It is", "There are")',
|
|
6811
|
+
coordinationRate: 'Paired phrases ("fast and friendly") per 100 words',
|
|
6812
|
+
participialRate: '"-ing" clauses per sentence',
|
|
6813
|
+
tricolons: "Lists of three",
|
|
6814
|
+
sentenceCv: "Spread of sentence lengths",
|
|
6815
|
+
skeletonRepeat: "Repeated sentence patterns",
|
|
6816
|
+
hardPer100: "Hard specifics (names, figures, dates) per 100 words",
|
|
6817
|
+
specificsPer100: "Specifics of any kind per 100 words",
|
|
6818
|
+
tradePer100: "Trade nouns per 100 words",
|
|
6819
|
+
figures: "Figures per paragraph",
|
|
6820
|
+
names: "Names per paragraph",
|
|
6821
|
+
generic: "Share of paragraphs with no specific at all"
|
|
6822
|
+
};
|
|
6823
|
+
var featureLabel = (f4) => LABELS[f4] ?? f4;
|
|
6824
|
+
function documentParagraphs(text) {
|
|
6825
|
+
return text.replace(/\r\n?/g, "\n").split(/\n\s*\n/).map((p) => p.replace(/\s*\n\s*/g, " ").trim()).filter((p) => p && !/^#{1,6}\s/.test(p));
|
|
6826
|
+
}
|
|
6827
|
+
function measure(paragraph) {
|
|
6828
|
+
const out = {};
|
|
6829
|
+
for (const [k, v] of Object.entries(shapeOf(paragraph))) out[k] = typeof v === "boolean" ? v ? 1 : 0 : v;
|
|
6830
|
+
for (const [k, v] of Object.entries(lexicalOf(paragraph))) out[k] = v;
|
|
6831
|
+
for (const [k, v] of Object.entries(registerOf(paragraph))) out[k] = v;
|
|
6832
|
+
return out;
|
|
6833
|
+
}
|
|
6834
|
+
var fmt = (x) => Math.abs(x) >= 10 ? x.toFixed(0) : x.toFixed(Math.abs(x) >= 1 ? 1 : 2);
|
|
6835
|
+
function checkRegister(text, id, profile) {
|
|
6836
|
+
const reg = getRegister(id);
|
|
6837
|
+
if (!reg) throw new Error(`unknown register "${id}"`);
|
|
6838
|
+
const { baseline, note } = REGISTER_BASELINE[id];
|
|
6839
|
+
const target2 = profile[baseline];
|
|
6840
|
+
if (!target2) throw new Error(`no baseline profile for "${baseline}"`);
|
|
6841
|
+
const kept = documentParagraphs(text).filter((p) => isBlurb(shapeOf(p)));
|
|
6842
|
+
const base = { register: id, baseline, paragraphs: kept.length, note };
|
|
6843
|
+
if (kept.length < MIN_PARAGRAPHS) {
|
|
6844
|
+
return {
|
|
6845
|
+
...base,
|
|
6846
|
+
measured: false,
|
|
6847
|
+
means: {},
|
|
6848
|
+
outside: [],
|
|
6849
|
+
nearest: [],
|
|
6850
|
+
summary: `Only ${kept.length} paragraph${kept.length === 1 ? "" : "s"} of 2 to 8 sentences. The registers overlap too much to place anything shorter than ${MIN_PARAGRAPHS}; read it against the brief instead.`
|
|
6851
|
+
};
|
|
6852
|
+
}
|
|
6853
|
+
const rows = kept.map(measure);
|
|
6854
|
+
const features = [...new Set(Object.values(profile).flatMap((p) => Object.keys(p)))];
|
|
6855
|
+
const means = {};
|
|
6856
|
+
for (const f4 of features) {
|
|
6857
|
+
const xs = rows.map((r) => r[f4]).filter((x) => typeof x === "number" && Number.isFinite(x));
|
|
6858
|
+
if (xs.length) means[f4] = xs.reduce((s, x) => s + x, 0) / xs.length;
|
|
6859
|
+
}
|
|
6860
|
+
const outside = [];
|
|
6861
|
+
for (const [f4, b] of Object.entries(target2)) {
|
|
6862
|
+
const v = means[f4];
|
|
6863
|
+
if (v === void 0 || b.separates.length === 0 || !usable(f4, b)) continue;
|
|
6864
|
+
if (v >= b.p10 && v <= b.p90) continue;
|
|
6865
|
+
const direction = v > b.p90 ? "higher" : "lower";
|
|
6866
|
+
outside.push({
|
|
6867
|
+
feature: f4,
|
|
6868
|
+
value: v,
|
|
6869
|
+
band: [b.p10, b.p90],
|
|
6870
|
+
direction,
|
|
6871
|
+
sentence: `${featureLabel(f4)}: ${fmt(v)}. ${reg.name} writing in the baseline runs ${fmt(b.p10)} to ${fmt(b.p90)}, so this is ${direction}.`
|
|
6872
|
+
});
|
|
6873
|
+
}
|
|
6874
|
+
const nearest2 = Object.entries(profile).map(([register, bands]) => {
|
|
6875
|
+
const zs = Object.entries(bands).filter(([f4, b]) => means[f4] !== void 0 && b.sd > 0 && usable(f4, b)).map(([f4, b]) => ((means[f4] - b.p50) / b.sd) ** 2);
|
|
6876
|
+
return { register, distance: zs.length ? Math.sqrt(zs.reduce((s, z) => s + z, 0) / zs.length) : Infinity };
|
|
6877
|
+
}).filter((n) => Number.isFinite(n.distance)).sort((a, b) => a.distance - b.distance);
|
|
6878
|
+
const closest = nearest2[0]?.register;
|
|
6879
|
+
const summary = (outside.length === 0 ? `All ${Object.entries(target2).filter(([f4, b]) => b.separates.length && usable(f4, b)).length} measured features sit inside the usual range for ${reg.name.toLowerCase()} writing.` : `${outside.length} feature${outside.length === 1 ? "" : "s"} outside the usual range for ${reg.name.toLowerCase()} writing.`) + (closest && closest !== baseline ? ` It reads closest to the ${closest} baseline.` : "");
|
|
6880
|
+
return { ...base, measured: true, means, outside, nearest: nearest2, summary };
|
|
6881
|
+
}
|
|
6882
|
+
|
|
6883
|
+
// src/register/profile.ts
|
|
6884
|
+
var PROFILE_PARAGRAPHS = 5;
|
|
6885
|
+
var PROFILE_MEASURED = "2026-09-30";
|
|
6886
|
+
var PROFILE = {
|
|
6887
|
+
"business-email": {
|
|
6888
|
+
"clauseDepth": {
|
|
6889
|
+
"p10": 0.36,
|
|
6890
|
+
"p50": 0.673,
|
|
6891
|
+
"p90": 1.113,
|
|
6892
|
+
"sd": 0.307,
|
|
6893
|
+
"separates": [
|
|
6894
|
+
"explanatory",
|
|
6895
|
+
"institutional",
|
|
6896
|
+
"literary"
|
|
6897
|
+
]
|
|
6898
|
+
},
|
|
6899
|
+
"commasPer100": {
|
|
6900
|
+
"p10": 1.424,
|
|
6901
|
+
"p50": 3.19,
|
|
6902
|
+
"p90": 5.154,
|
|
6903
|
+
"sd": 1.529,
|
|
6904
|
+
"separates": [
|
|
6905
|
+
"institutional",
|
|
6906
|
+
"literary"
|
|
6907
|
+
]
|
|
6908
|
+
},
|
|
6909
|
+
"commasPerSentence": {
|
|
6910
|
+
"p10": 0.2,
|
|
6911
|
+
"p50": 0.467,
|
|
6912
|
+
"p90": 0.826,
|
|
6913
|
+
"sd": 0.262,
|
|
6914
|
+
"separates": [
|
|
6915
|
+
"explanatory",
|
|
6916
|
+
"institutional",
|
|
6917
|
+
"literary",
|
|
6918
|
+
"marketing"
|
|
6919
|
+
]
|
|
6920
|
+
},
|
|
6921
|
+
"coordinationRate": {
|
|
6922
|
+
"p10": 0,
|
|
6923
|
+
"p50": 0.743,
|
|
6924
|
+
"p90": 1.712,
|
|
6925
|
+
"sd": 0.666,
|
|
6926
|
+
"separates": [
|
|
6927
|
+
"marketing"
|
|
6928
|
+
]
|
|
6929
|
+
},
|
|
6930
|
+
"figures": {
|
|
6931
|
+
"p10": 0.2,
|
|
6932
|
+
"p50": 0.8,
|
|
6933
|
+
"p90": 1.8,
|
|
6934
|
+
"sd": 0.725,
|
|
6935
|
+
"separates": [
|
|
6936
|
+
"literary"
|
|
6937
|
+
]
|
|
6938
|
+
},
|
|
6939
|
+
"firstPersonPer100": {
|
|
6940
|
+
"p10": 3.718,
|
|
6941
|
+
"p50": 5.968,
|
|
6942
|
+
"p90": 8.375,
|
|
6943
|
+
"sd": 1.825,
|
|
6944
|
+
"separates": [
|
|
6945
|
+
"explanatory"
|
|
6946
|
+
]
|
|
6947
|
+
},
|
|
6948
|
+
"generic": {
|
|
6949
|
+
"p10": 0,
|
|
6950
|
+
"p50": 0,
|
|
6951
|
+
"p90": 0.2,
|
|
6952
|
+
"sd": 0.138,
|
|
6953
|
+
"separates": [
|
|
6954
|
+
"explanatory"
|
|
6955
|
+
]
|
|
6956
|
+
},
|
|
6957
|
+
"hardPer100": {
|
|
6958
|
+
"p10": 4.289,
|
|
6959
|
+
"p50": 7.127,
|
|
6960
|
+
"p90": 11.308,
|
|
6961
|
+
"sd": 2.843,
|
|
6962
|
+
"separates": [
|
|
6963
|
+
"explanatory",
|
|
6964
|
+
"institutional",
|
|
6965
|
+
"literary"
|
|
6966
|
+
]
|
|
6967
|
+
},
|
|
6968
|
+
"impersonalOpenerShare": {
|
|
6969
|
+
"p10": 0,
|
|
6970
|
+
"p50": 0,
|
|
6971
|
+
"p90": 0.067,
|
|
6972
|
+
"sd": 0.031,
|
|
6973
|
+
"separates": [
|
|
6974
|
+
"explanatory"
|
|
6975
|
+
]
|
|
6976
|
+
},
|
|
6977
|
+
"meanSentenceWords": {
|
|
6978
|
+
"p10": 11.417,
|
|
6979
|
+
"p50": 14.25,
|
|
6980
|
+
"p90": 17.87,
|
|
6981
|
+
"sd": 2.656,
|
|
6982
|
+
"separates": [
|
|
6983
|
+
"explanatory",
|
|
6984
|
+
"literary"
|
|
6985
|
+
]
|
|
6986
|
+
},
|
|
6987
|
+
"meanWordLength": {
|
|
6988
|
+
"p10": 3.858,
|
|
6989
|
+
"p50": 4.16,
|
|
6990
|
+
"p90": 4.459,
|
|
6991
|
+
"sd": 0.231,
|
|
6992
|
+
"separates": [
|
|
6993
|
+
"explanatory"
|
|
6994
|
+
]
|
|
6995
|
+
},
|
|
6996
|
+
"names": {
|
|
6997
|
+
"p10": 1.2,
|
|
6998
|
+
"p50": 2.4,
|
|
6999
|
+
"p90": 3.6,
|
|
7000
|
+
"sd": 0.965,
|
|
7001
|
+
"separates": [
|
|
7002
|
+
"explanatory",
|
|
7003
|
+
"institutional"
|
|
7004
|
+
]
|
|
7005
|
+
},
|
|
7006
|
+
"nominalisationRate": {
|
|
7007
|
+
"p10": 0.625,
|
|
7008
|
+
"p50": 1.93,
|
|
7009
|
+
"p90": 3.831,
|
|
7010
|
+
"sd": 1.264,
|
|
7011
|
+
"separates": [
|
|
7012
|
+
"institutional",
|
|
7013
|
+
"marketing"
|
|
7014
|
+
]
|
|
7015
|
+
},
|
|
7016
|
+
"participialRate": {
|
|
7017
|
+
"p10": 0,
|
|
7018
|
+
"p50": 0,
|
|
7019
|
+
"p90": 0.05,
|
|
7020
|
+
"sd": 0.035,
|
|
7021
|
+
"separates": [
|
|
7022
|
+
"literary"
|
|
7023
|
+
]
|
|
7024
|
+
},
|
|
7025
|
+
"pronounOpenerShare": {
|
|
7026
|
+
"p10": 0,
|
|
7027
|
+
"p50": 0.05,
|
|
7028
|
+
"p90": 0.15,
|
|
7029
|
+
"sd": 0.068,
|
|
7030
|
+
"separates": [
|
|
7031
|
+
"marketing"
|
|
7032
|
+
]
|
|
7033
|
+
},
|
|
7034
|
+
"sentenceCv": {
|
|
7035
|
+
"p10": 0.344,
|
|
7036
|
+
"p50": 0.468,
|
|
7037
|
+
"p90": 0.6,
|
|
7038
|
+
"sd": 0.099,
|
|
7039
|
+
"separates": [
|
|
7040
|
+
"marketing"
|
|
7041
|
+
]
|
|
7042
|
+
},
|
|
7043
|
+
"skeletonRepeat": {
|
|
7044
|
+
"p10": 0,
|
|
7045
|
+
"p50": 0.017,
|
|
7046
|
+
"p90": 0.063,
|
|
7047
|
+
"sd": 0.031,
|
|
7048
|
+
"separates": [
|
|
7049
|
+
"institutional"
|
|
7050
|
+
]
|
|
7051
|
+
},
|
|
7052
|
+
"specificsPer100": {
|
|
7053
|
+
"p10": 4.22,
|
|
7054
|
+
"p50": 7.34,
|
|
7055
|
+
"p90": 11.46,
|
|
7056
|
+
"sd": 2.892,
|
|
7057
|
+
"separates": [
|
|
7058
|
+
"explanatory",
|
|
7059
|
+
"institutional",
|
|
7060
|
+
"literary"
|
|
7061
|
+
]
|
|
7062
|
+
},
|
|
7063
|
+
"tradePer100": {
|
|
7064
|
+
"p10": 0,
|
|
7065
|
+
"p50": 0,
|
|
7066
|
+
"p90": 0.588,
|
|
7067
|
+
"sd": 0.287,
|
|
7068
|
+
"separates": [
|
|
7069
|
+
"marketing"
|
|
7070
|
+
]
|
|
7071
|
+
},
|
|
7072
|
+
"tricolons": {
|
|
7073
|
+
"p10": 0,
|
|
7074
|
+
"p50": 0,
|
|
7075
|
+
"p90": 0.2,
|
|
7076
|
+
"sd": 0.142,
|
|
7077
|
+
"separates": [
|
|
7078
|
+
"institutional",
|
|
7079
|
+
"literary",
|
|
7080
|
+
"marketing"
|
|
7081
|
+
]
|
|
7082
|
+
}
|
|
7083
|
+
},
|
|
7084
|
+
"explanatory": {
|
|
7085
|
+
"clauseDepth": {
|
|
7086
|
+
"p10": 0.78,
|
|
7087
|
+
"p50": 1.194,
|
|
7088
|
+
"p90": 1.733,
|
|
7089
|
+
"sd": 0.383,
|
|
7090
|
+
"separates": [
|
|
7091
|
+
"business-email",
|
|
7092
|
+
"literary"
|
|
7093
|
+
]
|
|
7094
|
+
},
|
|
7095
|
+
"commasPer100": {
|
|
7096
|
+
"p10": 2.579,
|
|
7097
|
+
"p50": 4.164,
|
|
7098
|
+
"p90": 6.089,
|
|
7099
|
+
"sd": 1.423,
|
|
7100
|
+
"separates": [
|
|
7101
|
+
"literary"
|
|
7102
|
+
]
|
|
7103
|
+
},
|
|
7104
|
+
"commasPerSentence": {
|
|
7105
|
+
"p10": 0.448,
|
|
7106
|
+
"p50": 0.77,
|
|
7107
|
+
"p90": 1.2,
|
|
7108
|
+
"sd": 0.309,
|
|
7109
|
+
"separates": [
|
|
7110
|
+
"business-email",
|
|
7111
|
+
"literary"
|
|
7112
|
+
]
|
|
7113
|
+
},
|
|
7114
|
+
"coordinationRate": {
|
|
7115
|
+
"p10": 0.323,
|
|
7116
|
+
"p50": 0.973,
|
|
7117
|
+
"p90": 1.862,
|
|
7118
|
+
"sd": 0.612,
|
|
7119
|
+
"separates": [
|
|
7120
|
+
"marketing"
|
|
7121
|
+
]
|
|
7122
|
+
},
|
|
7123
|
+
"figures": {
|
|
7124
|
+
"p10": 0,
|
|
7125
|
+
"p50": 0.4,
|
|
7126
|
+
"p90": 1.4,
|
|
7127
|
+
"sd": 0.631,
|
|
7128
|
+
"separates": [
|
|
7129
|
+
"literary"
|
|
7130
|
+
]
|
|
7131
|
+
},
|
|
7132
|
+
"firstPersonPer100": {
|
|
7133
|
+
"p10": 0.27,
|
|
7134
|
+
"p50": 1.282,
|
|
7135
|
+
"p90": 3.114,
|
|
7136
|
+
"sd": 1.181,
|
|
7137
|
+
"separates": [
|
|
7138
|
+
"business-email",
|
|
7139
|
+
"literary"
|
|
7140
|
+
]
|
|
7141
|
+
},
|
|
7142
|
+
"generic": {
|
|
7143
|
+
"p10": 0,
|
|
7144
|
+
"p50": 0.4,
|
|
7145
|
+
"p90": 0.6,
|
|
7146
|
+
"sd": 0.214,
|
|
7147
|
+
"separates": [
|
|
7148
|
+
"business-email",
|
|
7149
|
+
"institutional"
|
|
7150
|
+
]
|
|
7151
|
+
},
|
|
7152
|
+
"hardPer100": {
|
|
7153
|
+
"p10": 0.988,
|
|
7154
|
+
"p50": 2.62,
|
|
7155
|
+
"p90": 5.171,
|
|
7156
|
+
"sd": 1.713,
|
|
7157
|
+
"separates": [
|
|
7158
|
+
"business-email",
|
|
7159
|
+
"institutional",
|
|
7160
|
+
"marketing"
|
|
7161
|
+
]
|
|
7162
|
+
},
|
|
7163
|
+
"impersonalOpenerShare": {
|
|
7164
|
+
"p10": 0,
|
|
7165
|
+
"p50": 0.04,
|
|
7166
|
+
"p90": 0.14,
|
|
7167
|
+
"sd": 0.061,
|
|
7168
|
+
"separates": [
|
|
7169
|
+
"business-email"
|
|
7170
|
+
]
|
|
7171
|
+
},
|
|
7172
|
+
"meanSentenceWords": {
|
|
7173
|
+
"p10": 14.973,
|
|
7174
|
+
"p50": 18.31,
|
|
7175
|
+
"p90": 22.533,
|
|
7176
|
+
"sd": 3.013,
|
|
7177
|
+
"separates": [
|
|
7178
|
+
"business-email"
|
|
7179
|
+
]
|
|
7180
|
+
},
|
|
7181
|
+
"meanWordLength": {
|
|
7182
|
+
"p10": 4.207,
|
|
7183
|
+
"p50": 4.466,
|
|
7184
|
+
"p90": 4.752,
|
|
7185
|
+
"sd": 0.213,
|
|
7186
|
+
"separates": [
|
|
7187
|
+
"business-email",
|
|
7188
|
+
"literary"
|
|
7189
|
+
]
|
|
7190
|
+
},
|
|
7191
|
+
"names": {
|
|
7192
|
+
"p10": 0.4,
|
|
7193
|
+
"p50": 1.2,
|
|
7194
|
+
"p90": 2.6,
|
|
7195
|
+
"sd": 0.941,
|
|
7196
|
+
"separates": [
|
|
7197
|
+
"business-email",
|
|
7198
|
+
"institutional"
|
|
7199
|
+
]
|
|
7200
|
+
},
|
|
7201
|
+
"nominalisationRate": {
|
|
7202
|
+
"p10": 0.766,
|
|
7203
|
+
"p50": 1.823,
|
|
7204
|
+
"p90": 3.416,
|
|
7205
|
+
"sd": 1.061,
|
|
7206
|
+
"separates": [
|
|
7207
|
+
"institutional",
|
|
7208
|
+
"marketing"
|
|
7209
|
+
]
|
|
7210
|
+
},
|
|
7211
|
+
"participialRate": {
|
|
7212
|
+
"p10": 0,
|
|
7213
|
+
"p50": 0,
|
|
7214
|
+
"p90": 0.1,
|
|
7215
|
+
"sd": 0.045,
|
|
7216
|
+
"separates": []
|
|
7217
|
+
},
|
|
7218
|
+
"pronounOpenerShare": {
|
|
7219
|
+
"p10": 0,
|
|
7220
|
+
"p50": 0.033,
|
|
7221
|
+
"p90": 0.124,
|
|
7222
|
+
"sd": 0.056,
|
|
7223
|
+
"separates": [
|
|
7224
|
+
"marketing"
|
|
7225
|
+
]
|
|
7226
|
+
},
|
|
7227
|
+
"sentenceCv": {
|
|
7228
|
+
"p10": 0.337,
|
|
7229
|
+
"p50": 0.441,
|
|
7230
|
+
"p90": 0.57,
|
|
7231
|
+
"sd": 0.092,
|
|
7232
|
+
"separates": []
|
|
7233
|
+
},
|
|
7234
|
+
"skeletonRepeat": {
|
|
7235
|
+
"p10": 9e-3,
|
|
7236
|
+
"p50": 0.039,
|
|
7237
|
+
"p90": 0.091,
|
|
7238
|
+
"sd": 0.036,
|
|
7239
|
+
"separates": []
|
|
7240
|
+
},
|
|
7241
|
+
"specificsPer100": {
|
|
7242
|
+
"p10": 1.04,
|
|
7243
|
+
"p50": 2.7,
|
|
7244
|
+
"p90": 5.36,
|
|
7245
|
+
"sd": 1.731,
|
|
7246
|
+
"separates": [
|
|
7247
|
+
"business-email",
|
|
7248
|
+
"institutional",
|
|
7249
|
+
"marketing"
|
|
7250
|
+
]
|
|
7251
|
+
},
|
|
7252
|
+
"tradePer100": {
|
|
7253
|
+
"p10": 0,
|
|
7254
|
+
"p50": 0,
|
|
7255
|
+
"p90": 0.427,
|
|
7256
|
+
"sd": 0.216,
|
|
7257
|
+
"separates": [
|
|
7258
|
+
"marketing"
|
|
7259
|
+
]
|
|
7260
|
+
},
|
|
7261
|
+
"tricolons": {
|
|
7262
|
+
"p10": 0,
|
|
7263
|
+
"p50": 0.2,
|
|
7264
|
+
"p90": 0.6,
|
|
7265
|
+
"sd": 0.222,
|
|
7266
|
+
"separates": []
|
|
7267
|
+
}
|
|
7268
|
+
},
|
|
7269
|
+
"institutional": {
|
|
7270
|
+
"clauseDepth": {
|
|
7271
|
+
"p10": 0.792,
|
|
7272
|
+
"p50": 1.233,
|
|
7273
|
+
"p90": 1.76,
|
|
7274
|
+
"sd": 0.377,
|
|
7275
|
+
"separates": [
|
|
7276
|
+
"business-email",
|
|
7277
|
+
"literary"
|
|
7278
|
+
]
|
|
7279
|
+
},
|
|
7280
|
+
"commasPer100": {
|
|
7281
|
+
"p10": 3.03,
|
|
7282
|
+
"p50": 4.435,
|
|
7283
|
+
"p90": 5.941,
|
|
7284
|
+
"sd": 1.165,
|
|
7285
|
+
"separates": [
|
|
7286
|
+
"business-email",
|
|
7287
|
+
"literary"
|
|
7288
|
+
]
|
|
7289
|
+
},
|
|
7290
|
+
"commasPerSentence": {
|
|
7291
|
+
"p10": 0.61,
|
|
7292
|
+
"p50": 0.96,
|
|
7293
|
+
"p90": 1.375,
|
|
7294
|
+
"sd": 0.307,
|
|
7295
|
+
"separates": [
|
|
7296
|
+
"business-email",
|
|
7297
|
+
"literary"
|
|
7298
|
+
]
|
|
7299
|
+
},
|
|
7300
|
+
"coordinationRate": {
|
|
7301
|
+
"p10": 0.323,
|
|
7302
|
+
"p50": 0.949,
|
|
7303
|
+
"p90": 1.752,
|
|
7304
|
+
"sd": 0.559,
|
|
7305
|
+
"separates": [
|
|
7306
|
+
"marketing"
|
|
7307
|
+
]
|
|
7308
|
+
},
|
|
7309
|
+
"figures": {
|
|
7310
|
+
"p10": 0,
|
|
7311
|
+
"p50": 0.6,
|
|
7312
|
+
"p90": 1.4,
|
|
7313
|
+
"sd": 0.56,
|
|
7314
|
+
"separates": [
|
|
7315
|
+
"literary"
|
|
7316
|
+
]
|
|
7317
|
+
},
|
|
7318
|
+
"generic": {
|
|
7319
|
+
"p10": 0,
|
|
7320
|
+
"p50": 0,
|
|
7321
|
+
"p90": 0.2,
|
|
7322
|
+
"sd": 0.114,
|
|
7323
|
+
"separates": [
|
|
7324
|
+
"explanatory",
|
|
7325
|
+
"literary",
|
|
7326
|
+
"marketing"
|
|
7327
|
+
]
|
|
7328
|
+
},
|
|
7329
|
+
"hardPer100": {
|
|
7330
|
+
"p10": 3.41,
|
|
7331
|
+
"p50": 5.135,
|
|
7332
|
+
"p90": 7.304,
|
|
7333
|
+
"sd": 1.573,
|
|
7334
|
+
"separates": [
|
|
7335
|
+
"business-email",
|
|
7336
|
+
"explanatory",
|
|
7337
|
+
"literary"
|
|
7338
|
+
]
|
|
7339
|
+
},
|
|
7340
|
+
"impersonalOpenerShare": {
|
|
7341
|
+
"p10": 0,
|
|
7342
|
+
"p50": 0.033,
|
|
7343
|
+
"p90": 0.109,
|
|
7344
|
+
"sd": 0.051,
|
|
7345
|
+
"separates": []
|
|
7346
|
+
},
|
|
7347
|
+
"names": {
|
|
7348
|
+
"p10": 2,
|
|
7349
|
+
"p50": 3.2,
|
|
7350
|
+
"p90": 4.8,
|
|
7351
|
+
"sd": 1.113,
|
|
7352
|
+
"separates": [
|
|
7353
|
+
"business-email",
|
|
7354
|
+
"explanatory",
|
|
7355
|
+
"literary",
|
|
7356
|
+
"marketing"
|
|
7357
|
+
]
|
|
7358
|
+
},
|
|
7359
|
+
"nominalisationRate": {
|
|
7360
|
+
"p10": 1.992,
|
|
7361
|
+
"p50": 3.391,
|
|
7362
|
+
"p90": 5.008,
|
|
7363
|
+
"sd": 1.147,
|
|
7364
|
+
"separates": [
|
|
7365
|
+
"business-email",
|
|
7366
|
+
"explanatory",
|
|
7367
|
+
"literary"
|
|
7368
|
+
]
|
|
7369
|
+
},
|
|
7370
|
+
"participialRate": {
|
|
7371
|
+
"p10": 0,
|
|
7372
|
+
"p50": 0,
|
|
7373
|
+
"p90": 0.1,
|
|
7374
|
+
"sd": 0.044,
|
|
7375
|
+
"separates": [
|
|
7376
|
+
"literary"
|
|
7377
|
+
]
|
|
7378
|
+
},
|
|
7379
|
+
"pronounOpenerShare": {
|
|
7380
|
+
"p10": 0,
|
|
7381
|
+
"p50": 0.05,
|
|
7382
|
+
"p90": 0.164,
|
|
7383
|
+
"sd": 0.068,
|
|
7384
|
+
"separates": [
|
|
7385
|
+
"marketing"
|
|
7386
|
+
]
|
|
7387
|
+
},
|
|
7388
|
+
"sentenceCv": {
|
|
7389
|
+
"p10": 0.386,
|
|
7390
|
+
"p50": 0.512,
|
|
7391
|
+
"p90": 0.639,
|
|
7392
|
+
"sd": 0.097,
|
|
7393
|
+
"separates": [
|
|
7394
|
+
"marketing"
|
|
7395
|
+
]
|
|
7396
|
+
},
|
|
7397
|
+
"skeletonRepeat": {
|
|
7398
|
+
"p10": 0.018,
|
|
7399
|
+
"p50": 0.048,
|
|
7400
|
+
"p90": 0.087,
|
|
7401
|
+
"sd": 0.028,
|
|
7402
|
+
"separates": [
|
|
7403
|
+
"business-email"
|
|
7404
|
+
]
|
|
7405
|
+
},
|
|
7406
|
+
"specificsPer100": {
|
|
7407
|
+
"p10": 3.36,
|
|
7408
|
+
"p50": 5.2,
|
|
7409
|
+
"p90": 7.4,
|
|
7410
|
+
"sd": 1.612,
|
|
7411
|
+
"separates": [
|
|
7412
|
+
"business-email",
|
|
7413
|
+
"explanatory",
|
|
7414
|
+
"literary"
|
|
7415
|
+
]
|
|
7416
|
+
},
|
|
7417
|
+
"tradePer100": {
|
|
7418
|
+
"p10": 0,
|
|
7419
|
+
"p50": 0,
|
|
7420
|
+
"p90": 0.157,
|
|
7421
|
+
"sd": 0.101,
|
|
7422
|
+
"separates": [
|
|
7423
|
+
"marketing"
|
|
7424
|
+
]
|
|
7425
|
+
},
|
|
7426
|
+
"tricolons": {
|
|
7427
|
+
"p10": 0,
|
|
7428
|
+
"p50": 0.2,
|
|
7429
|
+
"p90": 0.6,
|
|
7430
|
+
"sd": 0.233,
|
|
7431
|
+
"separates": [
|
|
7432
|
+
"business-email"
|
|
7433
|
+
]
|
|
7434
|
+
}
|
|
7435
|
+
},
|
|
7436
|
+
"literary": {
|
|
7437
|
+
"clauseDepth": {
|
|
7438
|
+
"p10": 1.333,
|
|
7439
|
+
"p50": 2.017,
|
|
7440
|
+
"p90": 2.933,
|
|
7441
|
+
"sd": 0.626,
|
|
7442
|
+
"separates": [
|
|
7443
|
+
"business-email",
|
|
7444
|
+
"explanatory",
|
|
7445
|
+
"institutional",
|
|
7446
|
+
"marketing"
|
|
7447
|
+
]
|
|
7448
|
+
},
|
|
7449
|
+
"commasPer100": {
|
|
7450
|
+
"p10": 5.997,
|
|
7451
|
+
"p50": 8.1,
|
|
7452
|
+
"p90": 10.586,
|
|
7453
|
+
"sd": 1.815,
|
|
7454
|
+
"separates": [
|
|
7455
|
+
"business-email",
|
|
7456
|
+
"explanatory",
|
|
7457
|
+
"institutional",
|
|
7458
|
+
"marketing"
|
|
7459
|
+
]
|
|
7460
|
+
},
|
|
7461
|
+
"commasPerSentence": {
|
|
7462
|
+
"p10": 1.067,
|
|
7463
|
+
"p50": 1.667,
|
|
7464
|
+
"p90": 2.435,
|
|
7465
|
+
"sd": 0.541,
|
|
7466
|
+
"separates": [
|
|
7467
|
+
"business-email",
|
|
7468
|
+
"explanatory",
|
|
7469
|
+
"institutional",
|
|
7470
|
+
"marketing"
|
|
7471
|
+
]
|
|
7472
|
+
},
|
|
7473
|
+
"coordinationRate": {
|
|
7474
|
+
"p10": 0.194,
|
|
7475
|
+
"p50": 0.814,
|
|
7476
|
+
"p90": 1.633,
|
|
7477
|
+
"sd": 0.572,
|
|
7478
|
+
"separates": [
|
|
7479
|
+
"marketing"
|
|
7480
|
+
]
|
|
7481
|
+
},
|
|
7482
|
+
"figures": {
|
|
7483
|
+
"p10": 0,
|
|
7484
|
+
"p50": 0,
|
|
7485
|
+
"p90": 0,
|
|
7486
|
+
"sd": 0.079,
|
|
7487
|
+
"separates": [
|
|
7488
|
+
"business-email",
|
|
7489
|
+
"explanatory",
|
|
7490
|
+
"institutional",
|
|
7491
|
+
"marketing"
|
|
7492
|
+
]
|
|
7493
|
+
},
|
|
7494
|
+
"firstPersonPer100": {
|
|
7495
|
+
"p10": 2.207,
|
|
7496
|
+
"p50": 4.67,
|
|
7497
|
+
"p90": 7.486,
|
|
7498
|
+
"sd": 2.027,
|
|
7499
|
+
"separates": [
|
|
7500
|
+
"explanatory"
|
|
7501
|
+
]
|
|
7502
|
+
},
|
|
7503
|
+
"generic": {
|
|
7504
|
+
"p10": 0,
|
|
7505
|
+
"p50": 0.2,
|
|
7506
|
+
"p90": 0.4,
|
|
7507
|
+
"sd": 0.178,
|
|
7508
|
+
"separates": [
|
|
7509
|
+
"institutional"
|
|
7510
|
+
]
|
|
7511
|
+
},
|
|
7512
|
+
"hardPer100": {
|
|
7513
|
+
"p10": 1.632,
|
|
7514
|
+
"p50": 3.076,
|
|
7515
|
+
"p90": 5.154,
|
|
7516
|
+
"sd": 1.367,
|
|
7517
|
+
"separates": [
|
|
7518
|
+
"business-email",
|
|
7519
|
+
"institutional"
|
|
7520
|
+
]
|
|
7521
|
+
},
|
|
7522
|
+
"impersonalOpenerShare": {
|
|
7523
|
+
"p10": 0,
|
|
7524
|
+
"p50": 0,
|
|
7525
|
+
"p90": 0.067,
|
|
7526
|
+
"sd": 0.039,
|
|
7527
|
+
"separates": []
|
|
7528
|
+
},
|
|
7529
|
+
"meanSentenceWords": {
|
|
7530
|
+
"p10": 15.083,
|
|
7531
|
+
"p50": 20.35,
|
|
7532
|
+
"p90": 27.027,
|
|
7533
|
+
"sd": 4.744,
|
|
7534
|
+
"separates": [
|
|
7535
|
+
"business-email"
|
|
7536
|
+
]
|
|
7537
|
+
},
|
|
7538
|
+
"meanWordLength": {
|
|
7539
|
+
"p10": 3.958,
|
|
7540
|
+
"p50": 4.186,
|
|
7541
|
+
"p90": 4.409,
|
|
7542
|
+
"sd": 0.175,
|
|
7543
|
+
"separates": [
|
|
7544
|
+
"explanatory"
|
|
7545
|
+
]
|
|
7546
|
+
},
|
|
7547
|
+
"names": {
|
|
7548
|
+
"p10": 1,
|
|
7549
|
+
"p50": 1.8,
|
|
7550
|
+
"p90": 3,
|
|
7551
|
+
"sd": 0.816,
|
|
7552
|
+
"separates": [
|
|
7553
|
+
"institutional"
|
|
7554
|
+
]
|
|
7555
|
+
},
|
|
7556
|
+
"nominalisationRate": {
|
|
7557
|
+
"p10": 0.444,
|
|
7558
|
+
"p50": 1.334,
|
|
7559
|
+
"p90": 2.486,
|
|
7560
|
+
"sd": 0.817,
|
|
7561
|
+
"separates": [
|
|
7562
|
+
"institutional",
|
|
7563
|
+
"marketing"
|
|
7564
|
+
]
|
|
7565
|
+
},
|
|
7566
|
+
"participialRate": {
|
|
7567
|
+
"p10": 0,
|
|
7568
|
+
"p50": 0.067,
|
|
7569
|
+
"p90": 0.2,
|
|
7570
|
+
"sd": 0.089,
|
|
7571
|
+
"separates": [
|
|
7572
|
+
"business-email",
|
|
7573
|
+
"institutional"
|
|
7574
|
+
]
|
|
7575
|
+
},
|
|
7576
|
+
"pronounOpenerShare": {
|
|
7577
|
+
"p10": 0,
|
|
7578
|
+
"p50": 0.025,
|
|
7579
|
+
"p90": 0.12,
|
|
7580
|
+
"sd": 0.058,
|
|
7581
|
+
"separates": [
|
|
7582
|
+
"marketing"
|
|
7583
|
+
]
|
|
7584
|
+
},
|
|
7585
|
+
"sentenceCv": {
|
|
7586
|
+
"p10": 0.367,
|
|
7587
|
+
"p50": 0.485,
|
|
7588
|
+
"p90": 0.625,
|
|
7589
|
+
"sd": 0.1,
|
|
7590
|
+
"separates": [
|
|
7591
|
+
"marketing"
|
|
7592
|
+
]
|
|
7593
|
+
},
|
|
7594
|
+
"skeletonRepeat": {
|
|
7595
|
+
"p10": 5e-3,
|
|
7596
|
+
"p50": 0.029,
|
|
7597
|
+
"p90": 0.07,
|
|
7598
|
+
"sd": 0.028,
|
|
7599
|
+
"separates": []
|
|
7600
|
+
},
|
|
7601
|
+
"specificsPer100": {
|
|
7602
|
+
"p10": 1.8,
|
|
7603
|
+
"p50": 3.28,
|
|
7604
|
+
"p90": 5.24,
|
|
7605
|
+
"sd": 1.365,
|
|
7606
|
+
"separates": [
|
|
7607
|
+
"business-email",
|
|
7608
|
+
"institutional",
|
|
7609
|
+
"marketing"
|
|
7610
|
+
]
|
|
7611
|
+
},
|
|
7612
|
+
"tradePer100": {
|
|
7613
|
+
"p10": 0,
|
|
7614
|
+
"p50": 0,
|
|
7615
|
+
"p90": 0.508,
|
|
7616
|
+
"sd": 0.275,
|
|
7617
|
+
"separates": [
|
|
7618
|
+
"marketing"
|
|
7619
|
+
]
|
|
7620
|
+
},
|
|
7621
|
+
"tricolons": {
|
|
7622
|
+
"p10": 0,
|
|
7623
|
+
"p50": 0.4,
|
|
7624
|
+
"p90": 0.8,
|
|
7625
|
+
"sd": 0.314,
|
|
7626
|
+
"separates": [
|
|
7627
|
+
"business-email"
|
|
7628
|
+
]
|
|
7629
|
+
}
|
|
7630
|
+
},
|
|
7631
|
+
"marketing": {
|
|
7632
|
+
"clauseDepth": {
|
|
7633
|
+
"p10": 0.567,
|
|
7634
|
+
"p50": 0.967,
|
|
7635
|
+
"p90": 1.56,
|
|
7636
|
+
"sd": 0.413,
|
|
7637
|
+
"separates": [
|
|
7638
|
+
"literary"
|
|
7639
|
+
]
|
|
7640
|
+
},
|
|
7641
|
+
"commasPer100": {
|
|
7642
|
+
"p10": 2.169,
|
|
7643
|
+
"p50": 4.087,
|
|
7644
|
+
"p90": 6.434,
|
|
7645
|
+
"sd": 1.667,
|
|
7646
|
+
"separates": [
|
|
7647
|
+
"literary"
|
|
7648
|
+
]
|
|
7649
|
+
},
|
|
7650
|
+
"commasPerSentence": {
|
|
7651
|
+
"p10": 0.4,
|
|
7652
|
+
"p50": 0.8,
|
|
7653
|
+
"p90": 1.35,
|
|
7654
|
+
"sd": 0.402,
|
|
7655
|
+
"separates": [
|
|
7656
|
+
"business-email",
|
|
7657
|
+
"literary"
|
|
7658
|
+
]
|
|
7659
|
+
},
|
|
7660
|
+
"coordinationRate": {
|
|
7661
|
+
"p10": 1.087,
|
|
7662
|
+
"p50": 2.236,
|
|
7663
|
+
"p90": 3.473,
|
|
7664
|
+
"sd": 0.931,
|
|
7665
|
+
"separates": [
|
|
7666
|
+
"business-email",
|
|
7667
|
+
"explanatory",
|
|
7668
|
+
"institutional",
|
|
7669
|
+
"literary"
|
|
7670
|
+
]
|
|
7671
|
+
},
|
|
7672
|
+
"figures": {
|
|
7673
|
+
"p10": 0,
|
|
7674
|
+
"p50": 0.4,
|
|
7675
|
+
"p90": 1,
|
|
7676
|
+
"sd": 0.427,
|
|
7677
|
+
"separates": [
|
|
7678
|
+
"literary"
|
|
7679
|
+
]
|
|
7680
|
+
},
|
|
7681
|
+
"generic": {
|
|
7682
|
+
"p10": 0,
|
|
7683
|
+
"p50": 0.2,
|
|
7684
|
+
"p90": 0.6,
|
|
7685
|
+
"sd": 0.206,
|
|
7686
|
+
"separates": [
|
|
7687
|
+
"institutional"
|
|
7688
|
+
]
|
|
7689
|
+
},
|
|
7690
|
+
"hardPer100": {
|
|
7691
|
+
"p10": 1.899,
|
|
7692
|
+
"p50": 4.549,
|
|
7693
|
+
"p90": 8.227,
|
|
7694
|
+
"sd": 2.655,
|
|
7695
|
+
"separates": [
|
|
7696
|
+
"explanatory"
|
|
7697
|
+
]
|
|
7698
|
+
},
|
|
7699
|
+
"impersonalOpenerShare": {
|
|
7700
|
+
"p10": 0,
|
|
7701
|
+
"p50": 0,
|
|
7702
|
+
"p90": 0.1,
|
|
7703
|
+
"sd": 0.047,
|
|
7704
|
+
"separates": []
|
|
7705
|
+
},
|
|
7706
|
+
"names": {
|
|
7707
|
+
"p10": 0.6,
|
|
7708
|
+
"p50": 1.8,
|
|
7709
|
+
"p90": 3.4,
|
|
7710
|
+
"sd": 1.21,
|
|
7711
|
+
"separates": [
|
|
7712
|
+
"institutional"
|
|
7713
|
+
]
|
|
7714
|
+
},
|
|
7715
|
+
"nominalisationRate": {
|
|
7716
|
+
"p10": 1.576,
|
|
7717
|
+
"p50": 3.222,
|
|
7718
|
+
"p90": 5.534,
|
|
7719
|
+
"sd": 1.6,
|
|
7720
|
+
"separates": [
|
|
7721
|
+
"business-email",
|
|
7722
|
+
"explanatory",
|
|
7723
|
+
"literary"
|
|
7724
|
+
]
|
|
7725
|
+
},
|
|
7726
|
+
"participialRate": {
|
|
7727
|
+
"p10": 0,
|
|
7728
|
+
"p50": 0,
|
|
7729
|
+
"p90": 0.133,
|
|
7730
|
+
"sd": 0.062,
|
|
7731
|
+
"separates": []
|
|
7732
|
+
},
|
|
7733
|
+
"pronounOpenerShare": {
|
|
7734
|
+
"p10": 0.067,
|
|
7735
|
+
"p50": 0.213,
|
|
7736
|
+
"p90": 0.4,
|
|
7737
|
+
"sd": 0.136,
|
|
7738
|
+
"separates": [
|
|
7739
|
+
"business-email",
|
|
7740
|
+
"explanatory",
|
|
7741
|
+
"institutional",
|
|
7742
|
+
"literary"
|
|
7743
|
+
]
|
|
7744
|
+
},
|
|
7745
|
+
"sentenceCv": {
|
|
7746
|
+
"p10": 0.275,
|
|
7747
|
+
"p50": 0.377,
|
|
7748
|
+
"p90": 0.52,
|
|
7749
|
+
"sd": 0.096,
|
|
7750
|
+
"separates": [
|
|
7751
|
+
"business-email",
|
|
7752
|
+
"institutional",
|
|
7753
|
+
"literary"
|
|
7754
|
+
]
|
|
7755
|
+
},
|
|
7756
|
+
"skeletonRepeat": {
|
|
7757
|
+
"p10": 0,
|
|
7758
|
+
"p50": 0.031,
|
|
7759
|
+
"p90": 0.081,
|
|
7760
|
+
"sd": 0.038,
|
|
7761
|
+
"separates": []
|
|
7762
|
+
},
|
|
7763
|
+
"specificsPer100": {
|
|
7764
|
+
"p10": 2.54,
|
|
7765
|
+
"p50": 5.2,
|
|
7766
|
+
"p90": 9.18,
|
|
7767
|
+
"sd": 2.733,
|
|
7768
|
+
"separates": [
|
|
7769
|
+
"explanatory",
|
|
7770
|
+
"literary"
|
|
7771
|
+
]
|
|
7772
|
+
},
|
|
7773
|
+
"tradePer100": {
|
|
7774
|
+
"p10": 0,
|
|
7775
|
+
"p50": 0.592,
|
|
7776
|
+
"p90": 1.515,
|
|
7777
|
+
"sd": 0.612,
|
|
7778
|
+
"separates": [
|
|
7779
|
+
"business-email",
|
|
7780
|
+
"explanatory",
|
|
7781
|
+
"institutional",
|
|
7782
|
+
"literary"
|
|
7783
|
+
]
|
|
7784
|
+
},
|
|
7785
|
+
"tricolons": {
|
|
7786
|
+
"p10": 0,
|
|
7787
|
+
"p50": 0.4,
|
|
7788
|
+
"p90": 0.8,
|
|
7789
|
+
"sd": 0.309,
|
|
7790
|
+
"separates": [
|
|
7791
|
+
"business-email"
|
|
7792
|
+
]
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
};
|
|
7796
|
+
|
|
6422
7797
|
// src/character/baseline.ts
|
|
6423
7798
|
var BASELINE_VERSION = 1;
|
|
6424
7799
|
function fnv1a(text) {
|
|
@@ -6519,23 +7894,23 @@ function parseCraftConfig(data, knownTells, source = "craft.config.json") {
|
|
|
6519
7894
|
return { ignore, severity, ...data.copyPaths ? { copyPaths: data.copyPaths } : {} };
|
|
6520
7895
|
}
|
|
6521
7896
|
function globToRegExp(glob) {
|
|
6522
|
-
const
|
|
7897
|
+
const pattern2 = glob.replace(/^\.\//, "").replace(/\/$/, "").replace(/\/\*\*$/, "");
|
|
6523
7898
|
let body = "";
|
|
6524
|
-
for (let i = 0; i <
|
|
6525
|
-
const c =
|
|
6526
|
-
if (c === "*" &&
|
|
6527
|
-
const slash =
|
|
7899
|
+
for (let i = 0; i < pattern2.length; i += 1) {
|
|
7900
|
+
const c = pattern2[i];
|
|
7901
|
+
if (c === "*" && pattern2[i + 1] === "*") {
|
|
7902
|
+
const slash = pattern2[i + 2] === "/";
|
|
6528
7903
|
body += slash ? "(?:.*/)?" : ".*";
|
|
6529
7904
|
i += slash ? 2 : 1;
|
|
6530
7905
|
} else if (c === "*") body += "[^/]*";
|
|
6531
7906
|
else if (c === "?") body += "[^/]";
|
|
6532
7907
|
else body += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
6533
7908
|
}
|
|
6534
|
-
const anywhere = !
|
|
7909
|
+
const anywhere = !pattern2.includes("/");
|
|
6535
7910
|
return new RegExp(`^${anywhere ? "(?:.*/)?" : ""}${body}(?:/.*)?$`);
|
|
6536
7911
|
}
|
|
6537
|
-
function ignoreMatcher(
|
|
6538
|
-
const res =
|
|
7912
|
+
function ignoreMatcher(patterns2) {
|
|
7913
|
+
const res = patterns2.map(globToRegExp);
|
|
6539
7914
|
return (path) => {
|
|
6540
7915
|
const p = path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
6541
7916
|
return res.some((re) => re.test(p));
|
|
@@ -6702,11 +8077,11 @@ function visualMeasures(img, maxSamples = 1e6) {
|
|
|
6702
8077
|
const sdRg = Math.sqrt(Math.max(0, sumRg2 / n - meanRg * meanRg));
|
|
6703
8078
|
const sdYb = Math.sqrt(Math.max(0, sumYb2 / n - meanYb * meanYb));
|
|
6704
8079
|
const colourfulness = Math.sqrt(sdRg ** 2 + sdYb ** 2) + 0.3 * Math.sqrt(meanRg ** 2 + meanYb ** 2);
|
|
6705
|
-
const
|
|
8080
|
+
const round3 = (v, d = 3) => Math.round(v * 10 ** d) / 10 ** d;
|
|
6706
8081
|
return {
|
|
6707
|
-
colourfulness:
|
|
6708
|
-
edgeDensity:
|
|
6709
|
-
symmetry:
|
|
8082
|
+
colourfulness: round3(colourfulness, 1),
|
|
8083
|
+
edgeDensity: round3(edgeN ? edges / edgeN : 0),
|
|
8084
|
+
symmetry: round3(asymN ? 1 - asym / asymN / 255 : 1),
|
|
6710
8085
|
width: w,
|
|
6711
8086
|
height: h,
|
|
6712
8087
|
sampled: n
|
|
@@ -7570,62 +8945,6 @@ function propose(input) {
|
|
|
7570
8945
|
};
|
|
7571
8946
|
}
|
|
7572
8947
|
|
|
7573
|
-
// src/estate/index.ts
|
|
7574
|
-
var ESTATE_VERSION = 1;
|
|
7575
|
-
var SIBLING_AT = 0.31;
|
|
7576
|
-
function emptyEstate() {
|
|
7577
|
-
return { version: ESTATE_VERSION, sites: [] };
|
|
7578
|
-
}
|
|
7579
|
-
function addSite(register, site) {
|
|
7580
|
-
if (!/^[a-z0-9][a-z0-9-]*$/.test(site.id)) throw new Error(`site id "${site.id}" must be short kebab-case`);
|
|
7581
|
-
const sites = [...register.sites.filter((s) => s.id !== site.id), site].sort((a, b) => a.id.localeCompare(b.id));
|
|
7582
|
-
return { version: ESTATE_VERSION, sites };
|
|
7583
|
-
}
|
|
7584
|
-
function sharedParts(a, b, d = fingerprintDistance(a, b)) {
|
|
7585
|
-
const out = [];
|
|
7586
|
-
const close = (k) => d.parts[k] <= SHARED_PART;
|
|
7587
|
-
if (close("accent")) out.push(a.accent || b.accent ? `${hueName(a.accent)} accent` : "no accent");
|
|
7588
|
-
if (close("type")) {
|
|
7589
|
-
if (a.display.family === b.display.family) out.push(`${a.display.family} headline`);
|
|
7590
|
-
if (a.body.family === b.body.family) out.push(`${a.body.family} body`);
|
|
7591
|
-
}
|
|
7592
|
-
if (close("ground")) out.push(`${groundName(a.ground)} ground`);
|
|
7593
|
-
if (close("shape")) out.push(`${shapeName(a.roundness)} buttons`);
|
|
7594
|
-
if (close("motion")) out.push(a.motion > 0 || b.motion > 0 ? "scroll reveals" : "no reveals");
|
|
7595
|
-
if (close("effects") && a.effects.length) out.push(a.effects.filter((e) => b.effects.includes(e)).join(", "));
|
|
7596
|
-
if (close("layout")) out.push("running order");
|
|
7597
|
-
return out;
|
|
7598
|
-
}
|
|
7599
|
-
function compareToEstate(target2, register, options = {}) {
|
|
7600
|
-
const at = options.siblingAt ?? SIBLING_AT;
|
|
7601
|
-
return register.sites.filter((s) => s.id !== options.exclude && s.fingerprint).map((s) => {
|
|
7602
|
-
const d = fingerprintDistance(target2, s.fingerprint);
|
|
7603
|
-
return { id: s.id, distance: d.total, sibling: d.total < at, shared: sharedParts(target2, s.fingerprint, d) };
|
|
7604
|
-
}).sort((a, b) => a.distance - b.distance);
|
|
7605
|
-
}
|
|
7606
|
-
function estatePairs(register, siblingAt = SIBLING_AT) {
|
|
7607
|
-
const out = [];
|
|
7608
|
-
const s = register.sites.filter((site) => site.fingerprint);
|
|
7609
|
-
for (let i = 0; i < s.length; i += 1) {
|
|
7610
|
-
for (let j = i + 1; j < s.length; j += 1) {
|
|
7611
|
-
const d = fingerprintDistance(s[i].fingerprint, s[j].fingerprint);
|
|
7612
|
-
out.push({ a: s[i].id, b: s[j].id, distance: d.total, sibling: d.total < siblingAt, shared: sharedParts(s[i].fingerprint, s[j].fingerprint, d) });
|
|
7613
|
-
}
|
|
7614
|
-
}
|
|
7615
|
-
return out.sort((x, y) => x.distance - y.distance);
|
|
7616
|
-
}
|
|
7617
|
-
function siblingLine(briefs) {
|
|
7618
|
-
const d = [];
|
|
7619
|
-
for (const runs of briefs) {
|
|
7620
|
-
for (let i = 0; i < runs.length; i += 1) for (let j = i + 1; j < runs.length; j += 1) d.push(fingerprintDistance(runs[i], runs[j]).total);
|
|
7621
|
-
}
|
|
7622
|
-
if (d.length === 0) throw new Error("no null pages to measure the sibling line from");
|
|
7623
|
-
d.sort((a, b) => a - b);
|
|
7624
|
-
const mid = Math.floor(d.length / 2);
|
|
7625
|
-
const m = d.length % 2 ? d[mid] : (d[mid - 1] + d[mid]) / 2;
|
|
7626
|
-
return Math.round(m * 1e3) / 1e3;
|
|
7627
|
-
}
|
|
7628
|
-
|
|
7629
8948
|
// src/report/index.ts
|
|
7630
8949
|
var TELL_HEAVY = 3;
|
|
7631
8950
|
var MIN_DECIDED = 5;
|
|
@@ -7781,6 +9100,155 @@ function choiceOfShared(part) {
|
|
|
7781
9100
|
return /running order/.test(part) ? void 0 : "motif";
|
|
7782
9101
|
}
|
|
7783
9102
|
|
|
9103
|
+
// src/calibrate/index.ts
|
|
9104
|
+
var LABELS2 = ["ai", "ai-looking", "human"];
|
|
9105
|
+
var FLAGGED_TARGET = 0.9;
|
|
9106
|
+
var HUMAN_TYPICAL_TARGET = 0.1;
|
|
9107
|
+
var SURFACE = new Map(CATALOGUE.map((t) => [t.id, t.surface]));
|
|
9108
|
+
var GENERATION = new Map(CATALOGUE.map((t) => [t.id, t.generation]));
|
|
9109
|
+
function designTells(tells) {
|
|
9110
|
+
return tells.filter((t) => SURFACE.has(t) && SURFACE.get(t) !== "copy");
|
|
9111
|
+
}
|
|
9112
|
+
function isFlagged(page) {
|
|
9113
|
+
return Boolean(page.typicality?.typical) || designTells(page.tells).length >= TELL_HEAVY;
|
|
9114
|
+
}
|
|
9115
|
+
var positive = (label) => label !== "human";
|
|
9116
|
+
var round2 = (n) => Math.round(n * 100) / 100;
|
|
9117
|
+
var share = (n, of) => `${n} of ${of} (${Math.round(100 * n / of)}%)`;
|
|
9118
|
+
function summarise(label, pages, typicality2) {
|
|
9119
|
+
const mine = pages.filter((p) => p.label === label);
|
|
9120
|
+
return {
|
|
9121
|
+
label,
|
|
9122
|
+
pages: mine.length,
|
|
9123
|
+
// A set measured partly against the null would count the same page two ways.
|
|
9124
|
+
flagged: mine.filter((p) => typicality2 ? isFlagged(p) : designTells(p.tells).length >= TELL_HEAVY).length,
|
|
9125
|
+
typical: typicality2 ? mine.filter((p) => p.typicality?.typical).length : null,
|
|
9126
|
+
tellHeavy: mine.filter((p) => designTells(p.tells).length >= TELL_HEAVY).length,
|
|
9127
|
+
blocking: mine.reduce((s, p) => s + p.blocking, 0)
|
|
9128
|
+
};
|
|
9129
|
+
}
|
|
9130
|
+
function flaggedTarget(target2, s, missing) {
|
|
9131
|
+
const note = missing ? `; ${missing} not measured, counted neither way` : "";
|
|
9132
|
+
if (s.pages === 0) return { target: target2, met: null, detail: `no page measured${note}` };
|
|
9133
|
+
return { target: target2, met: s.flagged / s.pages >= FLAGGED_TARGET, detail: `${share(s.flagged, s.pages)} flagged, target ${FLAGGED_TARGET * 100}% or more${note}` };
|
|
9134
|
+
}
|
|
9135
|
+
function calibrate(pages, unmeasured = []) {
|
|
9136
|
+
const typicality2 = pages.length > 0 && pages.every((p) => p.typicality !== void 0);
|
|
9137
|
+
const labels = LABELS2.map((l) => summarise(l, pages, typicality2));
|
|
9138
|
+
const byLabel = Object.fromEntries(labels.map((s) => [s.label, s]));
|
|
9139
|
+
const missing = (l) => unmeasured.filter((u) => u.label === l).length;
|
|
9140
|
+
const positives = pages.filter((p) => positive(p.label)).length;
|
|
9141
|
+
const fired = new Set(pages.flatMap((p) => p.tells));
|
|
9142
|
+
const tells = [...fired].map((tell) => {
|
|
9143
|
+
const hits = Object.fromEntries(LABELS2.map((l) => [l, pages.filter((p) => p.label === l && p.tells.includes(tell)).length]));
|
|
9144
|
+
const on = hits.ai + hits["ai-looking"];
|
|
9145
|
+
return { tell, generation: GENERATION.get(tell) ?? null, hits, precision: round2(on / (on + hits.human)), recall: positives ? round2(on / positives) : null };
|
|
9146
|
+
}).sort((a, b) => b.hits.ai + b.hits["ai-looking"] + b.hits.human - (a.hits.ai + a.hits["ai-looking"] + a.hits.human) || a.tell.localeCompare(b.tell));
|
|
9147
|
+
const human = byLabel.human;
|
|
9148
|
+
const humanNote = missing("human") ? `; ${missing("human")} not measured, counted neither way` : "";
|
|
9149
|
+
const targets = [
|
|
9150
|
+
flaggedTarget("1. Generated pages get caught", byLabel.ai, missing("ai")),
|
|
9151
|
+
human.pages === 0 ? { target: "2. Good human sites don't get caught", met: null, detail: `no page measured${humanNote}` } : {
|
|
9152
|
+
target: "2. Good human sites don't get caught",
|
|
9153
|
+
// A block hit fails it outright; without null models the other half is not known.
|
|
9154
|
+
met: human.blocking > 0 ? false : human.typical === null ? null : human.typical / human.pages <= HUMAN_TYPICAL_TARGET,
|
|
9155
|
+
detail: `${human.blocking} block hits, target 0; ${human.typical === null ? "typicality not measured (no null models)" : `${share(human.typical, human.pages)} typical, target ${HUMAN_TYPICAL_TARGET * 100}% or fewer`}${humanNote}`
|
|
9156
|
+
},
|
|
9157
|
+
flaggedTarget("3. Sites a person labelled AI-looking get caught", byLabel["ai-looking"], missing("ai-looking"))
|
|
9158
|
+
];
|
|
9159
|
+
return {
|
|
9160
|
+
pages: pages.length,
|
|
9161
|
+
typicality: typicality2,
|
|
9162
|
+
labels,
|
|
9163
|
+
tells,
|
|
9164
|
+
silent: CATALOGUE.map((t) => t.id).filter((id) => !fired.has(id)),
|
|
9165
|
+
targets,
|
|
9166
|
+
unmeasured
|
|
9167
|
+
};
|
|
9168
|
+
}
|
|
9169
|
+
function formatCalibration(c, notes = []) {
|
|
9170
|
+
const counts = c.labels.map((s) => `${s.pages} ${s.label}`).join(", ");
|
|
9171
|
+
const lines = [`craft calibrate: ${c.pages} pages measured (${counts})`, ...notes];
|
|
9172
|
+
if (!c.typicality) lines.push("No null models: flagged means tell-heavy only.");
|
|
9173
|
+
if (c.unmeasured.length) {
|
|
9174
|
+
lines.push("", `Not measured: ${c.unmeasured.length}. A page not measured never counts as a pass.`);
|
|
9175
|
+
for (const u of c.unmeasured) lines.push(` ${u.id} (${u.label}): ${u.reason}`);
|
|
9176
|
+
}
|
|
9177
|
+
lines.push("", "Flagged is a look-closer signal, not a verdict that a site is AI-made. Nothing gates on it.", "", "Targets");
|
|
9178
|
+
for (const t of c.targets) lines.push(` ${t.target.padEnd(50)} ${t.met === null ? "not known" : t.met ? "met" : "NOT MET"}`, ` ${t.detail}`);
|
|
9179
|
+
lines.push("", ` ${"label".padEnd(11)} ${"pages".padStart(5)} ${"flagged".padStart(8)} ${"typical".padStart(8)} ${"tell-heavy".padStart(11)} ${"blocking".padStart(9)}`);
|
|
9180
|
+
for (const s of c.labels) {
|
|
9181
|
+
lines.push(` ${s.label.padEnd(11)} ${String(s.pages).padStart(5)} ${String(s.flagged).padStart(8)} ${String(s.typical ?? "-").padStart(8)} ${String(s.tellHeavy).padStart(11)} ${String(s.blocking).padStart(9)}`);
|
|
9182
|
+
}
|
|
9183
|
+
lines.push("", "Per tell. A hit on ai or ai-looking counts for the tell; a hit on human counts against it.");
|
|
9184
|
+
lines.push(` ${"tell".padEnd(28)} ${"gen".padStart(3)} ${"ai".padStart(7)} ${"ai-looking".padStart(10)} ${"human".padStart(7)} ${"precision".padStart(9)} ${"recall".padStart(7)}`);
|
|
9185
|
+
const of = (l) => c.labels.find((s) => s.label === l)?.pages ?? 0;
|
|
9186
|
+
for (const t of c.tells) {
|
|
9187
|
+
lines.push(
|
|
9188
|
+
` ${t.tell.padEnd(28)} ${String(t.generation ?? "-").padStart(3)} ${`${t.hits.ai}/${of("ai")}`.padStart(7)} ${`${t.hits["ai-looking"]}/${of("ai-looking")}`.padStart(10)} ${`${t.hits.human}/${of("human")}`.padStart(7)} ${t.precision.toFixed(2).padStart(9)} ${(t.recall === null ? "-" : t.recall.toFixed(2)).padStart(7)}`
|
|
9189
|
+
);
|
|
9190
|
+
}
|
|
9191
|
+
if (!c.tells.length) lines.push(" no tell fired");
|
|
9192
|
+
lines.push("", `Never fired on this set: ${c.silent.length} of ${CATALOGUE.length} catalogue tells.`);
|
|
9193
|
+
return lines.join("\n");
|
|
9194
|
+
}
|
|
9195
|
+
|
|
9196
|
+
// src/estate/index.ts
|
|
9197
|
+
var ESTATE_VERSION = 1;
|
|
9198
|
+
var SIBLING_AT = 0.31;
|
|
9199
|
+
function emptyEstate() {
|
|
9200
|
+
return { version: ESTATE_VERSION, sites: [] };
|
|
9201
|
+
}
|
|
9202
|
+
function addSite(register, site) {
|
|
9203
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(site.id)) throw new Error(`site id "${site.id}" must be short kebab-case`);
|
|
9204
|
+
const sites = [...register.sites.filter((s) => s.id !== site.id), site].sort((a, b) => a.id.localeCompare(b.id));
|
|
9205
|
+
return { version: ESTATE_VERSION, sites };
|
|
9206
|
+
}
|
|
9207
|
+
function sharedParts(a, b, d = fingerprintDistance(a, b)) {
|
|
9208
|
+
const out = [];
|
|
9209
|
+
const close = (k) => d.parts[k] <= SHARED_PART;
|
|
9210
|
+
if (close("accent")) out.push(a.accent || b.accent ? `${hueName(a.accent)} accent` : "no accent");
|
|
9211
|
+
if (close("type")) {
|
|
9212
|
+
if (a.display.family === b.display.family) out.push(`${a.display.family} headline`);
|
|
9213
|
+
if (a.body.family === b.body.family) out.push(`${a.body.family} body`);
|
|
9214
|
+
}
|
|
9215
|
+
if (close("ground")) out.push(`${groundName(a.ground)} ground`);
|
|
9216
|
+
if (close("shape")) out.push(`${shapeName(a.roundness)} buttons`);
|
|
9217
|
+
if (close("motion")) out.push(a.motion > 0 || b.motion > 0 ? "scroll reveals" : "no reveals");
|
|
9218
|
+
if (close("effects") && a.effects.length) out.push(a.effects.filter((e) => b.effects.includes(e)).join(", "));
|
|
9219
|
+
if (close("layout")) out.push("running order");
|
|
9220
|
+
return out;
|
|
9221
|
+
}
|
|
9222
|
+
function compareToEstate(target2, register, options = {}) {
|
|
9223
|
+
const at = options.siblingAt ?? SIBLING_AT;
|
|
9224
|
+
return register.sites.filter((s) => s.id !== options.exclude && s.fingerprint).map((s) => {
|
|
9225
|
+
const d = fingerprintDistance(target2, s.fingerprint);
|
|
9226
|
+
return { id: s.id, distance: d.total, sibling: d.total < at, shared: sharedParts(target2, s.fingerprint, d) };
|
|
9227
|
+
}).sort((a, b) => a.distance - b.distance);
|
|
9228
|
+
}
|
|
9229
|
+
function estatePairs(register, siblingAt = SIBLING_AT) {
|
|
9230
|
+
const out = [];
|
|
9231
|
+
const s = register.sites.filter((site) => site.fingerprint);
|
|
9232
|
+
for (let i = 0; i < s.length; i += 1) {
|
|
9233
|
+
for (let j = i + 1; j < s.length; j += 1) {
|
|
9234
|
+
const d = fingerprintDistance(s[i].fingerprint, s[j].fingerprint);
|
|
9235
|
+
out.push({ a: s[i].id, b: s[j].id, distance: d.total, sibling: d.total < siblingAt, shared: sharedParts(s[i].fingerprint, s[j].fingerprint, d) });
|
|
9236
|
+
}
|
|
9237
|
+
}
|
|
9238
|
+
return out.sort((x, y) => x.distance - y.distance);
|
|
9239
|
+
}
|
|
9240
|
+
function siblingLine(briefs) {
|
|
9241
|
+
const d = [];
|
|
9242
|
+
for (const runs of briefs) {
|
|
9243
|
+
for (let i = 0; i < runs.length; i += 1) for (let j = i + 1; j < runs.length; j += 1) d.push(fingerprintDistance(runs[i], runs[j]).total);
|
|
9244
|
+
}
|
|
9245
|
+
if (d.length === 0) throw new Error("no null pages to measure the sibling line from");
|
|
9246
|
+
d.sort((a, b) => a - b);
|
|
9247
|
+
const mid = Math.floor(d.length / 2);
|
|
9248
|
+
const m = d.length % 2 ? d[mid] : (d[mid - 1] + d[mid]) / 2;
|
|
9249
|
+
return Math.round(m * 1e3) / 1e3;
|
|
9250
|
+
}
|
|
9251
|
+
|
|
7784
9252
|
// src/report/retrofit.ts
|
|
7785
9253
|
var HEADINGS = {
|
|
7786
9254
|
direction: "Decide first",
|
|
@@ -7847,6 +9315,7 @@ function retrofitPlan(report2, direction) {
|
|
|
7847
9315
|
CHOICE_KEYS,
|
|
7848
9316
|
COMPONENT_ROLES,
|
|
7849
9317
|
CONSIDERATION,
|
|
9318
|
+
CONTENT_FEATURES,
|
|
7850
9319
|
CONVENTION,
|
|
7851
9320
|
CUSTOMER_KINDS,
|
|
7852
9321
|
DEFAULT_IGNORE,
|
|
@@ -7863,6 +9332,7 @@ function retrofitPlan(report2, direction) {
|
|
|
7863
9332
|
ESTATE_VERSION,
|
|
7864
9333
|
EXIT_RATIO,
|
|
7865
9334
|
FINGERPRINT_VERSION,
|
|
9335
|
+
FLAGGED_TARGET,
|
|
7866
9336
|
FUNCTION_WORDS,
|
|
7867
9337
|
GROUND_SCALE,
|
|
7868
9338
|
GROUND_SHARED,
|
|
@@ -7873,11 +9343,15 @@ function retrofitPlan(report2, direction) {
|
|
|
7873
9343
|
HOUSE_BUDGET,
|
|
7874
9344
|
HOUSE_LOCKED,
|
|
7875
9345
|
HOUSE_TYPE,
|
|
9346
|
+
HUMAN_TYPICAL_TARGET,
|
|
7876
9347
|
IMAGERY_TELLS,
|
|
7877
9348
|
JSON_SCHEMA_VERSION,
|
|
9349
|
+
LABELS,
|
|
9350
|
+
LEXICAL_FEATURES,
|
|
7878
9351
|
LICENCES,
|
|
7879
9352
|
LIGHTNESS_CURVE,
|
|
7880
9353
|
MIN_DECIDED,
|
|
9354
|
+
MIN_PARAGRAPHS,
|
|
7881
9355
|
MIN_RUNS,
|
|
7882
9356
|
MOOD,
|
|
7883
9357
|
NEGATIVE_REASSURANCE,
|
|
@@ -7886,6 +9360,9 @@ function retrofitPlan(report2, direction) {
|
|
|
7886
9360
|
PILL_LIMIT,
|
|
7887
9361
|
PLAINER_WORDS,
|
|
7888
9362
|
PREFERENCE,
|
|
9363
|
+
PROFILE,
|
|
9364
|
+
PROFILE_MEASURED,
|
|
9365
|
+
PROFILE_PARAGRAPHS,
|
|
7889
9366
|
PROMO_BADGE,
|
|
7890
9367
|
PROOF_NAMES,
|
|
7891
9368
|
PROPOSED,
|
|
@@ -7894,6 +9371,10 @@ function retrofitPlan(report2, direction) {
|
|
|
7894
9371
|
READABLE_SNAPSHOT_VERSIONS,
|
|
7895
9372
|
REFLEX_FONTS_1,
|
|
7896
9373
|
REFLEX_FONTS_2,
|
|
9374
|
+
REGISTERS,
|
|
9375
|
+
REGISTER_BASELINE,
|
|
9376
|
+
REGISTER_FEATURES,
|
|
9377
|
+
REGISTER_IDS,
|
|
7897
9378
|
RENDERED_PATHS,
|
|
7898
9379
|
RENDERED_TELLS,
|
|
7899
9380
|
REVEAL_LIMIT,
|
|
@@ -7915,6 +9396,7 @@ function retrofitPlan(report2, direction) {
|
|
|
7915
9396
|
STOCK_FIGURES,
|
|
7916
9397
|
STOCK_PHOTO_HOSTS,
|
|
7917
9398
|
STOCK_PHRASES,
|
|
9399
|
+
STUDY_WORDS,
|
|
7918
9400
|
TELL_HEAVY,
|
|
7919
9401
|
TRADE_NOUNS,
|
|
7920
9402
|
TYPE_STEPS,
|
|
@@ -7928,12 +9410,14 @@ function retrofitPlan(report2, direction) {
|
|
|
7928
9410
|
applySeverity,
|
|
7929
9411
|
auditSnapshot,
|
|
7930
9412
|
briefTerms,
|
|
9413
|
+
calibrate,
|
|
7931
9414
|
catalogueTable,
|
|
7932
9415
|
characterReport,
|
|
7933
9416
|
checkCopy,
|
|
7934
9417
|
checkOrder,
|
|
7935
9418
|
checkPair,
|
|
7936
9419
|
checkReason,
|
|
9420
|
+
checkRegister,
|
|
7937
9421
|
checkRestraint,
|
|
7938
9422
|
choicesOf,
|
|
7939
9423
|
clauseDepth,
|
|
@@ -7957,6 +9441,8 @@ function retrofitPlan(report2, direction) {
|
|
|
7957
9441
|
deltaEOkHex,
|
|
7958
9442
|
densityCss,
|
|
7959
9443
|
densityTokens,
|
|
9444
|
+
designTells,
|
|
9445
|
+
documentParagraphs,
|
|
7960
9446
|
emitCss,
|
|
7961
9447
|
emptyEstate,
|
|
7962
9448
|
estateComponentPairs,
|
|
@@ -7964,6 +9450,7 @@ function retrofitPlan(report2, direction) {
|
|
|
7964
9450
|
exitDuration,
|
|
7965
9451
|
extractHtml,
|
|
7966
9452
|
faceLicence,
|
|
9453
|
+
featureLabel,
|
|
7967
9454
|
findClaims,
|
|
7968
9455
|
findColours,
|
|
7969
9456
|
findingKey,
|
|
@@ -7973,12 +9460,14 @@ function retrofitPlan(report2, direction) {
|
|
|
7973
9460
|
fluidSpace,
|
|
7974
9461
|
fluidType,
|
|
7975
9462
|
fontClass,
|
|
9463
|
+
formatCalibration,
|
|
7976
9464
|
formatClaims,
|
|
7977
9465
|
formatComparison,
|
|
7978
9466
|
formatCompetitor,
|
|
7979
9467
|
formatDirectionMatches,
|
|
7980
9468
|
formatHex,
|
|
7981
9469
|
formatReport,
|
|
9470
|
+
getRegister,
|
|
7982
9471
|
globToRegExp,
|
|
7983
9472
|
groundName,
|
|
7984
9473
|
harvest,
|
|
@@ -7997,8 +9486,10 @@ function retrofitPlan(report2, direction) {
|
|
|
7997
9486
|
isBlurb,
|
|
7998
9487
|
isCategoryLabel,
|
|
7999
9488
|
isCream,
|
|
9489
|
+
isFlagged,
|
|
8000
9490
|
jobWords,
|
|
8001
9491
|
layoutDistance,
|
|
9492
|
+
lexicalOf,
|
|
8002
9493
|
licencesJson,
|
|
8003
9494
|
makeSnapshot,
|
|
8004
9495
|
motionTokens,
|
|
@@ -8023,6 +9514,9 @@ function retrofitPlan(report2, direction) {
|
|
|
8023
9514
|
ramp,
|
|
8024
9515
|
rampFromAnchors,
|
|
8025
9516
|
readSnapshot,
|
|
9517
|
+
registerBrief,
|
|
9518
|
+
registerOf,
|
|
9519
|
+
registersDoc,
|
|
8026
9520
|
renderedOrder,
|
|
8027
9521
|
researchPrompt,
|
|
8028
9522
|
retrofitPlan,
|
|
@@ -8065,6 +9559,8 @@ function retrofitPlan(report2, direction) {
|
|
|
8065
9559
|
validateJob,
|
|
8066
9560
|
visibleText,
|
|
8067
9561
|
visualMeasures,
|
|
9562
|
+
vocabulary,
|
|
9563
|
+
vocabularyCounts,
|
|
8068
9564
|
wcagContrast,
|
|
8069
9565
|
wordListsJson
|
|
8070
9566
|
});
|