@dreamdata_io/verify-tracking 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +756 -0
- package/dist/ai/checker.js +222 -0
- package/dist/ai/checker.js.map +1 -0
- package/dist/ai/checklist.js +190 -0
- package/dist/ai/checklist.js.map +1 -0
- package/dist/ai/cli-presets.js +27 -0
- package/dist/ai/cli-presets.js.map +1 -0
- package/dist/ai/evidence-view.js +143 -0
- package/dist/ai/evidence-view.js.map +1 -0
- package/dist/ai/local-cli.js +58 -0
- package/dist/ai/local-cli.js.map +1 -0
- package/dist/ai/openai-compatible.js +78 -0
- package/dist/ai/openai-compatible.js.map +1 -0
- package/dist/ai/response-parser.js +105 -0
- package/dist/ai/response-parser.js.map +1 -0
- package/dist/ai/types.js +2 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/analysis/consent-mode.js +225 -0
- package/dist/analysis/consent-mode.js.map +1 -0
- package/dist/analysis/deployment.js +2658 -0
- package/dist/analysis/deployment.js.map +1 -0
- package/dist/analysis/diagnosis/copy.en.js +303 -0
- package/dist/analysis/diagnosis/copy.en.js.map +1 -0
- package/dist/analysis/diagnosis/diagnose.js +172 -0
- package/dist/analysis/diagnosis/diagnose.js.map +1 -0
- package/dist/analysis/diagnosis/docs.js +118 -0
- package/dist/analysis/diagnosis/docs.js.map +1 -0
- package/dist/analysis/diagnosis/index.js +5 -0
- package/dist/analysis/diagnosis/index.js.map +1 -0
- package/dist/analysis/diagnosis/rules.js +656 -0
- package/dist/analysis/diagnosis/rules.js.map +1 -0
- package/dist/analysis/diagnosis/types.js +2 -0
- package/dist/analysis/diagnosis/types.js.map +1 -0
- package/dist/cli.js +344 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/env.js +100 -0
- package/dist/config/env.js.map +1 -0
- package/dist/config/preflight.js +167 -0
- package/dist/config/preflight.js.map +1 -0
- package/dist/config/user-config.js +79 -0
- package/dist/config/user-config.js.map +1 -0
- package/dist/evidence/collect.js +527 -0
- package/dist/evidence/collect.js.map +1 -0
- package/dist/evidence/consent-accept.js +377 -0
- package/dist/evidence/consent-accept.js.map +1 -0
- package/dist/evidence/consent.js +340 -0
- package/dist/evidence/consent.js.map +1 -0
- package/dist/evidence/constants.js +615 -0
- package/dist/evidence/constants.js.map +1 -0
- package/dist/evidence/globals.js +132 -0
- package/dist/evidence/globals.js.map +1 -0
- package/dist/evidence/gtm-container.js +432 -0
- package/dist/evidence/gtm-container.js.map +1 -0
- package/dist/evidence/heuristic-banner.js +107 -0
- package/dist/evidence/heuristic-banner.js.map +1 -0
- package/dist/evidence/http-probe.js +139 -0
- package/dist/evidence/http-probe.js.map +1 -0
- package/dist/evidence/init-script.js +112 -0
- package/dist/evidence/init-script.js.map +1 -0
- package/dist/evidence/network.js +365 -0
- package/dist/evidence/network.js.map +1 -0
- package/dist/evidence/preference-center.js +368 -0
- package/dist/evidence/preference-center.js.map +1 -0
- package/dist/evidence/script.js +425 -0
- package/dist/evidence/script.js.map +1 -0
- package/dist/evidence/second-page.js +332 -0
- package/dist/evidence/second-page.js.map +1 -0
- package/dist/evidence/selector-probe.js +53 -0
- package/dist/evidence/selector-probe.js.map +1 -0
- package/dist/evidence/stealth.js +21 -0
- package/dist/evidence/stealth.js.map +1 -0
- package/dist/evidence/types.js +14 -0
- package/dist/evidence/types.js.map +1 -0
- package/dist/interactive/prompt.js +31 -0
- package/dist/interactive/prompt.js.map +1 -0
- package/dist/mcp/server.js +308 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/summary.js +41 -0
- package/dist/mcp/summary.js.map +1 -0
- package/dist/report/context.js +184 -0
- package/dist/report/context.js.map +1 -0
- package/dist/report/projection.js +125 -0
- package/dist/report/projection.js.map +1 -0
- package/dist/report/quote-check.js +90 -0
- package/dist/report/quote-check.js.map +1 -0
- package/dist/report/render.js +178 -0
- package/dist/report/render.js.map +1 -0
- package/dist/report/serializers.js +124 -0
- package/dist/report/serializers.js.map +1 -0
- package/dist/report/store.js +139 -0
- package/dist/report/store.js.map +1 -0
- package/dist/run/verify.js +77 -0
- package/dist/run/verify.js.map +1 -0
- package/dist/utils/duration.js +10 -0
- package/dist/utils/duration.js.map +1 -0
- package/dist/utils/errors.js +17 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/logger.js +59 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/runTimingsLog.js +27 -0
- package/dist/utils/runTimingsLog.js.map +1 -0
- package/dist/utils/slug.js +27 -0
- package/dist/utils/slug.js.map +1 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/package.json +57 -0
- package/scripts/install.sh +314 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { EN_CAUSE_COPY } from "./copy.en.js";
|
|
2
|
+
import { CMP_VENDORS_IN_DOCS, docTitle, docUrl } from "./docs.js";
|
|
3
|
+
import { CAUSE_RULES } from "./rules.js";
|
|
4
|
+
/**
|
|
5
|
+
* Ranking order. "not-a-verdict" is first because it pre-empts rather than
|
|
6
|
+
* outranks — nothing else is reported at all once one of those fires.
|
|
7
|
+
*/
|
|
8
|
+
const KIND_RANK = {
|
|
9
|
+
"not-a-verdict": 0,
|
|
10
|
+
blocking: 1,
|
|
11
|
+
leaking: 2,
|
|
12
|
+
"duplicate-counting": 3,
|
|
13
|
+
hardening: 4,
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Three is a reader's limit, not an evidence limit. Across the 25-report
|
|
17
|
+
* corpus the cap never actually binds (the worst sites resolve to three), so
|
|
18
|
+
* it is a safety net rather than the mechanism — and anything it does trim is
|
|
19
|
+
* still named in `alsoFired`, so a count stays complete.
|
|
20
|
+
*/
|
|
21
|
+
const MAX_CAUSES = 3;
|
|
22
|
+
/**
|
|
23
|
+
* Checks the diagnosis layer does not speak for at all.
|
|
24
|
+
*
|
|
25
|
+
* console-clean is the only one. Its warn says the install printed a
|
|
26
|
+
* Dreamdata message to the console — which turned out to be a false positive
|
|
27
|
+
* as a *finding*: blackline.com's "Plugin loaded - YOU SHOULD SEE THIS IN
|
|
28
|
+
* PRODUCTION" and qa.com's third-party destination note both ran clean
|
|
29
|
+
* otherwise, and neither is something to tell a customer about. It had a
|
|
30
|
+
* "hardening" cause of its own, and that cause was the whole of the headline
|
|
31
|
+
* on runs where nothing else was wrong — "Nothing is broken, one thing to
|
|
32
|
+
* harden" over a line of text no visitor sees.
|
|
33
|
+
*
|
|
34
|
+
* So the check stays exactly as it is in the per-check list, warn and all,
|
|
35
|
+
* for whoever is actually debugging an install. It just never enters the
|
|
36
|
+
* ledger: no cause may trigger on it, and it can never land in
|
|
37
|
+
* `unexplainedChecks` either, which is the other way a check reaches the
|
|
38
|
+
* summary. A run whose only unhealthy check is this one diagnoses as clean.
|
|
39
|
+
*/
|
|
40
|
+
const NOT_DIAGNOSED = new Set(["console-clean"]);
|
|
41
|
+
/** A check that is "fail" or "warn" is claimable; nothing else is. */
|
|
42
|
+
function isUnhealthy(status) {
|
|
43
|
+
return status === "fail" || status === "warn";
|
|
44
|
+
}
|
|
45
|
+
function buildFacts(analysis, extras) {
|
|
46
|
+
const byId = new Map(analysis.checks.map((check) => [check.id, check]));
|
|
47
|
+
const byPhase = new Map(analysis.matrix.map((phase) => [phase.phase, phase]));
|
|
48
|
+
const vendor = analysis.cmpVendor;
|
|
49
|
+
return {
|
|
50
|
+
analysis,
|
|
51
|
+
check: (id) => byId.get(id),
|
|
52
|
+
statusOf: (id) => byId.get(id)?.status ?? "absent",
|
|
53
|
+
// A check's own `phases` field already means "the phases this status is
|
|
54
|
+
// about" — for a failure, only the ones that actually failed. Re-deriving
|
|
55
|
+
// that here is how a cause ends up attributing a one-phase failure to
|
|
56
|
+
// three phases.
|
|
57
|
+
failingPhases: (id) => byId.get(id)?.phases ?? [],
|
|
58
|
+
phase: (name) => byPhase.get(name),
|
|
59
|
+
observed: analysis.matrix,
|
|
60
|
+
unhealthy: analysis.checks
|
|
61
|
+
.filter((check) => isUnhealthy(check.status) && !NOT_DIAGNOSED.has(check.id))
|
|
62
|
+
.map((check) => check.id),
|
|
63
|
+
duplicates: extras.duplicates,
|
|
64
|
+
vars: {
|
|
65
|
+
cmpVendor: vendor,
|
|
66
|
+
cmpInDocs: vendor !== null && CMP_VENDORS_IN_DOCS.has(vendor),
|
|
67
|
+
installMethod: analysis.install.method,
|
|
68
|
+
phases: analysis.phasesObserved,
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Only a "hardening" cause may be triggered by a "warn".
|
|
74
|
+
*
|
|
75
|
+
* A warn means the configuration is wrong AND this run proved something else
|
|
76
|
+
* held the line — nothing actually leaked (see CrossPhaseCheck). So a warn
|
|
77
|
+
* must never fire a blocking or leaking cause: sciex_com's Consent Mode
|
|
78
|
+
* defaults to granted and only a GTM blocking trigger keeps identified
|
|
79
|
+
* tracking off an unanswered page, which is worth reporting as a single point
|
|
80
|
+
* of failure and is emphatically NOT "this site tracks people who refused".
|
|
81
|
+
* Without this split, `consent-default-not-denied` matched that shape and
|
|
82
|
+
* reported a healthy site as leaking.
|
|
83
|
+
*
|
|
84
|
+
* A warn is still claimable: a cause that legitimately accounts for one may
|
|
85
|
+
* name it in `claims`. This governs triggering only.
|
|
86
|
+
*/
|
|
87
|
+
function triggerStatusHolds(rule, facts) {
|
|
88
|
+
// An empty trigger belongs to a not-a-verdict rule, which gates on
|
|
89
|
+
// pageReadability/shape in `match` instead of on any check.
|
|
90
|
+
if (rule.trigger.length === 0)
|
|
91
|
+
return true;
|
|
92
|
+
const wantsUnhealthy = rule.triggerOn === "unhealthy" || rule.kind === "hardening";
|
|
93
|
+
const triggers = (id) => {
|
|
94
|
+
const status = facts.statusOf(id);
|
|
95
|
+
return wantsUnhealthy ? isUnhealthy(status) : status === "fail";
|
|
96
|
+
};
|
|
97
|
+
return rule.triggerMode === "all" ? rule.trigger.every(triggers) : rule.trigger.some(triggers);
|
|
98
|
+
}
|
|
99
|
+
function toDiagnosedCause(fired, copy) {
|
|
100
|
+
const entry = copy[fired.rule.id];
|
|
101
|
+
const doc = entry.doc(fired.vars);
|
|
102
|
+
// The phases a cause is about are the union of the phases its claimed
|
|
103
|
+
// checks were about, deduped in PhaseName order rather than discovery order
|
|
104
|
+
// so the field is stable across runs.
|
|
105
|
+
const claimed = new Set(fired.vars.phases);
|
|
106
|
+
return {
|
|
107
|
+
id: fired.rule.id,
|
|
108
|
+
kind: fired.rule.kind,
|
|
109
|
+
problem: entry.problem(fired.vars),
|
|
110
|
+
fix: entry.fix(fired.vars),
|
|
111
|
+
docUrl: docUrl(doc),
|
|
112
|
+
docTitle: docTitle(doc),
|
|
113
|
+
explains: fired.claims,
|
|
114
|
+
phases: ["clean", "grant", "reject"].filter((phase) => claimed.has(phase)),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Diagnose one run.
|
|
119
|
+
*
|
|
120
|
+
* `copy` is the i18n seam: another table over the same CauseIds and CauseVars
|
|
121
|
+
* swaps the language without touching a single predicate.
|
|
122
|
+
*/
|
|
123
|
+
export function diagnose(analysis, extras, copy = EN_CAUSE_COPY) {
|
|
124
|
+
const facts = buildFacts(analysis, extras);
|
|
125
|
+
const hadFailures = analysis.checks.some((check) => check.status === "fail");
|
|
126
|
+
const open = new Set(facts.unhealthy);
|
|
127
|
+
const fired = [];
|
|
128
|
+
for (const rule of CAUSE_RULES) {
|
|
129
|
+
if (!triggerStatusHolds(rule, facts))
|
|
130
|
+
continue;
|
|
131
|
+
// Subsumption. If a check this rule exists for is unhealthy but no longer
|
|
132
|
+
// open, an earlier cause already accounted for it and this rule would be
|
|
133
|
+
// re-reporting the same problem one level down.
|
|
134
|
+
if (rule.trigger.some((id) => facts.unhealthy.includes(id) && !open.has(id)))
|
|
135
|
+
continue;
|
|
136
|
+
const match = rule.match(facts);
|
|
137
|
+
if (match === null)
|
|
138
|
+
continue;
|
|
139
|
+
// Filtering against `open` before recording is what makes double-claiming
|
|
140
|
+
// structurally impossible rather than merely unlikely.
|
|
141
|
+
const claims = [...new Set([...rule.trigger, ...match.claims])].filter((id) => open.has(id));
|
|
142
|
+
const phases = [...new Set(claims.flatMap((id) => facts.failingPhases(id)))];
|
|
143
|
+
fired.push({
|
|
144
|
+
rule,
|
|
145
|
+
claims,
|
|
146
|
+
vars: { ...facts.vars, ...match.vars, phases: phases.length > 0 ? phases : facts.vars.phases },
|
|
147
|
+
});
|
|
148
|
+
for (const id of claims)
|
|
149
|
+
open.delete(id);
|
|
150
|
+
if (match.preempt) {
|
|
151
|
+
// This run measured something other than the site. Anything else we
|
|
152
|
+
// could say about it would be a statement about a bot wall's challenge
|
|
153
|
+
// document, or about someone else's analytics.
|
|
154
|
+
return {
|
|
155
|
+
causes: fired.map((f) => toDiagnosedCause(f, copy)),
|
|
156
|
+
alsoFired: [],
|
|
157
|
+
unexplainedChecks: [],
|
|
158
|
+
hadFailures,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Stable sort on a total-ordered key, so equal kinds keep rule order and
|
|
163
|
+
// the same evidence always produces the same ranking.
|
|
164
|
+
const ranked = [...fired].sort((a, b) => KIND_RANK[a.rule.kind] - KIND_RANK[b.rule.kind]);
|
|
165
|
+
return {
|
|
166
|
+
causes: ranked.slice(0, MAX_CAUSES).map((f) => toDiagnosedCause(f, copy)),
|
|
167
|
+
alsoFired: ranked.slice(MAX_CAUSES).map((f) => f.rule.id),
|
|
168
|
+
unexplainedChecks: [...open],
|
|
169
|
+
hadFailures,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=diagnose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../../../src/analysis/diagnosis/diagnose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
export const DOCS_BASE_URL = "https://developer.dreamdata.io";
|
|
2
|
+
export const DOC_LINKS = {
|
|
3
|
+
/** Carries the per-vendor outbound list, which is why a CMP fix links here. */
|
|
4
|
+
"consent-mode-turn-on": {
|
|
5
|
+
path: "client-side/google-consent-mode",
|
|
6
|
+
anchor: "how-to-turn-on-google-consent-mode-v2",
|
|
7
|
+
title: "How to turn on Google Consent Mode v2",
|
|
8
|
+
},
|
|
9
|
+
"consent-mode-verify": {
|
|
10
|
+
path: "client-side/google-consent-mode",
|
|
11
|
+
anchor: "how-to-check-that-google-consent-mode-v2-is-enabled",
|
|
12
|
+
title: "How to check Google Consent Mode v2 is enabled",
|
|
13
|
+
},
|
|
14
|
+
/** The recipe for firing a tag off a CMP's own dataLayer event. */
|
|
15
|
+
"gtm-custom-trigger": {
|
|
16
|
+
path: "client-side/troubleshooting",
|
|
17
|
+
anchor: "adding-a-custom-trigger-in-google-tag-manager",
|
|
18
|
+
title: "Adding a custom trigger in Google Tag Manager",
|
|
19
|
+
},
|
|
20
|
+
spa: {
|
|
21
|
+
path: "client-side/how-to-track-spas",
|
|
22
|
+
title: "Single-Page App SDK",
|
|
23
|
+
},
|
|
24
|
+
"script-installation": {
|
|
25
|
+
path: "client-side/script-installation",
|
|
26
|
+
title: "Website Script",
|
|
27
|
+
},
|
|
28
|
+
"script-installation-gtm": {
|
|
29
|
+
path: "client-side/script-installation",
|
|
30
|
+
anchor: "option-b-install-with-google-tag-manager",
|
|
31
|
+
title: "Install with Google Tag Manager",
|
|
32
|
+
},
|
|
33
|
+
"script-installation-troubleshooting": {
|
|
34
|
+
path: "client-side/script-installation",
|
|
35
|
+
anchor: "troubleshooting-common-issues",
|
|
36
|
+
title: "Troubleshooting common issues",
|
|
37
|
+
},
|
|
38
|
+
cookieless: {
|
|
39
|
+
path: "client-side/cookieless",
|
|
40
|
+
title: "Cookieless Account Analytics",
|
|
41
|
+
},
|
|
42
|
+
debugging: {
|
|
43
|
+
path: "client-side/debugging-dreamdata-analytics",
|
|
44
|
+
title: "Test your tracking",
|
|
45
|
+
},
|
|
46
|
+
csp: {
|
|
47
|
+
path: "client-side/csp",
|
|
48
|
+
title: "Content Security Policy",
|
|
49
|
+
},
|
|
50
|
+
cookies: {
|
|
51
|
+
path: "faq/cookies",
|
|
52
|
+
title: "Cookies",
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
/** Composed in one place, so there is one thing for a test to assert about. */
|
|
56
|
+
export function docUrl(id) {
|
|
57
|
+
const link = DOC_LINKS[id];
|
|
58
|
+
return `${DOCS_BASE_URL}/${link.path}${link.anchor ? `#${link.anchor}` : ""}`;
|
|
59
|
+
}
|
|
60
|
+
export function docTitle(id) {
|
|
61
|
+
return DOC_LINKS[id].title;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The CMP vendors the Consent Mode page actually has setup instructions for.
|
|
65
|
+
*
|
|
66
|
+
* The intersection of two lists: the vendors named in
|
|
67
|
+
* `docs/client-side/google-consent-mode.md` (CookieBot, CookieYes, OneTrust,
|
|
68
|
+
* Osano, HubSpot, Cookie Information, Framer, Klaro) and the vendor ids this
|
|
69
|
+
* harness can detect (CMP_VENDORS and DOM_ONLY_CMP_VENDORS in
|
|
70
|
+
* src/evidence/constants.ts). Cookie Information, Framer and Klaro are in the
|
|
71
|
+
* docs but undetectable, so they cannot appear here; usercentrics, pardot,
|
|
72
|
+
* termly, complianz, trustarc, ketch, cookiescript and the two IAB shims are
|
|
73
|
+
* detectable but absent from the docs, so a fix sentence for them has to
|
|
74
|
+
* degrade — see CMP_DISPLAY_NAMES and the copy table.
|
|
75
|
+
*
|
|
76
|
+
* Real reports currently detect usercentrics (2 sites) and pardot (1), so
|
|
77
|
+
* that degrade path is live, not theoretical. docs.test.ts asserts this set
|
|
78
|
+
* in BOTH directions, so adding Usercentrics to the docs without adding it
|
|
79
|
+
* here fails the build rather than leaving the sentence needlessly vague.
|
|
80
|
+
*/
|
|
81
|
+
export const CMP_VENDORS_IN_DOCS = new Set([
|
|
82
|
+
"cookiebot",
|
|
83
|
+
"cookieyes",
|
|
84
|
+
"onetrust",
|
|
85
|
+
"osano",
|
|
86
|
+
"hubspot",
|
|
87
|
+
]);
|
|
88
|
+
/**
|
|
89
|
+
* How a vendor id is spelled in a sentence a human reads.
|
|
90
|
+
*
|
|
91
|
+
* Only ids that can actually reach a sentence need an entry; anything missing
|
|
92
|
+
* falls back to the raw id, which is still readable ("ketch"). "unknown-custom"
|
|
93
|
+
* is deliberately absent: a bespoke banner has no name to print, and the copy
|
|
94
|
+
* table branches on that rather than printing a placeholder.
|
|
95
|
+
*/
|
|
96
|
+
export const CMP_DISPLAY_NAMES = {
|
|
97
|
+
cookiebot: "Cookiebot",
|
|
98
|
+
cookieyes: "CookieYes",
|
|
99
|
+
onetrust: "OneTrust",
|
|
100
|
+
osano: "Osano",
|
|
101
|
+
hubspot: "HubSpot",
|
|
102
|
+
usercentrics: "Usercentrics",
|
|
103
|
+
pardot: "Pardot",
|
|
104
|
+
termly: "Termly",
|
|
105
|
+
complianz: "Complianz",
|
|
106
|
+
trustarc: "TrustArc",
|
|
107
|
+
ketch: "Ketch",
|
|
108
|
+
cookiescript: "CookieScript",
|
|
109
|
+
"iab-tcf": "the IAB TCF CMP",
|
|
110
|
+
"iab-cmp": "the IAB CMP",
|
|
111
|
+
"generic-cookieconsent": "the CookieConsent banner",
|
|
112
|
+
};
|
|
113
|
+
export function cmpDisplayName(vendor) {
|
|
114
|
+
if (vendor === null || vendor === "unknown-custom")
|
|
115
|
+
return "the cookie banner";
|
|
116
|
+
return CMP_DISPLAY_NAMES[vendor] ?? vendor;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=docs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.js","sourceRoot":"","sources":["../../../src/analysis/diagnosis/docs.ts"],"names":[],"mappings":"AAmBA,MAAM,CAAC,MAAM,aAAa,GAAG,gCAAgC,CAAC;AAE9D,MAAM,CAAC,MAAM,SAAS,GAA+B;IACnD,+EAA+E;IAC/E,sBAAsB,EAAE;QACtB,IAAI,EAAE,iCAAiC;QACvC,MAAM,EAAE,uCAAuC;QAC/C,KAAK,EAAE,uCAAuC;KAC/C;IACD,qBAAqB,EAAE;QACrB,IAAI,EAAE,iCAAiC;QACvC,MAAM,EAAE,qDAAqD;QAC7D,KAAK,EAAE,gDAAgD;KACxD;IACD,mEAAmE;IACnE,oBAAoB,EAAE;QACpB,IAAI,EAAE,6BAA6B;QACnC,MAAM,EAAE,+CAA+C;QACvD,KAAK,EAAE,+CAA+C;KACvD;IACD,GAAG,EAAE;QACH,IAAI,EAAE,+BAA+B;QACrC,KAAK,EAAE,qBAAqB;KAC7B;IACD,qBAAqB,EAAE;QACrB,IAAI,EAAE,iCAAiC;QACvC,KAAK,EAAE,gBAAgB;KACxB;IACD,yBAAyB,EAAE;QACzB,IAAI,EAAE,iCAAiC;QACvC,MAAM,EAAE,0CAA0C;QAClD,KAAK,EAAE,iCAAiC;KACzC;IACD,qCAAqC,EAAE;QACrC,IAAI,EAAE,iCAAiC;QACvC,MAAM,EAAE,+BAA+B;QACvC,KAAK,EAAE,+BAA+B;KACvC;IACD,UAAU,EAAE;QACV,IAAI,EAAE,wBAAwB;QAC9B,KAAK,EAAE,8BAA8B;KACtC;IACD,SAAS,EAAE;QACT,IAAI,EAAE,2CAA2C;QACjD,KAAK,EAAE,oBAAoB;KAC5B;IACD,GAAG,EAAE;QACH,IAAI,EAAE,iBAAiB;QACvB,KAAK,EAAE,yBAAyB;KACjC;IACD,OAAO,EAAE;QACP,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,SAAS;KACjB;CACF,CAAC;AAEF,+EAA+E;AAC/E,MAAM,UAAU,MAAM,CAAC,EAAa;IAClC,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IAC3B,OAAO,GAAG,aAAa,IAAI,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAa;IACpC,OAAO,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC;AAC7B,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAwB,IAAI,GAAG,CAAC;IAC9D,WAAW;IACX,WAAW;IACX,UAAU;IACV,OAAO;IACP,SAAS;CACV,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,SAAS,EAAE,WAAW;IACtB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,OAAO;IACd,OAAO,EAAE,SAAS;IAClB,YAAY,EAAE,cAAc;IAC5B,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,OAAO;IACd,YAAY,EAAE,cAAc;IAC5B,SAAS,EAAE,iBAAiB;IAC5B,SAAS,EAAE,aAAa;IACxB,uBAAuB,EAAE,0BAA0B;CACpD,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,gBAAgB;QAAE,OAAO,mBAAmB,CAAC;IAC/E,OAAO,iBAAiB,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { diagnose } from "./diagnose.js";
|
|
2
|
+
export { CMP_VENDORS_IN_DOCS, DOCS_BASE_URL, DOC_LINKS, cmpDisplayName, docTitle, docUrl } from "./docs.js";
|
|
3
|
+
export { EN_CAUSE_COPY, EN_CAUSE_LABELS, causeLabel } from "./copy.en.js";
|
|
4
|
+
export { CAUSE_RULES } from "./rules.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/analysis/diagnosis/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC5G,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|