@setsquare/review-sdk 0.0.1
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 +202 -0
- package/NOTICE +57 -0
- package/README.md +338 -0
- package/THIRD-PARTY-NOTICES.md +61 -0
- package/dist/autoscan.d.ts +25 -0
- package/dist/autoscan.d.ts.map +1 -0
- package/dist/autoscan.js +332 -0
- package/dist/autoscan.js.map +1 -0
- package/dist/axe.d.ts +96 -0
- package/dist/axe.d.ts.map +1 -0
- package/dist/axe.js +210 -0
- package/dist/axe.js.map +1 -0
- package/dist/bin/setsquare.d.ts +3 -0
- package/dist/bin/setsquare.d.ts.map +1 -0
- package/dist/bin/setsquare.js +21 -0
- package/dist/bin/setsquare.js.map +1 -0
- package/dist/brand.d.ts +84 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +335 -0
- package/dist/brand.js.map +1 -0
- package/dist/checks/dynamic.d.ts +57 -0
- package/dist/checks/dynamic.d.ts.map +1 -0
- package/dist/checks/dynamic.js +184 -0
- package/dist/checks/dynamic.js.map +1 -0
- package/dist/checks/rule-pack.d.ts +34 -0
- package/dist/checks/rule-pack.d.ts.map +1 -0
- package/dist/checks/rule-pack.js +270 -0
- package/dist/checks/rule-pack.js.map +1 -0
- package/dist/checks/versions.d.ts +28 -0
- package/dist/checks/versions.d.ts.map +1 -0
- package/dist/checks/versions.js +45 -0
- package/dist/checks/versions.js.map +1 -0
- package/dist/ci.d.ts +37 -0
- package/dist/ci.d.ts.map +1 -0
- package/dist/ci.js +199 -0
- package/dist/ci.js.map +1 -0
- package/dist/contract.d.ts +334 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +35 -0
- package/dist/contract.js.map +1 -0
- package/dist/dedupe.d.ts +79 -0
- package/dist/dedupe.d.ts.map +1 -0
- package/dist/dedupe.js +102 -0
- package/dist/dedupe.js.map +1 -0
- package/dist/document.d.ts +29 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +94 -0
- package/dist/document.js.map +1 -0
- package/dist/envelope.d.ts +124 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +337 -0
- package/dist/envelope.js.map +1 -0
- package/dist/escape.d.ts +14 -0
- package/dist/escape.d.ts.map +1 -0
- package/dist/escape.js +20 -0
- package/dist/escape.js.map +1 -0
- package/dist/findings.d.ts +47 -0
- package/dist/findings.d.ts.map +1 -0
- package/dist/findings.js +229 -0
- package/dist/findings.js.map +1 -0
- package/dist/fixture.d.ts +7 -0
- package/dist/fixture.d.ts.map +1 -0
- package/dist/fixture.js +237 -0
- package/dist/fixture.js.map +1 -0
- package/dist/group.d.ts +214 -0
- package/dist/group.d.ts.map +1 -0
- package/dist/group.js +709 -0
- package/dist/group.js.map +1 -0
- package/dist/html-report.d.ts +68 -0
- package/dist/html-report.d.ts.map +1 -0
- package/dist/html-report.js +649 -0
- package/dist/html-report.js.map +1 -0
- package/dist/human.d.ts +65 -0
- package/dist/human.d.ts.map +1 -0
- package/dist/human.js +111 -0
- package/dist/human.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/infer.d.ts +65 -0
- package/dist/infer.d.ts.map +1 -0
- package/dist/infer.js +67 -0
- package/dist/infer.js.map +1 -0
- package/dist/insights.d.ts +140 -0
- package/dist/insights.d.ts.map +1 -0
- package/dist/insights.js +483 -0
- package/dist/insights.js.map +1 -0
- package/dist/install.d.ts +8 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +114 -0
- package/dist/install.js.map +1 -0
- package/dist/links.d.ts +45 -0
- package/dist/links.d.ts.map +1 -0
- package/dist/links.js +45 -0
- package/dist/links.js.map +1 -0
- package/dist/mask.d.ts +85 -0
- package/dist/mask.d.ts.map +1 -0
- package/dist/mask.js +98 -0
- package/dist/mask.js.map +1 -0
- package/dist/observe.d.ts +51 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +233 -0
- package/dist/observe.js.map +1 -0
- package/dist/options.d.ts +249 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +185 -0
- package/dist/options.js.map +1 -0
- package/dist/output.d.ts +113 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +231 -0
- package/dist/output.js.map +1 -0
- package/dist/perf.d.ts +11 -0
- package/dist/perf.d.ts.map +1 -0
- package/dist/perf.js +150 -0
- package/dist/perf.js.map +1 -0
- package/dist/reading-level.d.ts +73 -0
- package/dist/reading-level.d.ts.map +1 -0
- package/dist/reading-level.js +189 -0
- package/dist/reading-level.js.map +1 -0
- package/dist/reporter.d.ts +94 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +709 -0
- package/dist/reporter.js.map +1 -0
- package/dist/rules.d.ts +55 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +77 -0
- package/dist/rules.js.map +1 -0
- package/dist/runtime.d.ts +32 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +67 -0
- package/dist/runtime.js.map +1 -0
- package/dist/sanitise.d.ts +116 -0
- package/dist/sanitise.d.ts.map +1 -0
- package/dist/sanitise.js +247 -0
- package/dist/sanitise.js.map +1 -0
- package/dist/scan.d.ts +60 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +246 -0
- package/dist/scan.js.map +1 -0
- package/dist/screens.d.ts +98 -0
- package/dist/screens.d.ts.map +1 -0
- package/dist/screens.js +301 -0
- package/dist/screens.js.map +1 -0
- package/dist/settle.d.ts +65 -0
- package/dist/settle.d.ts.map +1 -0
- package/dist/settle.js +162 -0
- package/dist/settle.js.map +1 -0
- package/dist/shots.d.ts +109 -0
- package/dist/shots.d.ts.map +1 -0
- package/dist/shots.js +113 -0
- package/dist/shots.js.map +1 -0
- package/dist/style.d.ts +47 -0
- package/dist/style.d.ts.map +1 -0
- package/dist/style.js +154 -0
- package/dist/style.js.map +1 -0
- package/dist/suite.d.ts +218 -0
- package/dist/suite.d.ts.map +1 -0
- package/dist/suite.js +219 -0
- package/dist/suite.js.map +1 -0
- package/dist/summary.d.ts +268 -0
- package/dist/summary.d.ts.map +1 -0
- package/dist/summary.js +1308 -0
- package/dist/summary.js.map +1 -0
- package/dist/unscannable.d.ts +75 -0
- package/dist/unscannable.d.ts.map +1 -0
- package/dist/unscannable.js +111 -0
- package/dist/unscannable.js.map +1 -0
- package/dist/versions.d.ts +13 -0
- package/dist/versions.d.ts.map +1 -0
- package/dist/versions.js +39 -0
- package/dist/versions.js.map +1 -0
- package/dist/wcag-map.d.ts +19 -0
- package/dist/wcag-map.d.ts.map +1 -0
- package/dist/wcag-map.js +52 -0
- package/dist/wcag-map.js.map +1 -0
- package/dist/with-setsquare.d.ts +26 -0
- package/dist/with-setsquare.d.ts.map +1 -0
- package/dist/with-setsquare.js +70 -0
- package/dist/with-setsquare.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setsquare's in-page axe rule pack: AAA checks axe does not ship.
|
|
3
|
+
*
|
|
4
|
+
* Registered via `axe.configure()` on OUR instance (never `window.axe`)
|
|
5
|
+
* immediately after axe is injected, so the rules flow through the same
|
|
6
|
+
* results shape, the same tags→WCAG mapping, and the same sanitisation as
|
|
7
|
+
* axe's own. Every rule carries an AAA version tag, which is what scopes it:
|
|
8
|
+
* `runOnly` selects by tag, so the pack only ever runs when a scan targets
|
|
9
|
+
* AAA — exactly like axe's own three AAA rules.
|
|
10
|
+
*
|
|
11
|
+
* **Clean-room rule (licensing):** these checks are implemented from the WCAG
|
|
12
|
+
* 2.2 Understanding documents cited on each rule, never from axe's own rule
|
|
13
|
+
* source (MPL — a close rewrite is a derivative) and never from GPL tools.
|
|
14
|
+
*
|
|
15
|
+
* **Honesty rule:** violation only where the geometry is deterministic and the
|
|
16
|
+
* SC's exceptions have been ruled out; everything judgment-shaped returns
|
|
17
|
+
* `undefined`, axe's needs-review outcome. 2.5.5's exceptions are Equivalent /
|
|
18
|
+
* Inline / User-agent / Essential — note there is NO spacing exception at AAA
|
|
19
|
+
* (that is 2.5.8's escape hatch, and importing it here would assess the wrong
|
|
20
|
+
* criterion).
|
|
21
|
+
*
|
|
22
|
+
* The pack is a source string because check `evaluate` functions must live in
|
|
23
|
+
* the page; a function shipped from Node does not survive the evaluate
|
|
24
|
+
* boundary. Version every behavioural change via SETSQUARE_RULE_PACK_VERSION — it
|
|
25
|
+
* feeds the ruleset digest.
|
|
26
|
+
*/
|
|
27
|
+
export declare const SETSQUARE_RULE_PACK_VERSION = "setsquare-rules@1";
|
|
28
|
+
export declare const SETSQUARE_RULE_IDS: readonly ["setsquare-target-size-aaa", "setsquare-visual-presentation", "setsquare-link-purpose"];
|
|
29
|
+
/**
|
|
30
|
+
* An IIFE taking the axe instance. Interpolated values are limited to the
|
|
31
|
+
* help URLs from links.ts — everything else is static source.
|
|
32
|
+
*/
|
|
33
|
+
export declare function rulePackSource(): string;
|
|
34
|
+
//# sourceMappingURL=rule-pack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-pack.d.ts","sourceRoot":"","sources":["../../src/checks/rule-pack.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,eAAO,MAAM,2BAA2B,sBAAsB,CAAC;AAE/D,eAAO,MAAM,kBAAkB,mGAIrB,CAAC;AAEX;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAuOvC"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { LINK_PURPOSE_LINK_ONLY_HELP_URL, TARGET_SIZE_ENHANCED_HELP_URL, VISUAL_PRESENTATION_HELP_URL, } from '../links.js';
|
|
2
|
+
/**
|
|
3
|
+
* Setsquare's in-page axe rule pack: AAA checks axe does not ship.
|
|
4
|
+
*
|
|
5
|
+
* Registered via `axe.configure()` on OUR instance (never `window.axe`)
|
|
6
|
+
* immediately after axe is injected, so the rules flow through the same
|
|
7
|
+
* results shape, the same tags→WCAG mapping, and the same sanitisation as
|
|
8
|
+
* axe's own. Every rule carries an AAA version tag, which is what scopes it:
|
|
9
|
+
* `runOnly` selects by tag, so the pack only ever runs when a scan targets
|
|
10
|
+
* AAA — exactly like axe's own three AAA rules.
|
|
11
|
+
*
|
|
12
|
+
* **Clean-room rule (licensing):** these checks are implemented from the WCAG
|
|
13
|
+
* 2.2 Understanding documents cited on each rule, never from axe's own rule
|
|
14
|
+
* source (MPL — a close rewrite is a derivative) and never from GPL tools.
|
|
15
|
+
*
|
|
16
|
+
* **Honesty rule:** violation only where the geometry is deterministic and the
|
|
17
|
+
* SC's exceptions have been ruled out; everything judgment-shaped returns
|
|
18
|
+
* `undefined`, axe's needs-review outcome. 2.5.5's exceptions are Equivalent /
|
|
19
|
+
* Inline / User-agent / Essential — note there is NO spacing exception at AAA
|
|
20
|
+
* (that is 2.5.8's escape hatch, and importing it here would assess the wrong
|
|
21
|
+
* criterion).
|
|
22
|
+
*
|
|
23
|
+
* The pack is a source string because check `evaluate` functions must live in
|
|
24
|
+
* the page; a function shipped from Node does not survive the evaluate
|
|
25
|
+
* boundary. Version every behavioural change via SETSQUARE_RULE_PACK_VERSION — it
|
|
26
|
+
* feeds the ruleset digest.
|
|
27
|
+
*/
|
|
28
|
+
export const SETSQUARE_RULE_PACK_VERSION = 'setsquare-rules@1';
|
|
29
|
+
export const SETSQUARE_RULE_IDS = [
|
|
30
|
+
'setsquare-target-size-aaa',
|
|
31
|
+
'setsquare-visual-presentation',
|
|
32
|
+
'setsquare-link-purpose',
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* An IIFE taking the axe instance. Interpolated values are limited to the
|
|
36
|
+
* help URLs from links.ts — everything else is static source.
|
|
37
|
+
*/
|
|
38
|
+
export function rulePackSource() {
|
|
39
|
+
return `(function (axe) {
|
|
40
|
+
'use strict';
|
|
41
|
+
|
|
42
|
+
axe.configure({
|
|
43
|
+
checks: [
|
|
44
|
+
{
|
|
45
|
+
// WCAG 2.5.5 Target Size (Enhanced), AAA. Implemented from the W3C
|
|
46
|
+
// Understanding document for 2.5.5 (linked as this rule's helpUrl).
|
|
47
|
+
id: 'setsquare-target-size-44',
|
|
48
|
+
evaluate: function (node) {
|
|
49
|
+
var rect = node.getBoundingClientRect();
|
|
50
|
+
var width = Math.round(rect.width);
|
|
51
|
+
var height = Math.round(rect.height);
|
|
52
|
+
// No accessible name here, deliberately (D13). For this rule the label
|
|
53
|
+
// is decoration around a measurement — the finding is 32x32 against a
|
|
54
|
+
// 44x44 requirement, and it reads the same without the page's own text.
|
|
55
|
+
// The link-purpose rule below is where the name IS the finding, and it
|
|
56
|
+
// is the only rule in this pack that may carry one.
|
|
57
|
+
//
|
|
58
|
+
// Note for anyone editing this file: it is one long template literal,
|
|
59
|
+
// so a backtick in a comment ends the string and the parse error lands
|
|
60
|
+
// three checks away from the character that caused it.
|
|
61
|
+
// Path only. A query string and a fragment are where reset tokens,
|
|
62
|
+
// email addresses and session ids live, and none of them is evidence
|
|
63
|
+
// about a target's size. Stripped here so the value never enters the
|
|
64
|
+
// check's data at all; the contract strips it again on the way out,
|
|
65
|
+
// because a rule author's care is not a boundary (D13).
|
|
66
|
+
var href = (node.getAttribute('href') || '').split('#')[0].split('?')[0];
|
|
67
|
+
|
|
68
|
+
this.data({
|
|
69
|
+
width: width,
|
|
70
|
+
height: height,
|
|
71
|
+
href: href,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (width >= 44 && height >= 44) return true;
|
|
75
|
+
|
|
76
|
+
// Inline exception: a target in a sentence or line of text is exempt.
|
|
77
|
+
var display = window.getComputedStyle(node).display;
|
|
78
|
+
if (display === 'inline' || display === 'inline-block') {
|
|
79
|
+
var parent = node.parentElement;
|
|
80
|
+
if (parent) {
|
|
81
|
+
for (var i = 0; i < parent.childNodes.length; i += 1) {
|
|
82
|
+
var sibling = parent.childNodes[i];
|
|
83
|
+
if (sibling.nodeType === 3 && sibling.textContent && sibling.textContent.trim()) {
|
|
84
|
+
// Sits amongst text: the inline exception may apply — a person decides.
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// User-agent exception: unstyled native checkboxes/radios are the
|
|
92
|
+
// browser's own size, which the SC exempts.
|
|
93
|
+
if (
|
|
94
|
+
node.tagName === 'INPUT' &&
|
|
95
|
+
(node.type === 'checkbox' || node.type === 'radio')
|
|
96
|
+
) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Deterministically small; the Equivalent exception is ruled out (or
|
|
101
|
+
// not) across the whole page in the after() phase.
|
|
102
|
+
return false;
|
|
103
|
+
},
|
|
104
|
+
after: function (results) {
|
|
105
|
+
// Equivalent exception: another target with the same function
|
|
106
|
+
// (approximated by accessible name / destination) that IS large
|
|
107
|
+
// enough. Cannot be decided per-node, so it is decided here, and it
|
|
108
|
+
// downgrades a failure to needs-review rather than deleting it — the
|
|
109
|
+
// heuristic sees a name match, not a genuine functional equivalent.
|
|
110
|
+
var bigEnough = {};
|
|
111
|
+
results.forEach(function (result) {
|
|
112
|
+
if (result.result === true && result.data) {
|
|
113
|
+
var key = result.data.href || result.data.name;
|
|
114
|
+
if (key) bigEnough[key] = true;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
results.forEach(function (result) {
|
|
118
|
+
if (result.result === false && result.data) {
|
|
119
|
+
var key = result.data.href || result.data.name;
|
|
120
|
+
if (key && bigEnough[key]) result.result = undefined;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
return results;
|
|
124
|
+
},
|
|
125
|
+
metadata: {
|
|
126
|
+
impact: 'moderate',
|
|
127
|
+
messages: {
|
|
128
|
+
pass: 'Target is at least 44 by 44 CSS pixels',
|
|
129
|
+
fail: 'Target is smaller than 44 by 44 CSS pixels and no exception applies',
|
|
130
|
+
incomplete:
|
|
131
|
+
'Target is smaller than 44 by 44 CSS pixels; an exception (inline, user-agent default, or an equivalent control) may apply — needs a person',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
// WCAG 1.4.8 Visual Presentation, AAA. Implemented from the W3C
|
|
137
|
+
// Understanding document for 1.4.8 (linked as this rule's helpUrl).
|
|
138
|
+
// Scoped to the prongs an author actively defeats: justified text,
|
|
139
|
+
// fixed line-height below 1.5, and measures past 80 characters
|
|
140
|
+
// (40 for CJK). Always needs-review — the SC requires a MECHANISM be
|
|
141
|
+
// available, so a conflicting default is a signal, never a verdict.
|
|
142
|
+
id: 'setsquare-visual-presentation-defaults',
|
|
143
|
+
evaluate: function (node) {
|
|
144
|
+
var style = window.getComputedStyle(node);
|
|
145
|
+
var problems = [];
|
|
146
|
+
|
|
147
|
+
if (style.textAlign === 'justify') problems.push('justified');
|
|
148
|
+
|
|
149
|
+
var fontSize = parseFloat(style.fontSize);
|
|
150
|
+
var lineHeight = parseFloat(style.lineHeight);
|
|
151
|
+
if (
|
|
152
|
+
style.lineHeight !== 'normal' &&
|
|
153
|
+
isFinite(lineHeight) &&
|
|
154
|
+
isFinite(fontSize) &&
|
|
155
|
+
fontSize > 0 &&
|
|
156
|
+
lineHeight / fontSize < 1.5
|
|
157
|
+
) {
|
|
158
|
+
problems.push('line-height ' + (Math.round((lineHeight / fontSize) * 100) / 100));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
var lang = (node.closest('[lang]') || document.documentElement)
|
|
162
|
+
.getAttribute('lang');
|
|
163
|
+
var cjk = /^(ja|zh|ko)/i.test(lang || '');
|
|
164
|
+
var width = node.getBoundingClientRect().width;
|
|
165
|
+
// Approximate rendered measure: CJK glyphs are square (one em); Latin
|
|
166
|
+
// averages about half an em.
|
|
167
|
+
var chars = cjk ? width / fontSize : width / (fontSize * 0.5);
|
|
168
|
+
var limit = cjk ? 40 : 80;
|
|
169
|
+
if (isFinite(chars) && chars > limit) {
|
|
170
|
+
problems.push('measure ~' + Math.round(chars) + ' chars (limit ' + limit + ')');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (problems.length === 0) return true;
|
|
174
|
+
this.data({ problems: problems.join('; ') });
|
|
175
|
+
return undefined;
|
|
176
|
+
},
|
|
177
|
+
metadata: {
|
|
178
|
+
impact: 'minor',
|
|
179
|
+
messages: {
|
|
180
|
+
pass: 'Text block defaults do not conflict with 1.4.8',
|
|
181
|
+
fail: 'Text block presentation fails 1.4.8',
|
|
182
|
+
incomplete:
|
|
183
|
+
'Defaults conflict with 1.4.8; a user mechanism may still satisfy it — needs a person',
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
// WCAG 2.4.9 Link Purpose (Link Only), AAA. Implemented from the W3C
|
|
189
|
+
// Understanding document for 2.4.9 (linked as this rule's helpUrl).
|
|
190
|
+
id: 'setsquare-link-purpose-text',
|
|
191
|
+
evaluate: function (node) {
|
|
192
|
+
var name = (
|
|
193
|
+
node.getAttribute('aria-label') ||
|
|
194
|
+
node.textContent ||
|
|
195
|
+
node.getAttribute('title') ||
|
|
196
|
+
''
|
|
197
|
+
)
|
|
198
|
+
.trim()
|
|
199
|
+
.toLowerCase()
|
|
200
|
+
.replace(/\\s+/g, ' ');
|
|
201
|
+
|
|
202
|
+
if (!name) return true; // Nameless links are axe's link-name rule, not ours.
|
|
203
|
+
|
|
204
|
+
var vague = [
|
|
205
|
+
'click here', 'click', 'here', 'read more', 'more', 'learn more',
|
|
206
|
+
'details', 'more details', 'this page', 'continue', 'link', 'go',
|
|
207
|
+
];
|
|
208
|
+
var isVague = vague.indexOf(name) !== -1 || /^https?:\\/\\//.test(name);
|
|
209
|
+
|
|
210
|
+
if (!isVague) return true;
|
|
211
|
+
this.data({ name: name.slice(0, 80) });
|
|
212
|
+
return undefined;
|
|
213
|
+
},
|
|
214
|
+
metadata: {
|
|
215
|
+
impact: 'minor',
|
|
216
|
+
messages: {
|
|
217
|
+
pass: 'Link text describes its purpose',
|
|
218
|
+
fail: 'Link text does not describe its purpose',
|
|
219
|
+
incomplete:
|
|
220
|
+
'Link text alone may not describe its purpose ("click here", "read more", a bare URL) — needs a person',
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
],
|
|
225
|
+
rules: [
|
|
226
|
+
{
|
|
227
|
+
id: 'setsquare-target-size-aaa',
|
|
228
|
+
selector:
|
|
229
|
+
'a[href], button, input:not([type=hidden]), select, textarea, ' +
|
|
230
|
+
'[role=button], [role=link], [role=checkbox], [role=radio], [role=tab], [role=menuitem]',
|
|
231
|
+
excludeHidden: true,
|
|
232
|
+
// 2.5.5 arrived in WCAG 2.1; the criterion tag is what toWcag() maps.
|
|
233
|
+
tags: ['wcag21aaa', 'wcag255'],
|
|
234
|
+
all: ['setsquare-target-size-44'],
|
|
235
|
+
metadata: {
|
|
236
|
+
description: 'Targets should be at least 44 by 44 CSS pixels (WCAG 2.5.5, AAA)',
|
|
237
|
+
help: 'Target size (enhanced)',
|
|
238
|
+
helpUrl: '${TARGET_SIZE_ENHANCED_HELP_URL}',
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: 'setsquare-visual-presentation',
|
|
243
|
+
selector: 'p',
|
|
244
|
+
excludeHidden: true,
|
|
245
|
+
tags: ['wcag2aaa', 'wcag148'],
|
|
246
|
+
all: ['setsquare-visual-presentation-defaults'],
|
|
247
|
+
metadata: {
|
|
248
|
+
description:
|
|
249
|
+
'Text block presentation should not conflict with WCAG 1.4.8 defaults (AAA)',
|
|
250
|
+
help: 'Visual presentation',
|
|
251
|
+
helpUrl: '${VISUAL_PRESENTATION_HELP_URL}',
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: 'setsquare-link-purpose',
|
|
256
|
+
selector: 'a[href]',
|
|
257
|
+
excludeHidden: true,
|
|
258
|
+
tags: ['wcag2aaa', 'wcag249'],
|
|
259
|
+
all: ['setsquare-link-purpose-text'],
|
|
260
|
+
metadata: {
|
|
261
|
+
description: 'Link purpose should be clear from the link text alone (WCAG 2.4.9, AAA)',
|
|
262
|
+
help: 'Link purpose (link only)',
|
|
263
|
+
helpUrl: '${LINK_PURPOSE_LINK_ONLY_HELP_URL}',
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
});
|
|
268
|
+
})`;
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=rule-pack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-pack.js","sourceRoot":"","sources":["../../src/checks/rule-pack.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,+BAA+B,EAC/B,6BAA6B,EAC7B,4BAA4B,GAC7B,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,MAAM,CAAC,MAAM,2BAA2B,GAAG,mBAAmB,CAAC;AAE/D,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,2BAA2B;IAC3B,+BAA+B;IAC/B,wBAAwB;CAChB,CAAC;AAEX;;;GAGG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAuMa,6BAA6B;;;;;;;;;;;;;sBAa7B,4BAA4B;;;;;;;;;;;;sBAY5B,+BAA+B;;;;;GAKlD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RulePolicy } from '../rules.js';
|
|
2
|
+
/**
|
|
3
|
+
* The Setsquare checks a run is CONFIGURED with, for the ruleset digest.
|
|
4
|
+
*
|
|
5
|
+
* Policy-level, deliberately, and identical for every scan in a run: the
|
|
6
|
+
* digest pins the configuration evidence is relative to, exactly as the tag
|
|
7
|
+
* list does — a quiet auto-scan that never found a safe moment for the
|
|
8
|
+
* dynamic checks still ran under the same configuration, the same way an
|
|
9
|
+
* inapplicable axe rule is still part of the ruleset. Making this per-scan
|
|
10
|
+
* (only the scans that executed a check) split one run across two digests
|
|
11
|
+
* and set off the multi-ruleset drift warning on every run, which would
|
|
12
|
+
* teach people to ignore the warning that exists to catch real drift.
|
|
13
|
+
*/
|
|
14
|
+
export declare function setsquareCheckVersions(policy: RulePolicy): string[];
|
|
15
|
+
/**
|
|
16
|
+
* Which criteria Setsquare's OWN checks map to — the setsquare half of the
|
|
17
|
+
* criterion → rules coverage map. Without this, a setsquare-covered criterion with
|
|
18
|
+
* no rows in a run renders as "no automated check in this engine", which is
|
|
19
|
+
* false the moment the check exists: 3.3.1 and 4.1.3 sat in that list on the
|
|
20
|
+
* first real Eos run while setsquare-status-messages was right there, idle only
|
|
21
|
+
* because no error state was scanned.
|
|
22
|
+
*
|
|
23
|
+
* Lists every check that EXISTS in this build, enabled or not — the ledger's
|
|
24
|
+
* "checks that did not run here" is exactly the right label for a check that
|
|
25
|
+
* exists but was gated off (reading level at an AA target, the AAA pack at AA).
|
|
26
|
+
*/
|
|
27
|
+
export declare const SETSQUARE_CHECK_CRITERIA: ReadonlyMap<string, readonly string[]>;
|
|
28
|
+
//# sourceMappingURL=versions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions.d.ts","sourceRoot":"","sources":["../../src/checks/versions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAO9C;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,EAAE,CAKnE;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,wBAAwB,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAO1E,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { readingLevelEnabled } from '../runtime.js';
|
|
2
|
+
import { SETSQUARE_DYNAMIC_CHECKS_VERSION } from './dynamic.js';
|
|
3
|
+
import { SETSQUARE_RULE_PACK_VERSION } from './rule-pack.js';
|
|
4
|
+
import { READING_LEVEL_CHECK_VERSION } from '../reading-level.js';
|
|
5
|
+
/**
|
|
6
|
+
* The Setsquare checks a run is CONFIGURED with, for the ruleset digest.
|
|
7
|
+
*
|
|
8
|
+
* Policy-level, deliberately, and identical for every scan in a run: the
|
|
9
|
+
* digest pins the configuration evidence is relative to, exactly as the tag
|
|
10
|
+
* list does — a quiet auto-scan that never found a safe moment for the
|
|
11
|
+
* dynamic checks still ran under the same configuration, the same way an
|
|
12
|
+
* inapplicable axe rule is still part of the ruleset. Making this per-scan
|
|
13
|
+
* (only the scans that executed a check) split one run across two digests
|
|
14
|
+
* and set off the multi-ruleset drift warning on every run, which would
|
|
15
|
+
* teach people to ignore the warning that exists to catch real drift.
|
|
16
|
+
*/
|
|
17
|
+
export function setsquareCheckVersions(policy) {
|
|
18
|
+
const versions = [SETSQUARE_DYNAMIC_CHECKS_VERSION];
|
|
19
|
+
if (policy.target === 'AAA')
|
|
20
|
+
versions.push(SETSQUARE_RULE_PACK_VERSION);
|
|
21
|
+
if (readingLevelEnabled())
|
|
22
|
+
versions.push(READING_LEVEL_CHECK_VERSION);
|
|
23
|
+
return versions;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Which criteria Setsquare's OWN checks map to — the setsquare half of the
|
|
27
|
+
* criterion → rules coverage map. Without this, a setsquare-covered criterion with
|
|
28
|
+
* no rows in a run renders as "no automated check in this engine", which is
|
|
29
|
+
* false the moment the check exists: 3.3.1 and 4.1.3 sat in that list on the
|
|
30
|
+
* first real Eos run while setsquare-status-messages was right there, idle only
|
|
31
|
+
* because no error state was scanned.
|
|
32
|
+
*
|
|
33
|
+
* Lists every check that EXISTS in this build, enabled or not — the ledger's
|
|
34
|
+
* "checks that did not run here" is exactly the right label for a check that
|
|
35
|
+
* exists but was gated off (reading level at an AA target, the AAA pack at AA).
|
|
36
|
+
*/
|
|
37
|
+
export const SETSQUARE_CHECK_CRITERIA = new Map([
|
|
38
|
+
['setsquare-text-spacing', ['1.4.12']],
|
|
39
|
+
['setsquare-status-messages', ['3.3.1', '4.1.3']],
|
|
40
|
+
['setsquare-reading-level', ['3.1.5']],
|
|
41
|
+
['setsquare-target-size-aaa', ['2.5.5']],
|
|
42
|
+
['setsquare-visual-presentation', ['1.4.8']],
|
|
43
|
+
['setsquare-link-purpose', ['2.4.9']],
|
|
44
|
+
]);
|
|
45
|
+
//# sourceMappingURL=versions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versions.js","sourceRoot":"","sources":["../../src/checks/versions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,gCAAgC,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D,OAAO,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAkB;IACvD,MAAM,QAAQ,GAAG,CAAC,gCAAgC,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK;QAAE,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACxE,IAAI,mBAAmB,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACtE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAA2C,IAAI,GAAG,CAAC;IACtF,CAAC,wBAAwB,EAAE,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC,2BAA2B,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC,yBAAyB,EAAE,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC,2BAA2B,EAAE,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC,+BAA+B,EAAE,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC,wBAAwB,EAAE,CAAC,OAAO,CAAC,CAAC;CACtC,CAAC,CAAC"}
|
package/dist/ci.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { RunIngestRequest } from '@setsquare/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Where this run came from.
|
|
4
|
+
*
|
|
5
|
+
* `runSource` and `branch` are not decoration. P2's canonical-run machinery
|
|
6
|
+
* decides which runs drive trend and regression claims, and it decides on these
|
|
7
|
+
* fields — so a run that misreports its branch attaches itself to a history it was
|
|
8
|
+
* never part of, and every "this regressed" claim built on that history is
|
|
9
|
+
* quietly wrong. That is why the rule here is absolute: **detection failures
|
|
10
|
+
* degrade to an explicit "unknown", never to a plausible guess.**
|
|
11
|
+
*
|
|
12
|
+
* "unknown" is unjoinable, which is precisely what makes it safe. A run that
|
|
13
|
+
* cannot say where it came from simply does not participate.
|
|
14
|
+
*/
|
|
15
|
+
export declare const UNKNOWN = "unknown";
|
|
16
|
+
export interface RunOrigin {
|
|
17
|
+
runSource: 'ci' | 'local';
|
|
18
|
+
branch: string;
|
|
19
|
+
commit: string;
|
|
20
|
+
ci?: NonNullable<RunIngestRequest['source']['ci']>;
|
|
21
|
+
/** Which fields could not be determined. Surfaced in the run's own output. */
|
|
22
|
+
unknowns: string[];
|
|
23
|
+
}
|
|
24
|
+
type Env = Record<string, string | undefined>;
|
|
25
|
+
/**
|
|
26
|
+
* Detect the run's origin from the environment, falling back to git.
|
|
27
|
+
*
|
|
28
|
+
* Providers are checked most-specific-first. A GitHub Actions runner also sets
|
|
29
|
+
* the generic `CI=true`, so an ordering that tested the generic case first would
|
|
30
|
+
* report every GitHub run as an unidentified CI with no branch — the fields are
|
|
31
|
+
* there, and we would have thrown them away.
|
|
32
|
+
*/
|
|
33
|
+
export declare function detectOrigin(env?: Env, cwd?: string): RunOrigin;
|
|
34
|
+
export declare function gitBranch(cwd?: string): string;
|
|
35
|
+
export declare function gitCommit(cwd?: string): string;
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=ci.d.ts.map
|
package/dist/ci.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../src/ci.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,OAAO,YAAY,CAAC;AAEjC,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,GAAE,GAAiB,EAAE,GAAG,GAAE,MAAsB,GAAG,SAAS,CAkB3F;AAuJD,wBAAgB,SAAS,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAW7D;AAED,wBAAgB,SAAS,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAE7D"}
|
package/dist/ci.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
/**
|
|
3
|
+
* Where this run came from.
|
|
4
|
+
*
|
|
5
|
+
* `runSource` and `branch` are not decoration. P2's canonical-run machinery
|
|
6
|
+
* decides which runs drive trend and regression claims, and it decides on these
|
|
7
|
+
* fields — so a run that misreports its branch attaches itself to a history it was
|
|
8
|
+
* never part of, and every "this regressed" claim built on that history is
|
|
9
|
+
* quietly wrong. That is why the rule here is absolute: **detection failures
|
|
10
|
+
* degrade to an explicit "unknown", never to a plausible guess.**
|
|
11
|
+
*
|
|
12
|
+
* "unknown" is unjoinable, which is precisely what makes it safe. A run that
|
|
13
|
+
* cannot say where it came from simply does not participate.
|
|
14
|
+
*/
|
|
15
|
+
export const UNKNOWN = 'unknown';
|
|
16
|
+
/**
|
|
17
|
+
* Detect the run's origin from the environment, falling back to git.
|
|
18
|
+
*
|
|
19
|
+
* Providers are checked most-specific-first. A GitHub Actions runner also sets
|
|
20
|
+
* the generic `CI=true`, so an ordering that tested the generic case first would
|
|
21
|
+
* report every GitHub run as an unidentified CI with no branch — the fields are
|
|
22
|
+
* there, and we would have thrown them away.
|
|
23
|
+
*/
|
|
24
|
+
export function detectOrigin(env = process.env, cwd = process.cwd()) {
|
|
25
|
+
const detected = githubActions(env) ?? gitlabCi(env) ?? circleCi(env) ?? genericCi(env);
|
|
26
|
+
if (detected)
|
|
27
|
+
return withUnknowns(detected);
|
|
28
|
+
/*
|
|
29
|
+
* Not CI. Read git, because the local envelope is a product in its own right
|
|
30
|
+
* and "which branch was this?" is the first thing anyone asks of a saved run.
|
|
31
|
+
*
|
|
32
|
+
* Shelling out is a deliberate, bounded choice: one short-lived process, a
|
|
33
|
+
* timeout, and silence on any failure. It is not a network call, and it is what
|
|
34
|
+
* every other developer tool in this space already does.
|
|
35
|
+
*/
|
|
36
|
+
return withUnknowns({
|
|
37
|
+
runSource: 'local',
|
|
38
|
+
branch: gitBranch(cwd),
|
|
39
|
+
commit: gitCommit(cwd),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function withUnknowns(origin) {
|
|
43
|
+
const unknowns = [];
|
|
44
|
+
if (origin.branch === UNKNOWN)
|
|
45
|
+
unknowns.push('branch');
|
|
46
|
+
if (origin.commit === UNKNOWN)
|
|
47
|
+
unknowns.push('commit');
|
|
48
|
+
return { ...origin, unknowns };
|
|
49
|
+
}
|
|
50
|
+
/** Non-empty, or nothing. An empty environment variable is not a value. */
|
|
51
|
+
function value(raw) {
|
|
52
|
+
const trimmed = raw?.trim();
|
|
53
|
+
return trimmed && trimmed.length > 0 ? trimmed : undefined;
|
|
54
|
+
}
|
|
55
|
+
function githubActions(env) {
|
|
56
|
+
if (value(env['GITHUB_ACTIONS']) !== 'true')
|
|
57
|
+
return undefined;
|
|
58
|
+
/*
|
|
59
|
+
* On a `pull_request` event GitHub checks out a MERGE commit that exists
|
|
60
|
+
* nowhere in the repository, and sets:
|
|
61
|
+
*
|
|
62
|
+
* GITHUB_REF_NAME = "123/merge" — not a branch
|
|
63
|
+
* GITHUB_SHA = <merge commit> — not the commit anyone pushed
|
|
64
|
+
* GITHUB_HEAD_REF = <source branch> — the thing a human would name
|
|
65
|
+
*
|
|
66
|
+
* Reporting the first two would file every PR run against a branch called
|
|
67
|
+
* "123/merge" and a commit nobody can check out. P2 joins branch lineage across
|
|
68
|
+
* runs, so that is not cosmetic — it would orphan every PR from its own branch's
|
|
69
|
+
* history.
|
|
70
|
+
*/
|
|
71
|
+
const isPullRequest = value(env['GITHUB_EVENT_NAME'])?.startsWith('pull_request') === true;
|
|
72
|
+
const headRef = value(env['GITHUB_HEAD_REF']);
|
|
73
|
+
const branch = (isPullRequest ? headRef : undefined) ?? value(env['GITHUB_REF_NAME']) ?? UNKNOWN;
|
|
74
|
+
const commit = value(env['GITHUB_SHA']) ?? UNKNOWN;
|
|
75
|
+
const ci = { provider: 'github-actions' };
|
|
76
|
+
const server = value(env['GITHUB_SERVER_URL']);
|
|
77
|
+
const repository = value(env['GITHUB_REPOSITORY']);
|
|
78
|
+
const runId = value(env['GITHUB_RUN_ID']);
|
|
79
|
+
if (server && repository && runId)
|
|
80
|
+
ci.buildUrl = `${server}/${repository}/actions/runs/${runId}`;
|
|
81
|
+
// `refs/pull/123/merge` -> `123`.
|
|
82
|
+
const pullRequest = /refs\/pull\/(\d+)\//.exec(value(env['GITHUB_REF']) ?? '')?.[1];
|
|
83
|
+
if (pullRequest)
|
|
84
|
+
ci.pullRequest = pullRequest;
|
|
85
|
+
return { runSource: 'ci', branch, commit, ci };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* GitLab, detected but not supported.
|
|
89
|
+
*
|
|
90
|
+
* The distinction matters and is deliberate: real GitLab *support* (merge-request
|
|
91
|
+
* comments, pipeline status) is a P7 adapter behind P5's provider interface. What
|
|
92
|
+
* belongs here is recognising the environment so the run is honestly labelled
|
|
93
|
+
* `ci` with a real branch, rather than being mistaken for someone's laptop and
|
|
94
|
+
* quietly excluded from every trend claim.
|
|
95
|
+
*/
|
|
96
|
+
function gitlabCi(env) {
|
|
97
|
+
if (value(env['GITLAB_CI']) !== 'true')
|
|
98
|
+
return undefined;
|
|
99
|
+
const ci = { provider: 'gitlab-ci' };
|
|
100
|
+
const buildUrl = value(env['CI_PIPELINE_URL']);
|
|
101
|
+
if (buildUrl)
|
|
102
|
+
ci.buildUrl = buildUrl;
|
|
103
|
+
const mergeRequest = value(env['CI_MERGE_REQUEST_IID']);
|
|
104
|
+
if (mergeRequest)
|
|
105
|
+
ci.pullRequest = mergeRequest;
|
|
106
|
+
return {
|
|
107
|
+
runSource: 'ci',
|
|
108
|
+
// `CI_COMMIT_REF_NAME` is the branch on a branch pipeline and the source
|
|
109
|
+
// branch on a merge-request pipeline, which is the same distinction GitHub
|
|
110
|
+
// needs `GITHUB_HEAD_REF` for.
|
|
111
|
+
branch: value(env['CI_COMMIT_REF_NAME']) ?? UNKNOWN,
|
|
112
|
+
commit: value(env['CI_COMMIT_SHA']) ?? UNKNOWN,
|
|
113
|
+
ci,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/** CircleCI, on the same detected-not-supported basis as GitLab. */
|
|
117
|
+
function circleCi(env) {
|
|
118
|
+
if (value(env['CIRCLECI']) !== 'true')
|
|
119
|
+
return undefined;
|
|
120
|
+
const ci = { provider: 'circleci' };
|
|
121
|
+
const buildUrl = value(env['CIRCLE_BUILD_URL']);
|
|
122
|
+
if (buildUrl)
|
|
123
|
+
ci.buildUrl = buildUrl;
|
|
124
|
+
const pullRequest = value(env['CIRCLE_PR_NUMBER']);
|
|
125
|
+
if (pullRequest)
|
|
126
|
+
ci.pullRequest = pullRequest;
|
|
127
|
+
return {
|
|
128
|
+
runSource: 'ci',
|
|
129
|
+
branch: value(env['CIRCLE_BRANCH']) ?? UNKNOWN,
|
|
130
|
+
commit: value(env['CIRCLE_SHA1']) ?? UNKNOWN,
|
|
131
|
+
ci,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Some CI we do not recognise.
|
|
136
|
+
*
|
|
137
|
+
* Nearly every CI system sets `CI=true`, so this catches Jenkins, Buildkite,
|
|
138
|
+
* Azure Pipelines, TeamCity and whatever comes next. It reports `runSource: ci`
|
|
139
|
+
* honestly — that much is certain — and declines to invent a branch, because the
|
|
140
|
+
* variable holding it differs per provider and guessing wrong is worse than
|
|
141
|
+
* admitting ignorance.
|
|
142
|
+
*
|
|
143
|
+
* Git still answers, and usually correctly: most CI systems check out a real
|
|
144
|
+
* branch. Where they check out a detached HEAD, `gitBranch` returns unknown
|
|
145
|
+
* rather than the literal string "HEAD".
|
|
146
|
+
*/
|
|
147
|
+
function genericCi(env) {
|
|
148
|
+
const ci = value(env['CI']);
|
|
149
|
+
if (ci !== 'true' && ci !== '1')
|
|
150
|
+
return undefined;
|
|
151
|
+
return {
|
|
152
|
+
runSource: 'ci',
|
|
153
|
+
branch: gitBranch(),
|
|
154
|
+
commit: gitCommit(),
|
|
155
|
+
ci: { provider: UNKNOWN },
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Run a git command, or give up quietly.
|
|
160
|
+
*
|
|
161
|
+
* Bounded on purpose: no shell, a short timeout, and any failure — not a repo, no
|
|
162
|
+
* git installed, a repository so large the call is slow — resolves to nothing.
|
|
163
|
+
* The SDK must never be the reason a suite hangs, and this runs on every single
|
|
164
|
+
* run.
|
|
165
|
+
*/
|
|
166
|
+
function git(args, cwd) {
|
|
167
|
+
try {
|
|
168
|
+
const result = spawnSync('git', args, {
|
|
169
|
+
cwd,
|
|
170
|
+
encoding: 'utf8',
|
|
171
|
+
timeout: 2000,
|
|
172
|
+
// No shell: the arguments are fixed, and a shell would be an injection
|
|
173
|
+
// surface for a directory name.
|
|
174
|
+
shell: false,
|
|
175
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
176
|
+
});
|
|
177
|
+
if (result.status !== 0)
|
|
178
|
+
return undefined;
|
|
179
|
+
return value(result.stdout);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
export function gitBranch(cwd = process.cwd()) {
|
|
186
|
+
const branch = git(['rev-parse', '--abbrev-ref', 'HEAD'], cwd);
|
|
187
|
+
/*
|
|
188
|
+
* A detached HEAD reports the literal string "HEAD", which is not a branch and
|
|
189
|
+
* would collide across every such run in the history. CI systems that check out
|
|
190
|
+
* a commit rather than a branch do this constantly.
|
|
191
|
+
*/
|
|
192
|
+
if (!branch || branch === 'HEAD')
|
|
193
|
+
return UNKNOWN;
|
|
194
|
+
return branch;
|
|
195
|
+
}
|
|
196
|
+
export function gitCommit(cwd = process.cwd()) {
|
|
197
|
+
return git(['rev-parse', 'HEAD'], cwd) ?? UNKNOWN;
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=ci.js.map
|
package/dist/ci.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ci.js","sourceRoot":"","sources":["../src/ci.ts"],"names":[],"mappings":"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"}
|