@domandigital/craft 0.9.0 → 0.11.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 +26 -0
- package/CHARACTER.md +2 -1
- package/COPY.md +6 -0
- package/README.md +41 -0
- package/dist/{audit-5P65UMFL.js → audit-QIPXL7E4.js} +3 -3
- package/dist/audit.cjs +67 -11
- package/dist/audit.js +67 -11
- package/dist/chunk-2AJB27BJ.js +743 -0
- package/dist/{chunk-ZT3WLN7R.js → chunk-3NGWXZZE.js} +64 -10
- package/dist/{chunk-VKQDOUHO.js → chunk-3OZQ4C5R.js} +7 -6
- package/dist/{chunk-5LI2VFN5.js → chunk-HOHHQB4N.js} +9 -8
- package/dist/{chunk-BYY32NIN.js → chunk-JP75P2DU.js} +5 -3
- package/dist/{chunk-JRMU6GYX.js → chunk-JWHC67ZS.js} +1 -1
- package/dist/chunk-MSQ57PJU.js +206 -0
- package/dist/{chunk-EHNEGKFR.js → chunk-QMYERCBB.js} +1 -1
- package/dist/{cli-4VAOH7ST.js → cli-4ESXOLKV.js} +4 -4
- package/dist/{cli-V55MTIOP.js → cli-DBZMVYYV.js} +20 -14
- package/dist/cli-T5RD2BTK.js +17 -0
- package/dist/{cli-3XPEGBUR.js → cli-U3SZVHSK.js} +7 -6
- package/dist/cli-VREYWCT4.js +16 -0
- package/dist/cli.js +2 -2
- package/dist/index.cjs +400 -10
- package/dist/index.d.cts +227 -2
- package/dist/index.d.ts +227 -2
- package/dist/index.js +383 -10
- package/package.json +13 -6
- package/word-lists.json +1 -1
- package/dist/chunk-DAENYJUO.js +0 -112
- package/dist/chunk-YLQE35PN.js +0 -364
- package/dist/cli-J7C6TI2B.js +0 -16
- package/dist/cli-WDSVVHKG.js +0 -15
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatMatches,
|
|
3
|
+
formatPairs,
|
|
4
|
+
loadEstate,
|
|
5
|
+
runEstate
|
|
6
|
+
} from "./chunk-HOHHQB4N.js";
|
|
7
|
+
import "./chunk-3OZQ4C5R.js";
|
|
8
|
+
import "./chunk-2AJB27BJ.js";
|
|
9
|
+
import "./chunk-QMYERCBB.js";
|
|
10
|
+
import "./chunk-3NGWXZZE.js";
|
|
11
|
+
export {
|
|
12
|
+
formatMatches,
|
|
13
|
+
formatPairs,
|
|
14
|
+
loadEstate,
|
|
15
|
+
runEstate
|
|
16
|
+
};
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -23,10 +23,12 @@ __export(index_exports, {
|
|
|
23
23
|
AI_PHRASES: () => AI_PHRASES,
|
|
24
24
|
AI_VIOLET: () => AI_VIOLET,
|
|
25
25
|
AI_WORDS: () => AI_WORDS,
|
|
26
|
+
BASELINE_VERSION: () => BASELINE_VERSION,
|
|
26
27
|
BUZZWORDS: () => BUZZWORDS,
|
|
27
28
|
CATALOGUE: () => CATALOGUE,
|
|
28
29
|
CATALOGUE_VERSION: () => CATALOGUE_VERSION,
|
|
29
30
|
CHOICE_KEYS: () => CHOICE_KEYS,
|
|
31
|
+
DEFAULT_IGNORE: () => DEFAULT_IGNORE,
|
|
30
32
|
DENSITIES: () => DENSITIES,
|
|
31
33
|
DENSITY_NAMES: () => DENSITY_NAMES,
|
|
32
34
|
DIRECTION_VERSION: () => DIRECTION_VERSION,
|
|
@@ -41,6 +43,7 @@ __export(index_exports, {
|
|
|
41
43
|
HOUSE: () => HOUSE,
|
|
42
44
|
HOUSE_BUDGET: () => HOUSE_BUDGET,
|
|
43
45
|
HOUSE_TYPE: () => HOUSE_TYPE,
|
|
46
|
+
JSON_SCHEMA_VERSION: () => JSON_SCHEMA_VERSION,
|
|
44
47
|
LIGHTNESS_CURVE: () => LIGHTNESS_CURVE,
|
|
45
48
|
MIN_DECIDED: () => MIN_DECIDED,
|
|
46
49
|
MIN_RUNS: () => MIN_RUNS,
|
|
@@ -71,7 +74,9 @@ __export(index_exports, {
|
|
|
71
74
|
accentFork: () => accentFork,
|
|
72
75
|
addSite: () => addSite,
|
|
73
76
|
apcaContrast: () => apcaContrast,
|
|
77
|
+
applyBaseline: () => applyBaseline,
|
|
74
78
|
applyHouseGate: () => applyHouseGate,
|
|
79
|
+
applySeverity: () => applySeverity,
|
|
75
80
|
auditSnapshot: () => auditSnapshot,
|
|
76
81
|
catalogueTable: () => catalogueTable,
|
|
77
82
|
characterReport: () => characterReport,
|
|
@@ -82,6 +87,7 @@ __export(index_exports, {
|
|
|
82
87
|
compareFacts: () => compareFacts,
|
|
83
88
|
compareToEstate: () => compareToEstate,
|
|
84
89
|
craftTokens: () => craftTokens,
|
|
90
|
+
createBaseline: () => createBaseline,
|
|
85
91
|
deltaEOk: () => deltaEOk,
|
|
86
92
|
deltaEOkHex: () => deltaEOkHex,
|
|
87
93
|
densityCss: () => densityCss,
|
|
@@ -91,22 +97,27 @@ __export(index_exports, {
|
|
|
91
97
|
estatePairs: () => estatePairs,
|
|
92
98
|
exitDuration: () => exitDuration,
|
|
93
99
|
extractHtml: () => extractHtml,
|
|
100
|
+
findClaims: () => findClaims,
|
|
94
101
|
findColours: () => findColours,
|
|
102
|
+
findingKey: () => findingKey,
|
|
95
103
|
fingerprint: () => fingerprint,
|
|
96
104
|
fingerprintDistance: () => fingerprintDistance,
|
|
97
105
|
fluidClamp: () => fluidClamp,
|
|
98
106
|
fluidSpace: () => fluidSpace,
|
|
99
107
|
fluidType: () => fluidType,
|
|
100
108
|
fontClass: () => fontClass,
|
|
109
|
+
formatClaims: () => formatClaims,
|
|
101
110
|
formatComparison: () => formatComparison,
|
|
102
111
|
formatHex: () => formatHex,
|
|
103
112
|
formatReport: () => formatReport,
|
|
113
|
+
globToRegExp: () => globToRegExp,
|
|
104
114
|
groundName: () => groundName,
|
|
105
115
|
harvest: () => harvest,
|
|
106
116
|
hexToOklch: () => hexToOklch,
|
|
107
117
|
houseRule: () => houseRule,
|
|
108
118
|
hueName: () => hueName,
|
|
109
119
|
hueSwatch: () => hueSwatch,
|
|
120
|
+
ignoreMatcher: () => ignoreMatcher,
|
|
110
121
|
inP3Gamut: () => inP3Gamut,
|
|
111
122
|
inSrgbGamut: () => inSrgbGamut,
|
|
112
123
|
initDirection: () => initDirection,
|
|
@@ -114,13 +125,16 @@ __export(index_exports, {
|
|
|
114
125
|
isCream: () => isCream,
|
|
115
126
|
makeSnapshot: () => makeSnapshot,
|
|
116
127
|
motionTokens: () => motionTokens,
|
|
128
|
+
namedSources: () => namedSources,
|
|
117
129
|
nearest: () => nearest,
|
|
118
130
|
normaliseFamily: () => normaliseFamily,
|
|
119
131
|
nullPrompt: () => nullPrompt,
|
|
120
132
|
oklchToHex: () => oklchToHex,
|
|
121
133
|
oklchToRgb: () => oklchToRgb,
|
|
122
134
|
paletteFromPixels: () => paletteFromPixels,
|
|
135
|
+
parseBaseline: () => parseBaseline,
|
|
123
136
|
parseColour: () => parseColour,
|
|
137
|
+
parseCraftConfig: () => parseCraftConfig,
|
|
124
138
|
parseHex: () => parseHex,
|
|
125
139
|
propose: () => propose,
|
|
126
140
|
protectedFacts: () => protectedFacts,
|
|
@@ -131,6 +145,7 @@ __export(index_exports, {
|
|
|
131
145
|
scanSource: () => scanSource,
|
|
132
146
|
sectionRhythm: () => sectionRhythm,
|
|
133
147
|
semantic: () => semantic,
|
|
148
|
+
severityExceptions: () => severityExceptions,
|
|
134
149
|
shapeName: () => shapeName,
|
|
135
150
|
sharedParts: () => sharedParts,
|
|
136
151
|
shouldAnimate: () => shouldAnimate,
|
|
@@ -139,6 +154,8 @@ __export(index_exports, {
|
|
|
139
154
|
tailwindV4Theme: () => tailwindV4Theme,
|
|
140
155
|
tellById: () => tellById,
|
|
141
156
|
toGamut: () => toGamut,
|
|
157
|
+
toJson: () => toJson,
|
|
158
|
+
toSarif: () => toSarif,
|
|
142
159
|
typeFeatureTokens: () => typeFeatureTokens,
|
|
143
160
|
typicality: () => typicality,
|
|
144
161
|
validateDirection: () => validateDirection,
|
|
@@ -1932,10 +1949,14 @@ var COPY_TELLS = [
|
|
|
1932
1949
|
surface: "copy",
|
|
1933
1950
|
why: "Three fragments in a row ('Fast. Friendly. Local.' or 'No fuss. No jargon. Just results.') is the second wave's favourite rhythm.",
|
|
1934
1951
|
fix: "Write one sentence that says which of the three is true, and how you know.",
|
|
1935
|
-
|
|
1952
|
+
// The fragments share one paragraph: "You don't. Again.", a blank line, then "It's frustrating." is two beats, not three.
|
|
1953
|
+
detect: phrases([/(?:\b[A-Z][\w'’-]*(?:[ \t]+[\w'’-]+){0,2}[.!](?:[ \t]+|[ \t]*\n(?![ \t]*\n)[ \t]*)){2}[A-Z][\w'’-]*(?:[ \t]+[\w'’-]+){0,2}[.!](?=\s|$)/], quoted),
|
|
1936
1954
|
fixtures: {
|
|
1937
|
-
flag: [f("content/home.md", "No fuss. No jargon. Just results.")],
|
|
1938
|
-
pass: [
|
|
1955
|
+
flag: [f("content/home.md", "No fuss. No jargon. Just results."), f("content/home.md", "No fuss.\nNo jargon.\nJust results.")],
|
|
1956
|
+
pass: [
|
|
1957
|
+
f("content/home.md", "We fix boilers the same day, and we tell you the price before we start."),
|
|
1958
|
+
f("content/guide.md", "Your competitor appears in the top three. You don't. Again.\n\nIt's frustrating.")
|
|
1959
|
+
]
|
|
1939
1960
|
}
|
|
1940
1961
|
},
|
|
1941
1962
|
{
|
|
@@ -1954,6 +1975,14 @@ var COPY_TELLS = [
|
|
|
1954
1975
|
}
|
|
1955
1976
|
];
|
|
1956
1977
|
var ING_TAIL = /,\s+(?:ensuring|highlighting|underscoring|showcasing|reflecting|demonstrating|emphasi[sz]ing|fostering|cementing|solidifying|reinforcing|symboli[sz]ing|signalling|signaling)\b[^.!?\n]{0,80}/i;
|
|
1978
|
+
var PROMPT_CONTEXT = [
|
|
1979
|
+
/\b(?:the|this|that)\s+(?:attached|uploaded|provided)\s+(?:(?:Perplexity|ChatGPT|Claude|Gemini|Copilot)\s+)?(?:research|research file|research pack|source file|sources)\b/i,
|
|
1980
|
+
/\b(?:attached|uploaded)\s+(?:Perplexity|ChatGPT|Claude|Gemini|Copilot)\b/i,
|
|
1981
|
+
/\bthe\s+(?:attached|uploaded|provided)\s+brief\s+(?:asks|says|wants|requests|suggests|mentions)\b/i
|
|
1982
|
+
];
|
|
1983
|
+
function gerundList(block, _match, index) {
|
|
1984
|
+
return /(?:^|[(,;:]\s*)\w+ing\b[^,.;()!?]{0,40}$/.test(block.text.slice(Math.max(0, index - 60), index));
|
|
1985
|
+
}
|
|
1957
1986
|
var VAGUE_ATTRIBUTION = [
|
|
1958
1987
|
/\b(?:studies|research|experts|scientists|surveys|statistics|the data)\s+(?:show|shows|suggest|suggests|agree|say|says|confirm|confirms|prove|proves|indicate|indicates)\b/i,
|
|
1959
1988
|
/\b(?:many|most)\s+(?:experts|people|customers|professionals|homeowners)\s+(?:agree|say|believe)\b/i,
|
|
@@ -2039,8 +2068,10 @@ function inlineLabelHits(ctx) {
|
|
|
2039
2068
|
run = [];
|
|
2040
2069
|
};
|
|
2041
2070
|
for (const line of lines) {
|
|
2042
|
-
const m = /^\s*
|
|
2043
|
-
|
|
2071
|
+
const m = /^\s*[-*+]\s+\*\*([^*]{1,40}?):?\*\*:?\s+(\S.*)$/.exec(line);
|
|
2072
|
+
const data = m && /[\d£$€%`]|https?:|^\*\*/.test(m[2]);
|
|
2073
|
+
const named = m && /\S[A-Z]|[./]/.test(m[1]);
|
|
2074
|
+
if (m && !data && !named && m[2].trim().split(/\s+/).length <= 6) run.push(offset);
|
|
2044
2075
|
else flush();
|
|
2045
2076
|
offset += line.length + 1;
|
|
2046
2077
|
}
|
|
@@ -2078,6 +2109,29 @@ var RESEARCH_TELLS = [
|
|
|
2078
2109
|
]
|
|
2079
2110
|
}
|
|
2080
2111
|
},
|
|
2112
|
+
{
|
|
2113
|
+
id: "prompt-context",
|
|
2114
|
+
name: "Prompt context",
|
|
2115
|
+
generation: 1,
|
|
2116
|
+
severity: "warn",
|
|
2117
|
+
surface: "copy",
|
|
2118
|
+
why: "'This article uses the attached Perplexity research file as the primary source', 'the attached research is right to say': the model talking about what it was given. A reader of a web page has no attachment. Found 38 times across five live DD articles in 2026-09, none caught by any other tell.",
|
|
2119
|
+
fix: "Delete the reference to the research or brief. Where it carried a claim, name the real source or cut the claim.",
|
|
2120
|
+
detect: phrases(PROMPT_CONTEXT, quoted),
|
|
2121
|
+
fixtures: {
|
|
2122
|
+
flag: [
|
|
2123
|
+
f("content/guide.md", "This article uses the attached Perplexity research file as the primary source."),
|
|
2124
|
+
f("content/guide.md", "The attached research is right to say these platforms suit early-stage businesses."),
|
|
2125
|
+
f("content/guide.md", "That is exactly how the uploaded research frames the category."),
|
|
2126
|
+
f("content/guide.md", "The attached brief asks for the point that most tradespeople miss.")
|
|
2127
|
+
],
|
|
2128
|
+
pass: [
|
|
2129
|
+
f("content/guide.md", "We research every quote before we send it."),
|
|
2130
|
+
f("app/email.tsx", `export const Invoice = () => <p>Your invoice is attached.</p>;`),
|
|
2131
|
+
f("content/guide.md", "BrightLocal's research shows that reviews drive 20% of local ranking.")
|
|
2132
|
+
]
|
|
2133
|
+
}
|
|
2134
|
+
},
|
|
2081
2135
|
{
|
|
2082
2136
|
id: "placeholder",
|
|
2083
2137
|
name: "Unfilled placeholder",
|
|
@@ -2130,7 +2184,11 @@ var RESEARCH_TELLS = [
|
|
|
2130
2184
|
pass: [
|
|
2131
2185
|
f("content/home.md", "- Pages load in under a second\n- Card details never touch our server\n- Support by phone until 8pm\n"),
|
|
2132
2186
|
f("content/home.md", "- **Speed:** Faster pages\n- **Security:** Safer data\n"),
|
|
2133
|
-
f("content/guide.md", "- **GDC**: The statutory regulator for all dental professionals.\n- **GCC**: The statutory regulator for chiropractors in the UK.\n- **CQC**: The independent regulator of health and social care in England.\n")
|
|
2187
|
+
f("content/guide.md", "- **GDC**: The statutory regulator for all dental professionals.\n- **GCC**: The statutory regulator for chiropractors in the UK.\n- **CQC**: The independent regulator of health and social care in England.\n"),
|
|
2188
|
+
f("content/guide.md", "- **Per page**: \xA3100-\xA3200 per page\n- **Hourly**: \xA350-\xA375/hour\n- **Day rate**: \xA3350-\xA3500\n"),
|
|
2189
|
+
f("content/guide.md", "- **Law Society Find a Solicitor:** For solicitors\n- **AccountingWEB / ICAEW directories:** For accountants\n- **NHS.uk:** For NHS services\n"),
|
|
2190
|
+
f("content/guide.md", "1. **Visit PageSpeed Insights** and paste the address\n2. **Enter their URL** and run it\n3. **Note their scores** for later\n"),
|
|
2191
|
+
f("content/guide.md", "- **Structural problems:** **REBUILD.**\n- **Messaging issues:** **REFRESH.**\n- **Neither:** **LEAVE IT.**\n")
|
|
2134
2192
|
]
|
|
2135
2193
|
}
|
|
2136
2194
|
},
|
|
@@ -2142,7 +2200,7 @@ var RESEARCH_TELLS = [
|
|
|
2142
2200
|
surface: "copy",
|
|
2143
2201
|
why: "'..., ensuring peace of mind', '..., highlighting our commitment': a participle tacked on the end that claims significance and names no mechanism. One of the most common shapes in the Wikipedia guide to AI writing.",
|
|
2144
2202
|
fix: "Cut the tail, or replace it with the mechanism: 'so you can drop the car off before work'.",
|
|
2145
|
-
detect: phrases([ING_TAIL], (m) => quoted(m.replace(/^,\s*/, ""))),
|
|
2203
|
+
detect: phrases([ING_TAIL], (m) => quoted(m.replace(/^,\s*/, "")), void 0, gerundList),
|
|
2146
2204
|
fixtures: {
|
|
2147
2205
|
flag: [
|
|
2148
2206
|
f("content/home.md", "Every engineer is Gas Safe registered, ensuring complete peace of mind."),
|
|
@@ -2150,7 +2208,8 @@ var RESEARCH_TELLS = [
|
|
|
2150
2208
|
],
|
|
2151
2209
|
pass: [
|
|
2152
2210
|
f("content/home.md", "We open at 7am, so you can drop the car off before work."),
|
|
2153
|
-
f("content/home.md", "Engineers arrive by 9, carrying the parts for most boilers.")
|
|
2211
|
+
f("content/home.md", "Engineers arrive by 9, carrying the parts for most boilers."),
|
|
2212
|
+
f("content/guide.md", "Many items (claiming your GBP, ensuring NAP consistency, writing title tags) are straightforward.")
|
|
2154
2213
|
]
|
|
2155
2214
|
}
|
|
2156
2215
|
},
|
|
@@ -2400,6 +2459,7 @@ function repeatHits(ctx) {
|
|
|
2400
2459
|
for (const s of sentences(doc2)) {
|
|
2401
2460
|
const words2 = normal(s.text);
|
|
2402
2461
|
if (words2.length < RUN || !/[.!?]["'’”)]*$/.test(s.text)) continue;
|
|
2462
|
+
if (/^\s*\[\^[\w-]+\]:/.test(s.text)) continue;
|
|
2403
2463
|
const key = words2.join(" ");
|
|
2404
2464
|
const earlier = whole.get(key);
|
|
2405
2465
|
if (earlier) {
|
|
@@ -2597,7 +2657,15 @@ var DENSITY_TELLS = [
|
|
|
2597
2657
|
f2("content/proposal.md", doc("We check every valve before the engineer leaves the house.\n\nMore here.\n\nWe check every valve before the engineer leaves the house.")),
|
|
2598
2658
|
f2("content/proposal.md", doc("We check every valve before the engineer leaves the house.\n\nBy then we check every valve before the engineer leaves the site."))
|
|
2599
2659
|
],
|
|
2600
|
-
pass: [
|
|
2660
|
+
pass: [
|
|
2661
|
+
f2("content/proposal.md", doc("We check every valve before the engineer leaves the house.\n\nThe engineer leaves once the customer has signed the sheet.")),
|
|
2662
|
+
f2(
|
|
2663
|
+
"content/guide.md",
|
|
2664
|
+
doc(
|
|
2665
|
+
"The Independent Healthcare Providers Network Private Patient Insight Report 2024 found that private demand rose.[^1]\n\n[^1]: Independent Healthcare Providers Network, Private Patient Insight Report 2024, published online."
|
|
2666
|
+
)
|
|
2667
|
+
)
|
|
2668
|
+
]
|
|
2601
2669
|
}
|
|
2602
2670
|
},
|
|
2603
2671
|
{
|
|
@@ -3634,6 +3702,9 @@ var HOUSE = {
|
|
|
3634
3702
|
"closing-summary": { tier: "review", label: "closing summary" },
|
|
3635
3703
|
"false-range": { tier: "review", label: "false range" },
|
|
3636
3704
|
"placeholder": { tier: "review", label: "unfilled placeholder" },
|
|
3705
|
+
// Every estate hit so far is real (38 in five DD articles, 2026-09-24), but
|
|
3706
|
+
// a proposal can honestly say "the attached research". Review until measured there.
|
|
3707
|
+
"prompt-context": { tier: "review", label: "prompt context: the model naming its own inputs" },
|
|
3637
3708
|
"question-reveal": { tier: "review", label: "staged reveal" },
|
|
3638
3709
|
"inline-label-list": { tier: "review", label: "bold-label bullets" },
|
|
3639
3710
|
"phrase-density": { tier: "review", label: "density" },
|
|
@@ -4316,7 +4387,7 @@ var RENDERED_PATHS = {
|
|
|
4316
4387
|
};
|
|
4317
4388
|
|
|
4318
4389
|
// src/character/check.ts
|
|
4319
|
-
var CATALOGUE_VERSION = "2026.09.
|
|
4390
|
+
var CATALOGUE_VERSION = "2026.09.8";
|
|
4320
4391
|
var CATALOGUE = [...SOURCE_TELLS, ...COPY_TELLS, ...RESEARCH_TELLS, ...DENSITY_TELLS].map(
|
|
4321
4392
|
(t) => RENDERED_PATHS[t.id] ? { ...t, rendered: RENDERED_PATHS[t.id] } : t
|
|
4322
4393
|
);
|
|
@@ -4581,6 +4652,308 @@ function formatComparison(result, beforePath, afterPath) {
|
|
|
4581
4652
|
return lines.join("\n");
|
|
4582
4653
|
}
|
|
4583
4654
|
|
|
4655
|
+
// src/character/claims.ts
|
|
4656
|
+
var CLAIM_KINDS = /* @__PURE__ */ new Set(["money", "number", "date"]);
|
|
4657
|
+
var PROPER = "[A-Z][\\w&.\u2019'-]*(?:\\s+(?:of|and|&|the|for)?\\s*[A-Z][\\w&.\u2019'-]*)*";
|
|
4658
|
+
var NOT_A_SOURCE = /^(?:We|I|It|This|That|These|Those|They|He|She|You|Our|Your|The|A|An|Each|Every|Most|Many|Some|One|Research|Studies|Experts|Data|Analysis|If|When|So|But|And|Or|In|On|At|From|For|By|As|Since|After|Before|Across|Over|Under|Its|Their|External|Source|UK|US|EU|Sometimes|Public|Recent|Industry|Independent|What|How|Why|Who|Where|Businesses|Customers|Clients|Patients|Consumers|People|Users|Online)$/;
|
|
4659
|
+
var NOUN = "study|survey|report|research|analysis|benchmark|benchmarks|guidelines|docs|documentation|help centre|help center|pricing page|figures|statistics|case study";
|
|
4660
|
+
var OWNED_NOUN = "guide|audit|support|pricing|data|site|website|blog";
|
|
4661
|
+
var VERB = "found|finds|reports?|reported|says|said|states?|stated|estimates?|estimated|recommends?|publishes|published|advertises|advertised|shows|showed|claims";
|
|
4662
|
+
var ATTRIBUTION = [
|
|
4663
|
+
new RegExp(`\\b[Aa]ccording to\\s+(?:the\\s+)?(${PROPER})`, "g"),
|
|
4664
|
+
new RegExp(`\\b(?:${NOUN})\\s+(?:by|from|commissioned by)\\s+(?:the\\s+)?(${PROPER})`, "g"),
|
|
4665
|
+
// "Akamai’s 2017 retail study", "the 2020 Deloitte study", "Bark’s UK guide", "Wix’s own developer guidelines".
|
|
4666
|
+
new RegExp(`\\b(${PROPER})(?:(?:\u2019s|'s)\\s+(?:own\\s+)?(?:\\d{4}\\s+)?(?:[A-Za-z]+\\s+)?(?:${NOUN}|${OWNED_NOUN})|\\s+(?:\\d{4}\\s+)?(?:[a-z]+\\s+)?(?:${NOUN}))\\b`, "g"),
|
|
4667
|
+
// "Google also reported", "Shopify UK currently advertises".
|
|
4668
|
+
new RegExp(`\\b(${PROPER})\\s+(?:also\\s+|now\\s+|currently\\s+|still\\s+)?(?:${VERB})\\b`, "g"),
|
|
4669
|
+
/\((?:[Ss]ources?:\s*|via\s+(?=[A-Z]))([^)]+)\)/g,
|
|
4670
|
+
/^\s*(?:source|sources)\s*:\s*(.+)$/gim
|
|
4671
|
+
];
|
|
4672
|
+
var LINK2 = /\[([^\]]+)\]\((https?:\/\/[^)\s]+)\)|\bhttps?:\/\/[^\s<>"')\]]+/g;
|
|
4673
|
+
function cleanName(raw) {
|
|
4674
|
+
const words2 = raw.trim().replace(/[.,;:]+$/, "").split(/\s+/);
|
|
4675
|
+
while (words2.length && NOT_A_SOURCE.test(words2[0])) words2.shift();
|
|
4676
|
+
return words2.join(" ").replace(/(?:’s|'s)(?=\s|$).*$/, "").trim();
|
|
4677
|
+
}
|
|
4678
|
+
var IMPERATIVE = /^(?:Add|Use|Check|Make|Get|Set|Include|Create|Update|List|Keep|Ask|Write|Track|Test|Claim|Build|Link|Submit|Verify|Review|Fix|Remove|Upload|Respond|Reply|Choose|Pick|Start|Run|Open|Install|Connect|Enable|Turn|Put|Give|Send|Book|Call|Read|See|Try|Compare|Aim|Target|Avoid|Post|Share|Mark|Tag)$/;
|
|
4679
|
+
var atStart = (sentence, index) => /^[\s*_"“”’(>#|-]*(?:\d{1,3}[.)]\s*)?[\s*_]*(?:[\w ]+:\**\s*)?$/.test(sentence.slice(0, index)) || /\|\s*\**$/.test(sentence.slice(0, index));
|
|
4680
|
+
function namedSources(sentence) {
|
|
4681
|
+
const found = /* @__PURE__ */ new Set();
|
|
4682
|
+
ATTRIBUTION.forEach((pattern, i) => {
|
|
4683
|
+
for (const m of sentence.matchAll(pattern)) {
|
|
4684
|
+
const raw = m[1].trim();
|
|
4685
|
+
const word = !/\s/.test(raw) && !/[’']s$/.test(m[0].split(/\s+/)[0]);
|
|
4686
|
+
if (i === 2 && word && atStart(sentence, m.index ?? 0)) continue;
|
|
4687
|
+
if (IMPERATIVE.test(raw.split(/\s+/)[0]) && atStart(sentence, m.index ?? 0)) continue;
|
|
4688
|
+
const name = cleanName(raw);
|
|
4689
|
+
if (!name || name.length < 2 || !/\s/.test(name) && /[a-z]ing$/.test(name)) continue;
|
|
4690
|
+
found.add(name);
|
|
4691
|
+
}
|
|
4692
|
+
});
|
|
4693
|
+
for (const m of sentence.matchAll(LINK2)) found.add(m[2] ?? m[0]);
|
|
4694
|
+
return [...found];
|
|
4695
|
+
}
|
|
4696
|
+
var FOOTNOTE_REF = /\[\^([\w-]+)\](?!:)/g;
|
|
4697
|
+
var FOOTNOTE_DEF = /^[ \t]*\[\^([\w-]+)\]:[ \t]*(.+)$/gm;
|
|
4698
|
+
var ASSUMPTION = /^(?:\*\*)?(?:assume|suppose|imagine|say|let's say|for example, say|picture)\b/i;
|
|
4699
|
+
var LEAD = /^\s*(?:#{1,6}\s+|>\s*|[-*+]\s+|\d+[.)]\s+)*/;
|
|
4700
|
+
function sentences2(text) {
|
|
4701
|
+
const out = [];
|
|
4702
|
+
let start = 0;
|
|
4703
|
+
let paragraph = 0;
|
|
4704
|
+
const push = (end) => {
|
|
4705
|
+
const raw = text.slice(start, end);
|
|
4706
|
+
const lead = raw.length - raw.trimStart().length;
|
|
4707
|
+
if (raw.trim()) out.push({ text: raw.trim(), offset: start + lead, paragraph });
|
|
4708
|
+
};
|
|
4709
|
+
for (const m of text.matchAll(/(?<!(?:^|\n)[ \t]*\d{1,3})[.!?](?:\[\^[\w-]+\])*(?=["”’)]?[ \t]+["“(*]*[A-Z0-9£$€])|\n+/g)) {
|
|
4710
|
+
const end = (m.index ?? 0) + m[0].length;
|
|
4711
|
+
push(end);
|
|
4712
|
+
start = end;
|
|
4713
|
+
if (/\n\s*\n/.test(m[0]) || /^\s*(?:#|\|)/.test(text.slice(end))) paragraph += 1;
|
|
4714
|
+
}
|
|
4715
|
+
push(text.length);
|
|
4716
|
+
return out;
|
|
4717
|
+
}
|
|
4718
|
+
var MAX = 180;
|
|
4719
|
+
var trim = (s) => s.length > MAX ? `${s.slice(0, MAX - 1).trimEnd()}\u2026` : s;
|
|
4720
|
+
function findClaims(files) {
|
|
4721
|
+
const claims = [];
|
|
4722
|
+
for (const file of files) {
|
|
4723
|
+
for (const block of extractCopy(file)) {
|
|
4724
|
+
const notes = new Map([...block.text.matchAll(FOOTNOTE_DEF)].map((m) => [m[1], m[2].trim()]));
|
|
4725
|
+
let carried;
|
|
4726
|
+
for (const s of sentences2(block.text)) {
|
|
4727
|
+
if (/^\s*#{1,6}\s/.test(s.text) || /^\s*\[\^[\w-]+\]:/.test(s.text)) continue;
|
|
4728
|
+
const refs = [...s.text.matchAll(FOOTNOTE_REF)].map((m) => notes.get(m[1]) ?? `footnote ${m[1]}`);
|
|
4729
|
+
const text = s.text.replace(FOOTNOTE_REF, "");
|
|
4730
|
+
const body = text.replace(LEAD, "");
|
|
4731
|
+
const own = [...namedSources(text), ...refs];
|
|
4732
|
+
if (own.length) carried = { paragraph: s.paragraph, sources: own };
|
|
4733
|
+
if (ASSUMPTION.test(body)) continue;
|
|
4734
|
+
const facts = protectedFacts(body).filter((f4) => CLAIM_KINDS.has(f4.kind));
|
|
4735
|
+
if (facts.length === 0 && own.length === 0) continue;
|
|
4736
|
+
const nearby = own.length === 0 && carried?.paragraph === s.paragraph ? carried.sources : void 0;
|
|
4737
|
+
const at = block.offset + s.offset;
|
|
4738
|
+
claims.push({
|
|
4739
|
+
path: file.path,
|
|
4740
|
+
line: file.text.slice(0, at).split("\n").length,
|
|
4741
|
+
sentence: trim(text.replace(/\s+/g, " ")),
|
|
4742
|
+
facts,
|
|
4743
|
+
sources: own,
|
|
4744
|
+
...nearby ? { nearby } : {}
|
|
4745
|
+
});
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
return { files: files.length, claims, unsourced: claims.filter((c) => c.sources.length === 0).length };
|
|
4750
|
+
}
|
|
4751
|
+
function formatClaims(report2, label = "craft copy claims") {
|
|
4752
|
+
const { claims, unsourced } = report2;
|
|
4753
|
+
if (claims.length === 0) return `${label}: no prices, figures, dates or named sources in ${report2.files} file${report2.files === 1 ? "" : "s"}.`;
|
|
4754
|
+
const lines = [
|
|
4755
|
+
`${label}: ${claims.length} claim${claims.length === 1 ? "" : "s"} to check, ${unsourced} with no source named.`,
|
|
4756
|
+
" Check each against its primary source before it ships. Sourced means a source is named, not that it agrees."
|
|
4757
|
+
];
|
|
4758
|
+
for (const c of claims) {
|
|
4759
|
+
const what = [
|
|
4760
|
+
...c.facts.map((f4) => f4.value),
|
|
4761
|
+
...c.sources.map((s) => `source: ${s}`),
|
|
4762
|
+
...c.nearby ? [`${c.nearby.join(", ")} named earlier in the paragraph: does it cover this?`] : []
|
|
4763
|
+
].join(" \xB7 ");
|
|
4764
|
+
lines.push("", ` ${c.path}:${c.line} ${c.sources.length ? "sourced " : "UNSOURCED"} ${what}`, ` ${c.sentence}`);
|
|
4765
|
+
}
|
|
4766
|
+
return lines.join("\n");
|
|
4767
|
+
}
|
|
4768
|
+
|
|
4769
|
+
// src/character/baseline.ts
|
|
4770
|
+
var BASELINE_VERSION = 1;
|
|
4771
|
+
function fnv1a(text) {
|
|
4772
|
+
let hash = 2166136261;
|
|
4773
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
4774
|
+
hash ^= text.charCodeAt(i);
|
|
4775
|
+
hash = Math.imul(hash, 16777619);
|
|
4776
|
+
}
|
|
4777
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
4778
|
+
}
|
|
4779
|
+
var excerptHash = (f4) => fnv1a(f4.excerpt.replace(/\s+/g, " ").trim());
|
|
4780
|
+
var keyOf = (tell, path, excerpt) => `${tell}\0${path}\0${excerpt}`;
|
|
4781
|
+
function findingKey(f4) {
|
|
4782
|
+
return keyOf(f4.tell, f4.path, excerptHash(f4));
|
|
4783
|
+
}
|
|
4784
|
+
function createBaseline(report2) {
|
|
4785
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4786
|
+
for (const f4 of report2.findings) {
|
|
4787
|
+
const excerpt = excerptHash(f4);
|
|
4788
|
+
const key = keyOf(f4.tell, f4.path, excerpt);
|
|
4789
|
+
const entry = counts.get(key);
|
|
4790
|
+
if (entry) entry.count += 1;
|
|
4791
|
+
else counts.set(key, { tell: f4.tell, path: f4.path, excerpt, count: 1 });
|
|
4792
|
+
}
|
|
4793
|
+
const entries = [...counts.values()].sort((a, b) => a.path.localeCompare(b.path) || a.tell.localeCompare(b.tell) || a.excerpt.localeCompare(b.excerpt));
|
|
4794
|
+
return { version: BASELINE_VERSION, catalogueVersion: report2.catalogueVersion, entries };
|
|
4795
|
+
}
|
|
4796
|
+
function parseBaseline(data, source = "baseline") {
|
|
4797
|
+
const b = data;
|
|
4798
|
+
if (!b || typeof b !== "object" || b.version !== BASELINE_VERSION || !Array.isArray(b.entries)) {
|
|
4799
|
+
throw new Error(`${source}: not a craft baseline (version ${BASELINE_VERSION})`);
|
|
4800
|
+
}
|
|
4801
|
+
for (const e of b.entries) {
|
|
4802
|
+
if (typeof e?.tell !== "string" || typeof e.path !== "string" || typeof e.excerpt !== "string" || !Number.isInteger(e.count) || e.count < 1) {
|
|
4803
|
+
throw new Error(`${source}: malformed entry ${JSON.stringify(e)}`);
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4806
|
+
return b;
|
|
4807
|
+
}
|
|
4808
|
+
function recount(report2, findings) {
|
|
4809
|
+
const byGeneration = { 1: 0, 2: 0, 3: 0 };
|
|
4810
|
+
const byTell = {};
|
|
4811
|
+
for (const f4 of findings) {
|
|
4812
|
+
byGeneration[f4.generation] += 1;
|
|
4813
|
+
byTell[f4.tell] = (byTell[f4.tell] ?? 0) + 1;
|
|
4814
|
+
}
|
|
4815
|
+
return {
|
|
4816
|
+
...report2,
|
|
4817
|
+
findings,
|
|
4818
|
+
summary: { ...report2.summary, findings: findings.length, byGeneration, byTell, blocking: findings.filter((f4) => f4.severity === "block").length }
|
|
4819
|
+
};
|
|
4820
|
+
}
|
|
4821
|
+
function applyBaseline(report2, baseline) {
|
|
4822
|
+
const remaining = /* @__PURE__ */ new Map();
|
|
4823
|
+
for (const e of baseline.entries) {
|
|
4824
|
+
const key = keyOf(e.tell, e.path, e.excerpt);
|
|
4825
|
+
remaining.set(key, (remaining.get(key) ?? 0) + e.count);
|
|
4826
|
+
}
|
|
4827
|
+
const kept = [];
|
|
4828
|
+
let baselined = 0;
|
|
4829
|
+
for (const f4 of report2.findings) {
|
|
4830
|
+
const key = findingKey(f4);
|
|
4831
|
+
const left = remaining.get(key) ?? 0;
|
|
4832
|
+
if (left > 0) {
|
|
4833
|
+
remaining.set(key, left - 1);
|
|
4834
|
+
baselined += 1;
|
|
4835
|
+
} else kept.push(f4);
|
|
4836
|
+
}
|
|
4837
|
+
return { ...recount(report2, kept), baselined };
|
|
4838
|
+
}
|
|
4839
|
+
|
|
4840
|
+
// src/character/config.ts
|
|
4841
|
+
var DEFAULT_IGNORE = [".claude", ".agents", ".cursor"];
|
|
4842
|
+
var KEYS = /* @__PURE__ */ new Set(["$schema", "ignore", "copyPaths", "severity"]);
|
|
4843
|
+
var LEVELS = /* @__PURE__ */ new Set(["warn", "block", "off"]);
|
|
4844
|
+
var MIN_BECAUSE = 12;
|
|
4845
|
+
var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
4846
|
+
var isStringArray = (v) => Array.isArray(v) && v.every((s) => typeof s === "string");
|
|
4847
|
+
function parseCraftConfig(data, knownTells, source = "craft.config.json") {
|
|
4848
|
+
if (!isRecord(data)) throw new Error(`${source}: expected an object`);
|
|
4849
|
+
for (const key of Object.keys(data)) if (!KEYS.has(key)) throw new Error(`${source}: unknown key "${key}"`);
|
|
4850
|
+
const ignore = data.ignore ?? [];
|
|
4851
|
+
if (!isStringArray(ignore)) throw new Error(`${source}: "ignore" must be an array of glob strings`);
|
|
4852
|
+
if (data.copyPaths !== void 0 && !isStringArray(data.copyPaths)) throw new Error(`${source}: "copyPaths" must be an array of paths`);
|
|
4853
|
+
const severity = {};
|
|
4854
|
+
const raw = data.severity ?? {};
|
|
4855
|
+
if (!isRecord(raw)) throw new Error(`${source}: "severity" must map a tell id to { level, because }`);
|
|
4856
|
+
for (const [tell, value] of Object.entries(raw)) {
|
|
4857
|
+
if (!knownTells.has(tell)) throw new Error(`${source}: severity names no tell called "${tell}"`);
|
|
4858
|
+
if (!isRecord(value) || !LEVELS.has(value.level)) {
|
|
4859
|
+
throw new Error(`${source}: severity.${tell} needs a level of "warn", "block" or "off"`);
|
|
4860
|
+
}
|
|
4861
|
+
if (typeof value.because !== "string" || value.because.trim().length < MIN_BECAUSE) {
|
|
4862
|
+
throw new Error(`${source}: severity.${tell} needs a because of at least a sentence`);
|
|
4863
|
+
}
|
|
4864
|
+
severity[tell] = { level: value.level, because: value.because };
|
|
4865
|
+
}
|
|
4866
|
+
return { ignore, severity, ...data.copyPaths ? { copyPaths: data.copyPaths } : {} };
|
|
4867
|
+
}
|
|
4868
|
+
function globToRegExp(glob) {
|
|
4869
|
+
const pattern = glob.replace(/^\.\//, "").replace(/\/$/, "").replace(/\/\*\*$/, "");
|
|
4870
|
+
let body = "";
|
|
4871
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
4872
|
+
const c = pattern[i];
|
|
4873
|
+
if (c === "*" && pattern[i + 1] === "*") {
|
|
4874
|
+
const slash = pattern[i + 2] === "/";
|
|
4875
|
+
body += slash ? "(?:.*/)?" : ".*";
|
|
4876
|
+
i += slash ? 2 : 1;
|
|
4877
|
+
} else if (c === "*") body += "[^/]*";
|
|
4878
|
+
else if (c === "?") body += "[^/]";
|
|
4879
|
+
else body += c.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
4880
|
+
}
|
|
4881
|
+
const anywhere = !pattern.includes("/");
|
|
4882
|
+
return new RegExp(`^${anywhere ? "(?:.*/)?" : ""}${body}(?:/.*)?$`);
|
|
4883
|
+
}
|
|
4884
|
+
function ignoreMatcher(patterns) {
|
|
4885
|
+
const res = patterns.map(globToRegExp);
|
|
4886
|
+
return (path) => {
|
|
4887
|
+
const p = path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
4888
|
+
return res.some((re) => re.test(p));
|
|
4889
|
+
};
|
|
4890
|
+
}
|
|
4891
|
+
function severityExceptions(config) {
|
|
4892
|
+
return Object.entries(config.severity).filter(([, o]) => o.level === "off").map(([tell, o]) => ({ tell, because: `craft.config.json: ${o.because}` }));
|
|
4893
|
+
}
|
|
4894
|
+
function applySeverity(report2, config) {
|
|
4895
|
+
const findings = report2.findings.map((f4) => {
|
|
4896
|
+
const o = config.severity[f4.tell];
|
|
4897
|
+
return o && o.level !== "off" ? { ...f4, severity: o.level } : f4;
|
|
4898
|
+
});
|
|
4899
|
+
return { ...report2, findings, summary: { ...report2.summary, blocking: findings.filter((f4) => f4.severity === "block").length } };
|
|
4900
|
+
}
|
|
4901
|
+
|
|
4902
|
+
// src/character/sarif.ts
|
|
4903
|
+
var isUrl = (path) => /^[a-z][a-z0-9+.-]*:\/\//i.test(path);
|
|
4904
|
+
function toSarif(report2, options) {
|
|
4905
|
+
const byId = new Map(options.tells.map((t) => [t.id, t]));
|
|
4906
|
+
const ids = [...new Set(report2.findings.map((f4) => f4.tell))].sort();
|
|
4907
|
+
const index = new Map(ids.map((id, i) => [id, i]));
|
|
4908
|
+
const rules = ids.map((id) => {
|
|
4909
|
+
const t = byId.get(id);
|
|
4910
|
+
return {
|
|
4911
|
+
id,
|
|
4912
|
+
name: t?.name ?? id,
|
|
4913
|
+
shortDescription: { text: t?.name ?? id },
|
|
4914
|
+
...t ? { fullDescription: { text: t.why }, help: { text: t.fix } } : {}
|
|
4915
|
+
};
|
|
4916
|
+
});
|
|
4917
|
+
const results = report2.findings.map((f4) => ({
|
|
4918
|
+
ruleId: f4.tell,
|
|
4919
|
+
ruleIndex: index.get(f4.tell),
|
|
4920
|
+
level: f4.severity === "block" ? "error" : "warning",
|
|
4921
|
+
message: { text: `${f4.message}. ${f4.fix}` },
|
|
4922
|
+
locations: [
|
|
4923
|
+
{
|
|
4924
|
+
physicalLocation: {
|
|
4925
|
+
artifactLocation: { uri: isUrl(f4.path) ? f4.path : f4.path.replace(/\\/g, "/") },
|
|
4926
|
+
...f4.line > 0 ? { region: { startLine: f4.line, snippet: { text: f4.excerpt } } } : {}
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
],
|
|
4930
|
+
partialFingerprints: { "craftFinding/v1": fnv1a(findingKey(f4)) }
|
|
4931
|
+
}));
|
|
4932
|
+
return {
|
|
4933
|
+
$schema: "https://json.schemastore.org/sarif-2.1.0.json",
|
|
4934
|
+
version: "2.1.0",
|
|
4935
|
+
runs: [
|
|
4936
|
+
{
|
|
4937
|
+
tool: {
|
|
4938
|
+
driver: {
|
|
4939
|
+
name: "craft",
|
|
4940
|
+
version: report2.catalogueVersion,
|
|
4941
|
+
informationUri: options.informationUri ?? "https://www.npmjs.com/package/@domandigital/craft",
|
|
4942
|
+
rules
|
|
4943
|
+
}
|
|
4944
|
+
},
|
|
4945
|
+
results
|
|
4946
|
+
}
|
|
4947
|
+
]
|
|
4948
|
+
};
|
|
4949
|
+
}
|
|
4950
|
+
|
|
4951
|
+
// src/character/json.ts
|
|
4952
|
+
var JSON_SCHEMA_VERSION = 1;
|
|
4953
|
+
function toJson(data) {
|
|
4954
|
+
return JSON.stringify({ schemaVersion: JSON_SCHEMA_VERSION, ...data }, null, 2);
|
|
4955
|
+
}
|
|
4956
|
+
|
|
4584
4957
|
// src/fingerprint/index.ts
|
|
4585
4958
|
var FINGERPRINT_VERSION = 1;
|
|
4586
4959
|
var CHROMATIC = 0.03;
|
|
@@ -5476,10 +5849,12 @@ function retrofitPlan(report2, direction) {
|
|
|
5476
5849
|
AI_PHRASES,
|
|
5477
5850
|
AI_VIOLET,
|
|
5478
5851
|
AI_WORDS,
|
|
5852
|
+
BASELINE_VERSION,
|
|
5479
5853
|
BUZZWORDS,
|
|
5480
5854
|
CATALOGUE,
|
|
5481
5855
|
CATALOGUE_VERSION,
|
|
5482
5856
|
CHOICE_KEYS,
|
|
5857
|
+
DEFAULT_IGNORE,
|
|
5483
5858
|
DENSITIES,
|
|
5484
5859
|
DENSITY_NAMES,
|
|
5485
5860
|
DIRECTION_VERSION,
|
|
@@ -5494,6 +5869,7 @@ function retrofitPlan(report2, direction) {
|
|
|
5494
5869
|
HOUSE,
|
|
5495
5870
|
HOUSE_BUDGET,
|
|
5496
5871
|
HOUSE_TYPE,
|
|
5872
|
+
JSON_SCHEMA_VERSION,
|
|
5497
5873
|
LIGHTNESS_CURVE,
|
|
5498
5874
|
MIN_DECIDED,
|
|
5499
5875
|
MIN_RUNS,
|
|
@@ -5524,7 +5900,9 @@ function retrofitPlan(report2, direction) {
|
|
|
5524
5900
|
accentFork,
|
|
5525
5901
|
addSite,
|
|
5526
5902
|
apcaContrast,
|
|
5903
|
+
applyBaseline,
|
|
5527
5904
|
applyHouseGate,
|
|
5905
|
+
applySeverity,
|
|
5528
5906
|
auditSnapshot,
|
|
5529
5907
|
catalogueTable,
|
|
5530
5908
|
characterReport,
|
|
@@ -5535,6 +5913,7 @@ function retrofitPlan(report2, direction) {
|
|
|
5535
5913
|
compareFacts,
|
|
5536
5914
|
compareToEstate,
|
|
5537
5915
|
craftTokens,
|
|
5916
|
+
createBaseline,
|
|
5538
5917
|
deltaEOk,
|
|
5539
5918
|
deltaEOkHex,
|
|
5540
5919
|
densityCss,
|
|
@@ -5544,22 +5923,27 @@ function retrofitPlan(report2, direction) {
|
|
|
5544
5923
|
estatePairs,
|
|
5545
5924
|
exitDuration,
|
|
5546
5925
|
extractHtml,
|
|
5926
|
+
findClaims,
|
|
5547
5927
|
findColours,
|
|
5928
|
+
findingKey,
|
|
5548
5929
|
fingerprint,
|
|
5549
5930
|
fingerprintDistance,
|
|
5550
5931
|
fluidClamp,
|
|
5551
5932
|
fluidSpace,
|
|
5552
5933
|
fluidType,
|
|
5553
5934
|
fontClass,
|
|
5935
|
+
formatClaims,
|
|
5554
5936
|
formatComparison,
|
|
5555
5937
|
formatHex,
|
|
5556
5938
|
formatReport,
|
|
5939
|
+
globToRegExp,
|
|
5557
5940
|
groundName,
|
|
5558
5941
|
harvest,
|
|
5559
5942
|
hexToOklch,
|
|
5560
5943
|
houseRule,
|
|
5561
5944
|
hueName,
|
|
5562
5945
|
hueSwatch,
|
|
5946
|
+
ignoreMatcher,
|
|
5563
5947
|
inP3Gamut,
|
|
5564
5948
|
inSrgbGamut,
|
|
5565
5949
|
initDirection,
|
|
@@ -5567,13 +5951,16 @@ function retrofitPlan(report2, direction) {
|
|
|
5567
5951
|
isCream,
|
|
5568
5952
|
makeSnapshot,
|
|
5569
5953
|
motionTokens,
|
|
5954
|
+
namedSources,
|
|
5570
5955
|
nearest,
|
|
5571
5956
|
normaliseFamily,
|
|
5572
5957
|
nullPrompt,
|
|
5573
5958
|
oklchToHex,
|
|
5574
5959
|
oklchToRgb,
|
|
5575
5960
|
paletteFromPixels,
|
|
5961
|
+
parseBaseline,
|
|
5576
5962
|
parseColour,
|
|
5963
|
+
parseCraftConfig,
|
|
5577
5964
|
parseHex,
|
|
5578
5965
|
propose,
|
|
5579
5966
|
protectedFacts,
|
|
@@ -5584,6 +5971,7 @@ function retrofitPlan(report2, direction) {
|
|
|
5584
5971
|
scanSource,
|
|
5585
5972
|
sectionRhythm,
|
|
5586
5973
|
semantic,
|
|
5974
|
+
severityExceptions,
|
|
5587
5975
|
shapeName,
|
|
5588
5976
|
sharedParts,
|
|
5589
5977
|
shouldAnimate,
|
|
@@ -5592,6 +5980,8 @@ function retrofitPlan(report2, direction) {
|
|
|
5592
5980
|
tailwindV4Theme,
|
|
5593
5981
|
tellById,
|
|
5594
5982
|
toGamut,
|
|
5983
|
+
toJson,
|
|
5984
|
+
toSarif,
|
|
5595
5985
|
typeFeatureTokens,
|
|
5596
5986
|
typicality,
|
|
5597
5987
|
validateDirection,
|