@webority/repo-checks 0.87.2 → 0.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -6
- package/dist/repo-checks.js +17 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,6 +4,9 @@ Repository checks for Webority React web portals and React Native apps. One comm
|
|
|
4
4
|
app `package.json` in the git repository and reports what the house rules say it must not have,
|
|
5
5
|
must have, and how it must be pinned and installed.
|
|
6
6
|
|
|
7
|
+
It also counts raw measures, raw colours, root font sizes and palette reads in every tracked style,
|
|
8
|
+
markup and script file of the repository (bootstrap-ui.md → Tokens).
|
|
9
|
+
|
|
7
10
|
## Use
|
|
8
11
|
|
|
9
12
|
```bash
|
|
@@ -23,10 +26,44 @@ Anything else (tooling roots, libraries) gets only the lockfile check.
|
|
|
23
26
|
| `bootstrap-version` | Bootstrap other than 5.3.3 |
|
|
24
27
|
| `lockstep:<set>` | Packages that publish together at one version are pinned at different versions |
|
|
25
28
|
| `pnpm:*` | A committed `package-lock.json` or `yarn.lock`, no `pnpm-lock.yaml`, no `packageManager: pnpm@…`, or a `pnpm-workspace.yaml` without `engineStrict: true` and `strictPeerDependencies: true` |
|
|
26
|
-
| `biome:*` | No Biome config, a config that does not extend `@webority/biome-config/biome.jsonc`, a `formatter.lineEnding` or root `linter.rules`, or (mobile) no `__DEV__` global |
|
|
29
|
+
| `biome:*` | No Biome config, a config that does not extend `@webority/biome-config/biome.jsonc`, a `formatter.lineEnding` or root `linter.rules`, or (mobile) no `__DEV__` global, either top-level or in an override whose `includes` cover the app folder |
|
|
27
30
|
| `catalogue-copy:<file>` | A web file under `src/components/` named like a `@webority/ui-react` export |
|
|
31
|
+
| `raw-measure:<file>` | A px, rem or em literal, or a bare number for a weight or a leading, in padding, margin, gap, inset, a corner, font size, font weight or line height. Counted per file. |
|
|
32
|
+
| `raw-colour:<file>` | A hex, an `rgb()` or `hsl()` with numbers, or a CSS named colour in a colour property or style key, where a colour meaning belongs. Counted per file. |
|
|
33
|
+
| `root-font-size:<file>` | A `font-size` or `font` declared on `html` or `:root`. The type scale assumes the browser's root size. Counted per file. |
|
|
34
|
+
| `palette-read:<file>` | A read of a raw palette step (`var(--wui-<step>)`, or a phone `palette.` read) or of a Bootstrap theme colour (`var(--bs-primary)`, `var(--bs-primary-rgb)` or Sass `$primary`, for the eight theme colours), where a colour meaning belongs. The message names the meaning to read. Counted per file. |
|
|
28
35
|
| `hook:drift` | The root `.husky/pre-commit` is missing or differs from the shared hook this package ships (CRLF is ignored) |
|
|
29
36
|
|
|
37
|
+
## Token rules: counted per file
|
|
38
|
+
|
|
39
|
+
The four rules read every tracked `.scss`, `.css`, `.cshtml`, `.jsx` and `.tsx` file, and each `.js` or
|
|
40
|
+
`.ts` file that imports `react-native`. They skip a path with a `node_modules`, `dist`, `generated`,
|
|
41
|
+
`vendor`, `__tests__` or `__mocks__` segment, a path containing `wwwroot/lib/`, a `.generated.` name,
|
|
42
|
+
a `.min.css` name, and a `.test.` or `.spec.` script.
|
|
43
|
+
|
|
44
|
+
`raw-measure` counts a non-zero px, rem or em literal, or a bare number for a weight or a leading, in
|
|
45
|
+
padding, margin, gap, inset, a corner, font size, font weight or line height: one finding per
|
|
46
|
+
declaration or style key. A zero, a keyword (`auto`, `bold`, `normal`), a token
|
|
47
|
+
(`var(--wui-space-md)`), a percentage or another unit, and a custom property or Sass variable
|
|
48
|
+
declaration are not counted.
|
|
49
|
+
|
|
50
|
+
`raw-colour` counts a hex, an `rgb()`, `rgba()`, `hsl()` or `hsla()` with numeric arguments, or a CSS
|
|
51
|
+
named colour, in a colour property or style key (including a fallback inside `var(--color-x, #fff)`).
|
|
52
|
+
`transparent`, `currentColor`, a meaning read, a custom property or Sass variable declaration, and
|
|
53
|
+
text inside a `url()` or a quoted string are not counted.
|
|
54
|
+
|
|
55
|
+
`root-font-size` counts every `font-size` or `font` declaration in a rule whose selector is `html` or
|
|
56
|
+
`:root` (with or without an attribute, class or pseudo-class), whatever its value.
|
|
57
|
+
|
|
58
|
+
`palette-read` counts each `var(--wui-<step>)` and each phone `palette.` read, plus each
|
|
59
|
+
`var(--bs-<colour>)`, `var(--bs-<colour>-rgb)` and Sass `$<colour>` for Bootstrap's eight theme
|
|
60
|
+
colours: one finding per read, and a declaration is not a read.
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
src/assets/styles/_home.scss:12: color: var(--wui-primary);
|
|
64
|
+
(read the meaning: var(--color-primary))
|
|
65
|
+
```
|
|
66
|
+
|
|
30
67
|
## Existing findings: a baseline that only shrinks
|
|
31
68
|
|
|
32
69
|
A repository adopting the checks records what it has today, once:
|
|
@@ -35,12 +72,29 @@ A repository adopting the checks records what it has today, once:
|
|
|
35
72
|
pnpm exec webority-repo-checks --baseline-init
|
|
36
73
|
```
|
|
37
74
|
|
|
38
|
-
That writes `.webority/repo-checks-baseline.json
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
75
|
+
That writes `.webority/repo-checks-baseline.json`: the dependency findings as
|
|
76
|
+
`"<app folder> | <id>"`, and the code rules counted per file:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"version": 2,
|
|
81
|
+
"findings": ["apps/portal | banned:@webority/ui-elements", "samples/react-sandbox | required:@webority/web-core"],
|
|
82
|
+
"counts": { "palette-read:packages/theme/scss/wui/_buttons.scss": 3, "raw-measure:src/assets/styles/_home.scss": 14 }
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
From then on a finding in the baseline is reported as known and does not fail; any other finding
|
|
87
|
+
fails (exit 1). A count may only fall: a file above its recorded count fails and prints its lines,
|
|
88
|
+
and a file missing from the baseline is at 0, so a new or renamed file starts at 0. After fixing old
|
|
89
|
+
findings or lowering counts, `--baseline-shrink` drops the fixed findings and lowers each count to
|
|
90
|
+
its current value, deleting one that reaches 0; it never adds or raises one.
|
|
91
|
+
|
|
92
|
+
`--baseline-init` runs once: it refuses an existing file and folder arguments. When the file is the
|
|
93
|
+
earlier shape (no `version`), delete it and run `--baseline-init` once from the git root, then review
|
|
94
|
+
the diff before committing.
|
|
42
95
|
|
|
43
|
-
`--json` prints `{ root, new, known, stale }` for tools
|
|
96
|
+
`--json` prints `{ root, new, known, stale }` for tools; a count above its record appears in `new`
|
|
97
|
+
with its lines.
|
|
44
98
|
|
|
45
99
|
## The shared pre-commit hook
|
|
46
100
|
|
package/dist/repo-checks.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{chmodSync as e,existsSync as t,mkdirSync as n,readFileSync as r,readdirSync as i,writeFileSync as a}from"node:fs";import{basename as o,dirname as s,
|
|
2
|
+
import{chmodSync as e,existsSync as t,mkdirSync as n,readFileSync as r,readdirSync as i,writeFileSync as a}from"node:fs";import{basename as o,dirname as s,extname as c,join as l,matchesGlob as u,relative as d,resolve as f}from"node:path";import{spawnSync as ee}from"node:child_process";var p=`.webority/repo-checks-baseline.json`,te=[`raw-measure:`,`palette-read:`,`raw-colour:`,`root-font-size:`],m=class extends Error{};function ne(e,t){return`${e} | ${t}`}function h(e){if(typeof e!=`string`)throw new m(`${p} is not a valid version 2 baseline: "findings" must be a list of "<app folder> | <finding id>" strings.`);let t=e.indexOf(` | `);if(t===-1)throw new m(`${p} is not a valid version 2 baseline: "findings" must be a list of "<app folder> | <finding id>" strings.`);return[e.slice(0,t),e.slice(t+3)]}function re(e){let n=l(e,p);if(!t(n))return null;let i;try{i=JSON.parse(r(n,`utf8`))}catch{throw new m(`${p} does not parse.`)}if(typeof i!=`object`||!i||Array.isArray(i)||i.version!==2)throw new m(`${p} has no "version": 2; it is the earlier shape without counts. Delete it and run webority-repo-checks --baseline-init once from the git root, then review and commit the new file.`);for(let e of Object.keys(i))if(e!==`version`&&e!==`findings`&&e!==`counts`)throw new m(`${p} is not a valid version 2 baseline: unknown key "${e}".`);if(!Array.isArray(i.findings))throw new m(`${p} is not a valid version 2 baseline: "findings" must be a list of "<app folder> | <finding id>" strings.`);for(let e of i.findings)if(typeof e!=`string`||!e.includes(` | `))throw new m(`${p} is not a valid version 2 baseline: "findings" must be a list of "<app folder> | <finding id>" strings.`);if(i.counts===null||typeof i.counts!=`object`||Array.isArray(i.counts))throw new m(`${p} is not a valid version 2 baseline: "counts" must be an object of "<rule>:<file>" ids and whole numbers above 0.`);for(let[e,t]of Object.entries(i.counts))if(!te.some(t=>e.startsWith(t))||typeof t!=`number`||!Number.isInteger(t)||t<=0)throw new m(`${p} is not a valid version 2 baseline: count "${e}" must be a raw-measure:, palette-read:, raw-colour: or root-font-size: id with a whole number above 0.`);return{version:2,findings:i.findings,counts:i.counts}}function ie(e,t){let r=l(e,p);n(s(r),{recursive:!0});let i=[...new Set(t.findings??[])].sort(),o={};for(let e of Object.keys(t.counts??{}).sort())o[e]=t.counts[e];a(r,`${JSON.stringify({version:2,findings:i,counts:o},null,4)}\n`)}function ae(e){let t=[...new Set(e.findings??[])].sort(),n={};for(let t of Object.keys(e.counts??{}).sort()){let r=e.counts[t];typeof r==`number`&&r>0&&(n[t]=r)}return{version:2,findings:t,counts:n}}function oe(e,t){if(!t)return e;let n=(e.findings??[]).filter(e=>{let[n]=h(e);return t.pkgs?.has?.(n)??!1}),r={};for(let[n,i]of Object.entries(e.counts??{})){let e=n.indexOf(`:`),a=(e===-1?n:n.slice(e+1)).split(`\\`).join(`/`);(t.dirs??[]).some(e=>{let t=e.split(`\\`).join(`/`);return t===`.`||t===a||a.startsWith(`${t}/`)})&&(r[n]=i)}return{version:2,findings:n,counts:r}}function g(e,t){let n=new Set(e.findings??[]),r=new Set(t.findings??[]),i=[...r].filter(e=>!n.has(e)).sort(),a=[...r].filter(e=>n.has(e)).sort(),o=[...n].filter(e=>!r.has(e)).sort(),s=new Set([...Object.keys(e.counts??{}),...Object.keys(t.counts??{})]),c=[],l=[],u=[];for(let n of[...s].sort()){let r=e.counts?.[n]??0,i=t.counts?.[n]??0,a={id:n,baseline:r,current:i};i>r&&c.push(a),i>0&&i<=r&&l.push(a),r>i&&u.push(a)}return{fresh:i,known:a,stale:o,over:c,within:l,fallen:u}}function se(e,t){let n=new Set(t.findings??[]),r=[...new Set((e.findings??[]).filter(e=>n.has(e)))].sort(),i={};for(let n of Object.keys(e.counts??{}).sort()){let r=e.counts[n],a=t.counts?.[n]??0,o=Math.min(r,a);o>0&&(i[n]=o)}return{version:2,findings:r,counts:i}}var _=`# Fast only. The expensive verification is \`corepack pnpm check\`, run by hand before pushing
|
|
3
3
|
# (CLAUDE.md -> Before pushing). A slow pre-commit gets bypassed within a day, and a hook people bypass is worse than none because
|
|
4
4
|
# it manufactures confidence without providing it.
|
|
5
5
|
#
|
|
@@ -53,7 +53,20 @@ local_checks="$(git rev-parse --show-toplevel)/.husky/pre-commit.local"
|
|
|
53
53
|
if [ -f "$local_checks" ]; then
|
|
54
54
|
sh "$local_checks" || exit 1
|
|
55
55
|
fi
|
|
56
|
-
`;function
|
|
56
|
+
`;function ce(e){let t=``,n=!1;for(let r=0;r<e.length;r+=1){let i=e[r];if(n){t+=i,i===`\\`?(t+=e[r+1]??``,r+=1):i===`"`&&(n=!1);continue}if(i===`"`)n=!0,t+=i;else if(i===`/`&&e[r+1]===`/`){for(;r<e.length&&e[r]!==`
|
|
57
57
|
`;)r+=1;t+=`
|
|
58
|
-
`}else if(i===`/`&&e[r+1]===`*`){for(r+=2;r<e.length&&!(e[r]===`*`&&e[r+1]===`/`);)r+=1;r+=1}else t+=i}return JSON.parse(t.replace(/,(\s*[}\]])/g,`$1`))}var p=[[`eslint`,`react.md: Biome is the only lint and format tool`],[`@eslint/js`,`react.md: Biome is the only lint and format tool`],[`prettier`,`react.md: Biome is the only lint and format tool`],[`lint-staged`,`react.md: the shared pre-commit hook replaces lint-staged`]],m=[[`@typescript-eslint/`,`react.md: no TypeScript toolchain residue`],[`eslint-plugin-`,`react.md: Biome is the only lint and format tool`],[`eslint-config-`,`react.md: Biome is the only lint and format tool`],[`prettier-plugin-`,`react.md: Biome is the only lint and format tool`]],h=`bootstrap-ui.md: hard interactive components come from @webority/ui-react`,g=`react.md: Bootstrap 5.3.3 is the only UI framework`,_=`react.md: dates format through Intl and the web-core formatters`,v=`react-native.md: retired; Intl and the mobile-core formatters`,y={web:[...p,[`typescript`,`react.md: JavaScript only, never TypeScript`],[`sass`,`react.md: the SCSS compiler is sass-embedded, never the pure-JS sass`],[`react-toastify`,`react.md: notifications are toast from @webority/ui-react`],[`downshift`,h],[`react-day-picker`,h],[`react-aria`,h],[`react-aria-components`,h],[`@webority/ui-elements`,`bootstrap-ui.md: products use the App* wrappers, and ui-react brings the elements itself`],[`crypto-js`,`react.md: stored tokens are never encrypted client-side`],[`tailwindcss`,g],[`antd`,g],[`styled-components`,`react.md: no CSS-in-JS`],[`bootstrap-icons`,`bootstrap-ui.md: icons are AppIcon from @webority/ui-react`],[`iconsax-react`,`ui-components.md: icons are AppIcon from @webority/ui-react`],[`moment`,_],[`moment-timezone`,_],[`dayjs`,_],[`date-fns`,_]],mobile:[...p,[`typescript`,`react-native.md: app code is JavaScript`],[`@types/react`,`react-native.md: app code is JavaScript`],[`@react-native/typescript-config`,`react-native.md: app code is JavaScript`],[`react-native-permissions`,`react-native.md: retired; each Expo module requests its own permission`],[`moment`,v],[`moment-timezone`,v],[`dayjs`,v],[`react-native-fast-image`,`react-native.md: retired; expo-image`],[`@d11/react-native-fast-image`,`react-native.md: retired; expo-image`],[`formik`,`react-native.md: retired; react-hook-form`],[`yup`,`react-native.md: retired; zod with zodResolver`],[`react-native-status-bar-height`,`react-native.md: retired; react-native-safe-area-context insets`],[`react-native-flash-message`,`react-native.md: retired; the mobile-ui toast`],[`react-native-toast-message`,`react-native.md: retired; the mobile-ui toast`],[`prop-types`,`react-native.md: retired; defaults in the parameter destructure`],[`@react-navigation/stack`,`react-native.md: retired; @react-navigation/native-stack`],[`react-native-version-check`,`react-native.md: retired; the server-driven minimum version`],[`@react-native-firebase/messaging`,`react-native.md: push is expo-notifications through mobile-core`],[`@notifee/react-native`,`react-native.md: push is expo-notifications through mobile-core`],[`patch-package`,`react-native-toolchain.md: patch with pnpm patch, never patch-package`]],demo:[]},b={web:[...m,[`@mui/`,g],[`@chakra-ui/`,g],[`@emotion/`,`react.md: no CSS-in-JS`],[`@radix-ui/`,h],[`@react-aria/`,h]],mobile:[...m],demo:[]},te={web:[[`axios-retry`,`@webority/web-core`,`react.md: retry lives only in @webority/web-core`]],mobile:[[`axios-retry`,`@webority/mobile-core`,`react.md: retry lives only in @webority/mobile-core`]],demo:[]},ne={web:[[`@biomejs/biome`,`react.md: Biome is mandatory`],[`@webority/biome-config`,`react.md: every repo extends the shared Biome preset`],[`@webority/web-core`,`react.md: clients, auth, errors and logging come from web-core`],[`@webority/ui-react`,`react.md: App* components come from the catalogue`],[`@webority/theme`,`bootstrap-ui.md: look and tokens come from the shared theme`],[`bootstrap`,`bootstrap-ui.md: Bootstrap 5.3.3 on every surface`],[`react-bootstrap`,`bootstrap-ui.md: react-bootstrap is a dependency from project init`],[`sass-embedded`,`react.md: the SCSS compiler is sass-embedded`]],mobile:[[`@biomejs/biome`,`react-native.md: Biome is mandatory`],[`@webority/biome-config`,`react.md: every repo extends the shared Biome preset`],[`@webority/mobile-core`,`react-native.md: apps consume the shared mobile library`],[`@webority/mobile-ui`,`react-native.md: apps consume the shared mobile library`],[`@react-native-firebase/app`,`react-native.md: Crashlytics in every app`],[`@react-native-firebase/crashlytics`,`react-native.md: Crashlytics in every app`]],demo:[[`@biomejs/biome`,`react.md: Biome is mandatory`],[`@webority/biome-config`,`react.md: every repo extends the shared Biome preset`]]},re=`5.3.3`,ie=[[`@webority/theme`,`@webority/ui-elements`,`@webority/ui-react`,`@webority/support-react`,`@webority/chat-react`,`@webority/web-core`,`@webority/biome-config`,`@webority/repo-checks`],[`@webority/mobile-core`,`@webority/mobile-ui`,`@webority/mobile-support`,`@webority/mobile-tools`]],ae=`@webority/biome-config/biome.jsonc`,x=`AppAccordion.AppActionIcon.AppAlert.AppAsyncBlock.AppAutocomplete.AppAvatar.AppAvatarGroup.AppBadge.AppBanner.AppBreadcrumbs.AppButton.AppCard.AppCheckbox.AppChip.AppChoiceCard.AppChoiceChip.AppColorField.AppColumnMenu.AppCommandPalette.AppCompareTable.AppConfirmDialog.AppConsentBanner.AppCopyButton.AppCountrySelect.AppDataTable.AppDatePicker.AppDateRangePicker.AppDescriptions.AppDropdown.AppEmptyState.AppErrorSummary.AppFileAttachment.AppFilePicker.AppFileViewer.AppFloatingDock.AppFormActions.AppFormRow.AppFormSection.AppIcon.AppInfoList.AppInfoTip.AppInput.AppKpiTile.AppLink.AppLogoPicker.AppMeter.AppModal.AppMultiSelect.AppNumberInput.AppOtpInput.AppPageHeader.AppPagination.AppPhoneNumberInput.AppPopover.AppPricingCard.AppProgress.AppQrCode.AppRadio.AppRadioGroup.AppRepeater.AppRequiredMark.AppResourceCard.AppResult.AppScrollbar.AppSearch.AppSegmented.AppSelect.AppSelectMini.AppShell.AppSidebarMenu.AppSkeleton.AppSkeletonRows.AppSlider.AppSpinner.AppSplash.AppStatusBadge.AppStepper.AppSwitch.AppTableEmptyState.AppTablePagination.AppTableToolbar.AppTabs.AppTagInput.AppTextarea.AppThemeToggle.AppTimeline.AppTimePicker.AppToast.AppToolbar.AppTooltip.AppWizard.AppWorkspaceSwitcher`.split(`.`),S=e=>e.split(`\\`).join(`/`),C=(e,t)=>S(l(e,t))||`.`;function w(e){try{return JSON.parse(r(e,`utf8`))}catch{return null}}function T(e,t){let n=ee(`git`,t,{cwd:e,encoding:`utf8`,windowsHide:!0,maxBuffer:64*1024*1024});return n.status===0?n.stdout:null}function oe(e){let t=T(e,[`rev-parse`,`--show-toplevel`]);return t?t.trim():null}function E(e,t){let n=T(e,[`ls-files`,`-z`,`--`,...t.flatMap(e=>[e,`:(glob)**/${e}`])]);return n?[...new Set(n.split(`\0`).filter(Boolean))]:[]}function se(e){let t=e?.dependencies??{};return t[`react-native`]?`mobile`:t[`react-dom`]?e?.devDependencies?.[`react-native-web`]||t[`react-native-web`]?`demo`:`web`:null}var D=e=>/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(e)||/^(?:workspace:\*|file:|link:)/.test(e),O=new Set([`@biomejs/biome`,`@webority/biome-config`]),ce=e=>/^(?:workspace:|file:|link:)/.test(e);function le(e,t,n){let r=[],i={...e.dependencies,...e.devDependencies},a=Object.keys(i);for(let[e,n]of y[t])i[e]&&r.push([`banned:${e}`,`"${e}" is a dependency. ${n}.`]);for(let[e,n]of b[t])for(let t of a.filter(t=>t.startsWith(e)))r.push([`banned:${t}`,`"${t}" is a dependency. ${n}.`]);for(let[e,n,a]of te[t])i[e]&&i[n]&&r.push([`banned:${e}`,`"${e}" is a dependency beside ${n}. ${a}.`]);for(let[e,a]of ne[t])(O.has(e)?n:i)[e]||r.push([`required:${e}`,`"${e}" is not a dependency. ${a}.`]);let o=t===`mobile`?a:a.filter(e=>e.startsWith(`@webority/`)||e===`bootstrap`);for(let e of o){let t=String(i[e]);D(t)||r.push([`not-exact:${e}`,`"${e}": "${t}" is a range. Pin the version the lockfile holds, without ^ or ~.`])}i.bootstrap&&String(i.bootstrap).replace(/^[\^~]/,``)!==`5.3.3`&&r.push([`bootstrap-version`,`bootstrap is "${i.bootstrap}". bootstrap-ui.md: every surface pins ${re}.`]);for(let e of ie){let t=e.filter(e=>i[e]&&!ce(String(i[e])));if(new Set(t.map(e=>String(i[e]).replace(/^[\^~]/,``))).size>1){let n=t.map(e=>`${e}@${i[e]}`).join(`, `);r.push([`lockstep:${e[0]}`,`${n} differ. These publish together at one version; move every pin in the set together.`])}}return r}function k(e,n,r){let i=e;for(;;){for(let e of r)if(t(c(i,e)))return c(i,e);if(i===n)return null;let e=s(i);if(e===i)return null;i=e}}function A(e,t){let n=e,i=null;for(;;){let e=k(n,t,[`biome.json`,`biome.jsonc`]);if(!e)return i;i=s(e);let a;try{a=f(r(e,`utf8`))}catch{return i}let o=s(i);if(a.root!==!1||i===t||o===i)return i;n=o}}function ue(e,t,n){let r=A(e,t),i=r&&r!==e?w(c(r,`package.json`)):null;return i?{...i.dependencies,...i.devDependencies}:n}function de(e,n){let i=[],a=k(e,n,[`pnpm-lock.yaml`]);a||i.push([`pnpm:no-lockfile`,`No pnpm-lock.yaml in this folder or above it. react.md: every JS repo installs with pnpm.`]);let o=a?s(a):e,l=w(c(o,`package.json`))??w(c(e,`package.json`));/^pnpm@/.test(l?.packageManager??``)||i.push([`pnpm:package-manager`,`package.json has no "packageManager": "pnpm@<version>". react.md: Package manager.`]);let u=c(o,`pnpm-workspace.yaml`);if(!t(u))i.push([`pnpm:no-workspace-file`,`No pnpm-workspace.yaml beside the lockfile. react.md: it holds engineStrict, strictPeerDependencies and allowBuilds.`]);else{let e=r(u,`utf8`);/^engineStrict:\s*true\s*$/m.test(e)||i.push([`pnpm:engine-strict`,`pnpm-workspace.yaml lacks engineStrict: true. react.md: a Node mismatch must fail the install.`]),/^strictPeerDependencies:\s*true\s*$/m.test(e)||i.push([`pnpm:strict-peers`,`pnpm-workspace.yaml lacks strictPeerDependencies: true. react.md: a peer conflict must fail the install.`])}for(let n of[`package-lock.json`,`yarn.lock`])t(c(e,n))&&i.push([`pnpm:${n}`,`${n} sits in this folder. react.md: pnpm only; seed pnpm-lock.yaml with pnpm import, then delete it.`]);return i}function fe(e,t,n){let i=k(e,t,[`biome.json`,`biome.jsonc`]);if(!i)return[[`biome:missing`,`No biome.json in this folder or above it. react.md: one committed root biome.json.`]];let a;try{a=f(r(i,`utf8`))}catch{return[[`biome:unreadable`,`${o(i)} does not parse.`]]}let s=[];return[].concat(a.extends??[]).some(e=>e===`@webority/biome-config/biome.jsonc`||String(e).endsWith(`biome-config/biome.jsonc`))||s.push([`biome:extends`,`${o(i)} does not extend "${ae}". react.md: every repo extends the shared preset.`]),a.formatter?.lineEnding&&s.push([`biome:line-ending`,`${o(i)} sets formatter.lineEnding. react.md: inherit it from the shared preset, never set it.`]),a.linter?.rules&&Object.keys(a.linter.rules).length>0&&s.push([`biome:root-rules`,`${o(i)} sets linter.rules at the root. react.md: never a rule's severity at the root; a per-path exception goes in overrides.`]),n===`mobile`&&!(a.javascript?.globals??[]).includes(`__DEV__`)&&s.push([`biome:dev-global`,`${o(i)} lacks "__DEV__" in javascript.globals. react-native.md: Debugging and agent access.`]),s}function pe(e){let t=c(e,`node_modules`,`@webority`,`ui-react`);try{let e=JSON.parse(r(c(t,`package.json`),`utf8`)),n=r(c(t,typeof e.module==`string`?e.module:typeof e.main==`string`?e.main:`dist/index.js`),`utf8`),i=new Set([...n.matchAll(/App[A-Z][A-Za-z0-9]*/g)].map(e=>e[0]));if(i.size>0)return i}catch{}return new Set(x)}function j(e){return i(e,{withFileTypes:!0}).flatMap(t=>t.isDirectory()?j(c(e,t.name)):[c(e,t.name)])}function me(e){let n=c(e,`src`,`components`);if(!t(n))return[];let r=pe(e),i=[];for(let t of j(n)){let n=o(t).split(`.`)[0];if(r.has(n)){let r=S(l(e,t));i.push([`catalogue-copy:${r}`,`${r} is named like the @webority/ui-react export ${n}. bootstrap-ui.md: use the catalogue component, never a local copy.`])}}return i}var M=`.husky/pre-commit`;function N(e){if(t(c(e,`.github/workflows/production.yml`)))return[];let n=c(e,M),i=t(n)?r(n,`utf8`).replace(/\r\n/g,`
|
|
59
|
-
`):null;return i===d?[]:[[`hook:drift`,`${M} ${i===null?`is missing`:`differs from the shared hook`}. Run pnpm exec webority-repo-checks --sync-hook from the git root; repo-only steps go in .husky/pre-commit.local.`]]}function P(e,n=null){let r=n?new Set(n.map(t=>C(e,t))):null,i=[],a=(e,t)=>{for(let[n,r]of t)i.push({pkg:e,id:n,message:r})};(!r||r.has(`.`))&&a(`.`,N(e));for(let n of E(e,[`package-lock.json`,`yarn.lock`])){if(!t(c(e,n)))continue;let i=S(s(n))||`.`;r&&!r.has(i)||a(i,[[`pnpm:${o(n)}`,`${o(n)} is committed. react.md: pnpm only; seed pnpm-lock.yaml with pnpm import, then delete it.`]])}let l=new Set(E(e,[`package.json`]).map(t=>C(e,c(e,s(t)))));for(let n of r??[])t(c(e,n,`package.json`))&&l.add(n);for(let t of l){if(r&&!r.has(t))continue;let n=c(e,t),o=w(c(n,`package.json`)),s=se(o);if(!s)continue;let l=de(n,e).filter(([e])=>!i.some(n=>n.pkg===t&&n.id===e));a(t,[...le(o,s,ue(n,e,{...o.dependencies,...o.devDependencies})),...l,...fe(n,e,s),...s===`web`?me(n):[]])}return i}var F=`.webority/repo-checks-baseline.json`,I=process.argv.slice(2),L=new Set(I.filter(e=>e.startsWith(`--`))),R=I.filter(e=>!e.startsWith(`--`)),z=L.has(`--sync-hook`),B=e=>process.stdout.write(`${e}\n`),V=e=>process.stderr.write(`${e}\n`),he=new Set([`--json`,`--baseline-init`,`--baseline-shrink`,`--sync-hook`]),H=[...L].filter(e=>!he.has(e));(H.length||L.has(`--baseline-init`)&&L.has(`--baseline-shrink`)||z&&(L.size>1||R.length))&&(V(`repo-checks: unknown or conflicting options ${H.join(` `)}`.trim()),V(`usage: webority-repo-checks [--json] [--baseline-init | --baseline-shrink] [app folder ...]`),V(` webority-repo-checks --sync-hook`),process.exit(2));var U=oe(process.cwd());if(U||(V(`repo-checks: not inside a git repository.`),process.exit(2)),z){let t=c(U,M);n(s(t),{recursive:!0}),a(t,d),e(t,493),B(`repo-checks: wrote ${t}`),process.exit(0)}var W=P(U,R.length?R.map(e=>u(process.cwd(),e)):null).sort((e,t)=>e.pkg===t.pkg?0:e.pkg<t.pkg?-1:1),G=e=>`${e.pkg}\t${e.id}`,K=c(U,F);function ge(){if(!t(K))return null;try{return JSON.parse(r(K,`utf8`))}catch{V(`repo-checks: ${F} does not parse.`),process.exit(2)}}function q(e){let t={};for(let[n,r]of e.map(e=>e.split(` `)).sort())(t[n]??=[]).push(r);n(s(K),{recursive:!0}),a(K,`${JSON.stringify(t,null,4)}\n`)}var J=ge(),Y=new Set(Object.entries(J??{}).flatMap(([e,t])=>t.map(t=>`${e}\t${t}`)));L.has(`--baseline-init`)&&(J&&(V(`repo-checks: ${F} already exists. It only shrinks: fix a new finding, or run --baseline-shrink after fixing old ones.`),process.exit(2)),q(W.map(G)),B(`repo-checks: recorded ${W.length} existing finding(s) in ${F}.`),process.exit(0));var X=new Set(W.map(G)),_e=new Set(R.map(e=>l(U,u(process.cwd(),e)).split(`\\`).join(`/`)||`.`)),ve=e=>!R.length||_e.has(e.split(` `)[0]),Z=[...Y].filter(e=>!X.has(e)&&ve(e));L.has(`--baseline-shrink`)&&(J||(V(`repo-checks: no ${F} to shrink.`),process.exit(2)),R.length&&(V(`repo-checks: --baseline-shrink reads the whole repository; run it without folder arguments.`),process.exit(2)),q([...Y].filter(e=>X.has(e))),B(`repo-checks: dropped ${Z.length} fixed entr${Z.length===1?`y`:`ies`} from ${F}.`),process.exit(0));var Q=W.filter(e=>!Y.has(G(e))),$=W.filter(e=>Y.has(G(e)));if(L.has(`--json`)&&(B(JSON.stringify({root:U,new:Q,known:$,stale:Z.map(e=>e.split(` `))},null,2)),process.exit(+!!Q.length)),Q.length){V(`repo-checks: ${Q.length} new finding(s)`);let e=null;for(let t of Q)t.pkg!==e&&(e=t.pkg,V(` ${e}`)),V(` - ${t.id}: ${t.message}`)}else B(`repo-checks: no new findings.`);if($.length&&B(`repo-checks: ${$.length} known finding(s) recorded in ${F}.`),Z.length){B(`repo-checks: ${Z.length} baseline entr${Z.length===1?`y is`:`ies are`} fixed; drop them with webority-repo-checks --baseline-shrink:`);for(let e of Z)B(` ${e.replace(` `,` `)}`)}process.exit(+!!Q.length);export{};
|
|
58
|
+
`}else if(i===`/`&&e[r+1]===`*`){for(r+=2;r<e.length&&!(e[r]===`*`&&e[r+1]===`/`);)r+=1;r+=1}else t+=i}return JSON.parse(t.replace(/,(\s*[}\]])/g,`$1`))}var le=[[`eslint`,`react.md: Biome is the only lint and format tool`],[`@eslint/js`,`react.md: Biome is the only lint and format tool`],[`prettier`,`react.md: Biome is the only lint and format tool`],[`lint-staged`,`react.md: the shared pre-commit hook replaces lint-staged`]],ue=[[`@typescript-eslint/`,`react.md: no TypeScript toolchain residue`],[`eslint-plugin-`,`react.md: Biome is the only lint and format tool`],[`eslint-config-`,`react.md: Biome is the only lint and format tool`],[`prettier-plugin-`,`react.md: Biome is the only lint and format tool`]],v=`bootstrap-ui.md: hard interactive components come from @webority/ui-react`,y=`react.md: Bootstrap 5.3.3 is the only UI framework`,b=`react.md: dates format through Intl and the web-core formatters`,x=`react-native.md: retired; Intl and the mobile-core formatters`,de={web:[...le,[`typescript`,`react.md: JavaScript only, never TypeScript`],[`sass`,`react.md: the SCSS compiler is sass-embedded, never the pure-JS sass`],[`react-toastify`,`react.md: notifications are toast from @webority/ui-react`],[`downshift`,v],[`react-day-picker`,v],[`react-aria`,v],[`react-aria-components`,v],[`@webority/ui-elements`,`bootstrap-ui.md: products use the App* wrappers, and ui-react brings the elements itself`],[`crypto-js`,`react.md: stored tokens are never encrypted client-side`],[`tailwindcss`,y],[`antd`,y],[`styled-components`,`react.md: no CSS-in-JS`],[`bootstrap-icons`,`bootstrap-ui.md: icons are AppIcon from @webority/ui-react`],[`iconsax-react`,`ui-components.md: icons are AppIcon from @webority/ui-react`],[`moment`,b],[`moment-timezone`,b],[`dayjs`,b],[`date-fns`,b]],mobile:[...le,[`typescript`,`react-native.md: app code is JavaScript`],[`@types/react`,`react-native.md: app code is JavaScript`],[`@react-native/typescript-config`,`react-native.md: app code is JavaScript`],[`react-native-permissions`,`react-native.md: retired; each Expo module requests its own permission`],[`moment`,x],[`moment-timezone`,x],[`dayjs`,x],[`react-native-fast-image`,`react-native.md: retired; expo-image`],[`@d11/react-native-fast-image`,`react-native.md: retired; expo-image`],[`formik`,`react-native.md: retired; react-hook-form`],[`yup`,`react-native.md: retired; zod with zodResolver`],[`react-native-status-bar-height`,`react-native.md: retired; react-native-safe-area-context insets`],[`react-native-flash-message`,`react-native.md: retired; the mobile-ui toast`],[`react-native-toast-message`,`react-native.md: retired; the mobile-ui toast`],[`prop-types`,`react-native.md: retired; defaults in the parameter destructure`],[`@react-navigation/stack`,`react-native.md: retired; @react-navigation/native-stack`],[`react-native-version-check`,`react-native.md: retired; the server-driven minimum version`],[`@react-native-firebase/messaging`,`react-native.md: push is expo-notifications through mobile-core`],[`@notifee/react-native`,`react-native.md: push is expo-notifications through mobile-core`],[`patch-package`,`react-native-toolchain.md: patch with pnpm patch, never patch-package`]],demo:[]},fe={web:[...ue,[`@mui/`,y],[`@chakra-ui/`,y],[`@emotion/`,`react.md: no CSS-in-JS`],[`@radix-ui/`,v],[`@react-aria/`,v]],mobile:[...ue],demo:[]},pe={web:[[`axios-retry`,`@webority/web-core`,`react.md: retry lives only in @webority/web-core`]],mobile:[[`axios-retry`,`@webority/mobile-core`,`react.md: retry lives only in @webority/mobile-core`]],demo:[]},me={web:[[`@biomejs/biome`,`react.md: Biome is mandatory`],[`@webority/biome-config`,`react.md: every repo extends the shared Biome preset`],[`@webority/web-core`,`react.md: clients, auth, errors and logging come from web-core`],[`@webority/ui-react`,`react.md: App* components come from the catalogue`],[`@webority/theme`,`bootstrap-ui.md: look and tokens come from the shared theme`],[`bootstrap`,`bootstrap-ui.md: Bootstrap 5.3.3 on every surface`],[`react-bootstrap`,`bootstrap-ui.md: react-bootstrap is a dependency from project init`],[`sass-embedded`,`react.md: the SCSS compiler is sass-embedded`]],mobile:[[`@biomejs/biome`,`react-native.md: Biome is mandatory`],[`@webority/biome-config`,`react.md: every repo extends the shared Biome preset`],[`@webority/mobile-core`,`react-native.md: apps consume the shared mobile library`],[`@webority/mobile-ui`,`react-native.md: apps consume the shared mobile library`],[`@react-native-firebase/app`,`react-native.md: Crashlytics in every app`],[`@react-native-firebase/crashlytics`,`react-native.md: Crashlytics in every app`]],demo:[[`@biomejs/biome`,`react.md: Biome is mandatory`],[`@webority/biome-config`,`react.md: every repo extends the shared Biome preset`]]},he=`5.3.3`,ge=[[`@webority/theme`,`@webority/ui-elements`,`@webority/ui-react`,`@webority/support-react`,`@webority/chat-react`,`@webority/web-core`,`@webority/biome-config`,`@webority/repo-checks`],[`@webority/mobile-core`,`@webority/mobile-ui`,`@webority/mobile-support`,`@webority/mobile-tools`]],_e=`@webority/biome-config/biome.jsonc`,ve=`AppAccordion.AppActionIcon.AppAlert.AppAsyncBlock.AppAutocomplete.AppAvatar.AppAvatarGroup.AppBadge.AppBanner.AppBreadcrumbs.AppButton.AppCard.AppCheckbox.AppChip.AppChoiceCard.AppChoiceChip.AppColorField.AppColumnMenu.AppCommandPalette.AppCompareTable.AppConfirmDialog.AppConsentBanner.AppCopyButton.AppCountrySelect.AppDataTable.AppDatePicker.AppDateRangePicker.AppDescriptions.AppDropdown.AppEmptyState.AppErrorSummary.AppFileAttachment.AppFilePicker.AppFileViewer.AppFloatingDock.AppFormActions.AppFormRow.AppFormSection.AppIcon.AppInfoList.AppInfoTip.AppInput.AppKpiTile.AppLink.AppLogoPicker.AppMeter.AppModal.AppMultiSelect.AppNumberInput.AppOtpInput.AppPageHeader.AppPagination.AppPhoneNumberInput.AppPopover.AppPricingCard.AppProgress.AppQrCode.AppRadio.AppRadioGroup.AppRepeater.AppRequiredMark.AppResourceCard.AppResult.AppScrollbar.AppSearch.AppSegmented.AppSelect.AppSelectMini.AppShell.AppSidebarMenu.AppSkeleton.AppSkeletonRows.AppSlider.AppSpinner.AppSplash.AppStatusBadge.AppStepper.AppSwitch.AppTableEmptyState.AppTablePagination.AppTableToolbar.AppTabs.AppTagInput.AppTextarea.AppThemeToggle.AppTimeline.AppTimePicker.AppToast.AppToolbar.AppTooltip.AppWizard.AppWorkspaceSwitcher`.split(`.`),S=e=>e.split(`\\`).join(`/`),C=(e,t)=>S(d(e,t))||`.`;function w(e){try{return JSON.parse(r(e,`utf8`))}catch{return null}}function ye(e,t){let n=ee(`git`,t,{cwd:e,encoding:`utf8`,windowsHide:!0,maxBuffer:64*1024*1024});return n.status===0?n.stdout:null}function be(e){let t=ye(e,[`rev-parse`,`--show-toplevel`]);return t?t.trim():null}function T(e,t){let n=ye(e,[`ls-files`,`-z`,`--`,...t.flatMap(e=>[e,`:(glob)**/${e}`])]);return n?[...new Set(n.split(`\0`).filter(Boolean))]:[]}function xe(e){let t=e?.dependencies??{};return t[`react-native`]?`mobile`:t[`react-dom`]?e?.devDependencies?.[`react-native-web`]||t[`react-native-web`]?`demo`:`web`:null}var Se=e=>/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(e)||/^(?:workspace:\*|file:|link:)/.test(e),Ce=new Set([`@biomejs/biome`,`@webority/biome-config`]),we=e=>/^(?:workspace:|file:|link:)/.test(e);function Te(e,t,n){let r=[],i={...e.dependencies,...e.devDependencies},a=Object.keys(i);for(let[e,n]of de[t])i[e]&&r.push([`banned:${e}`,`"${e}" is a dependency. ${n}.`]);for(let[e,n]of fe[t])for(let t of a.filter(t=>t.startsWith(e)))r.push([`banned:${t}`,`"${t}" is a dependency. ${n}.`]);for(let[e,n,a]of pe[t])i[e]&&i[n]&&r.push([`banned:${e}`,`"${e}" is a dependency beside ${n}. ${a}.`]);for(let[e,a]of me[t])(Ce.has(e)?n:i)[e]||r.push([`required:${e}`,`"${e}" is not a dependency. ${a}.`]);let o=t===`mobile`?a:a.filter(e=>e.startsWith(`@webority/`)||e===`bootstrap`);for(let e of o){let t=String(i[e]);Se(t)||r.push([`not-exact:${e}`,`"${e}": "${t}" is a range. Pin the version the lockfile holds, without ^ or ~.`])}i.bootstrap&&String(i.bootstrap).replace(/^[\^~]/,``)!==`5.3.3`&&r.push([`bootstrap-version`,`bootstrap is "${i.bootstrap}". bootstrap-ui.md: every surface pins ${he}.`]);for(let e of ge){let t=e.filter(e=>i[e]&&!we(String(i[e])));if(new Set(t.map(e=>String(i[e]).replace(/^[\^~]/,``))).size>1){let n=t.map(e=>`${e}@${i[e]}`).join(`, `);r.push([`lockstep:${e[0]}`,`${n} differ. These publish together at one version; move every pin in the set together.`])}}return r}function E(e,n,r){let i=e;for(;;){for(let e of r)if(t(l(i,e)))return l(i,e);if(i===n)return null;let e=s(i);if(e===i)return null;i=e}}function Ee(e,t){let n=e,i=null;for(;;){let e=E(n,t,[`biome.json`,`biome.jsonc`]);if(!e)return i;i=s(e);let a;try{a=ce(r(e,`utf8`))}catch{return i}let o=s(i);if(a.root!==!1||i===t||o===i)return i;n=o}}function De(e,t,n){let r=Ee(e,t),i=r&&r!==e?w(l(r,`package.json`)):null;return i?{...i.dependencies,...i.devDependencies}:n}function Oe(e,n){let i=[],a=E(e,n,[`pnpm-lock.yaml`]);a||i.push([`pnpm:no-lockfile`,`No pnpm-lock.yaml in this folder or above it. react.md: every JS repo installs with pnpm.`]);let o=a?s(a):e,c=w(l(o,`package.json`))??w(l(e,`package.json`));/^pnpm@/.test(c?.packageManager??``)||i.push([`pnpm:package-manager`,`package.json has no "packageManager": "pnpm@<version>". react.md: Package manager.`]);let u=l(o,`pnpm-workspace.yaml`);if(!t(u))i.push([`pnpm:no-workspace-file`,`No pnpm-workspace.yaml beside the lockfile. react.md: it holds engineStrict, strictPeerDependencies and allowBuilds.`]);else{let e=r(u,`utf8`);/^engineStrict:\s*true\s*$/m.test(e)||i.push([`pnpm:engine-strict`,`pnpm-workspace.yaml lacks engineStrict: true. react.md: a Node mismatch must fail the install.`]),/^strictPeerDependencies:\s*true\s*$/m.test(e)||i.push([`pnpm:strict-peers`,`pnpm-workspace.yaml lacks strictPeerDependencies: true. react.md: a peer conflict must fail the install.`])}for(let n of[`package-lock.json`,`yarn.lock`])t(l(e,n))&&i.push([`pnpm:${n}`,`${n} sits in this folder. react.md: pnpm only; seed pnpm-lock.yaml with pnpm import, then delete it.`]);return i}function ke(e,t,n,r){if((e.javascript?.globals??[]).includes(r))return!0;let i=S(d(t,l(n,`index.js`)));return(e.overrides??[]).some(e=>(e.javascript?.globals??[]).includes(r)&&[].concat(e.includes??[]).some(e=>!String(e).startsWith(`!`)&&u(i,String(e))))}function Ae(e,t,n){let i=E(e,t,[`biome.json`,`biome.jsonc`]);if(!i)return[[`biome:missing`,`No biome.json in this folder or above it. react.md: one committed root biome.json.`]];let a;try{a=ce(r(i,`utf8`))}catch{return[[`biome:unreadable`,`${o(i)} does not parse.`]]}let c=[];return[].concat(a.extends??[]).some(e=>e===`@webority/biome-config/biome.jsonc`||String(e).endsWith(`biome-config/biome.jsonc`))||c.push([`biome:extends`,`${o(i)} does not extend "${_e}". react.md: every repo extends the shared preset.`]),a.formatter?.lineEnding&&c.push([`biome:line-ending`,`${o(i)} sets formatter.lineEnding. react.md: inherit it from the shared preset, never set it.`]),a.linter?.rules&&Object.keys(a.linter.rules).length>0&&c.push([`biome:root-rules`,`${o(i)} sets linter.rules at the root. react.md: never a rule's severity at the root; a per-path exception goes in overrides.`]),n===`mobile`&&!ke(a,s(i),e,`__DEV__`)&&c.push([`biome:dev-global`,`${o(i)} lacks "__DEV__" in javascript.globals. react-native.md: Debugging and agent access.`]),c}function je(e){let t=l(e,`node_modules`,`@webority`,`ui-react`);try{let e=JSON.parse(r(l(t,`package.json`),`utf8`)),n=r(l(t,typeof e.module==`string`?e.module:typeof e.main==`string`?e.main:`dist/index.js`),`utf8`),i=new Set([...n.matchAll(/App[A-Z][A-Za-z0-9]*/g)].map(e=>e[0]));if(i.size>0)return i}catch{}return new Set(ve)}function D(e){return i(e,{withFileTypes:!0}).flatMap(t=>t.isDirectory()?D(l(e,t.name)):[l(e,t.name)])}function Me(e){let n=l(e,`src`,`components`);if(!t(n))return[];let r=je(e),i=[];for(let t of D(n)){let n=o(t).split(`.`)[0];if(r.has(n)){let r=S(d(e,t));i.push([`catalogue-copy:${r}`,`${r} is named like the @webority/ui-react export ${n}. bootstrap-ui.md: use the catalogue component, never a local copy.`])}}return i}var O=`.husky/pre-commit`;function Ne(e){if(t(l(e,`.github/workflows/production.yml`)))return[];let n=l(e,O),i=t(n)?r(n,`utf8`).replace(/\r\n/g,`
|
|
59
|
+
`):null;return i===_?[]:[[`hook:drift`,`${O} ${i===null?`is missing`:`differs from the shared hook`}. Run pnpm exec webority-repo-checks --sync-hook from the git root; repo-only steps go in .husky/pre-commit.local.`]]}function Pe(e,n=null){let r=n?new Set(n.map(t=>C(e,t))):null,i=[],a=(e,t)=>{for(let[n,r]of t)i.push({pkg:e,id:n,message:r})};(!r||r.has(`.`))&&a(`.`,Ne(e));for(let n of T(e,[`package-lock.json`,`yarn.lock`])){if(!t(l(e,n)))continue;let i=S(s(n))||`.`;r&&!r.has(i)||a(i,[[`pnpm:${o(n)}`,`${o(n)} is committed. react.md: pnpm only; seed pnpm-lock.yaml with pnpm import, then delete it.`]])}let c=new Set(T(e,[`package.json`]).map(t=>C(e,l(e,s(t)))));for(let n of r??[])t(l(e,n,`package.json`))&&c.add(n);for(let t of c){if(r&&!r.has(t))continue;let n=l(e,t),o=w(l(n,`package.json`)),s=xe(o);if(!s)continue;let c=Oe(n,e).filter(([e])=>!i.some(n=>n.pkg===t&&n.id===e));a(t,[...Te(o,s,De(n,e,{...o.dependencies,...o.devDependencies})),...c,...Ae(n,e,s),...s===`web`?Me(n):[]])}return i}var k=[``,`-top`,`-right`,`-bottom`,`-left`,`-inline`,`-inline-start`,`-inline-end`,`-block`,`-block-start`,`-block-end`],A=[...k.map(e=>`padding${e}`),...k.map(e=>`margin${e}`),`gap`,`row-gap`,`column-gap`,`grid-gap`,`grid-row-gap`,`grid-column-gap`,`inset`,`inset-inline`,`inset-inline-start`,`inset-inline-end`,`inset-block`,`inset-block-start`,`inset-block-end`,`border-radius`,`border-top-left-radius`,`border-top-right-radius`,`border-bottom-right-radius`,`border-bottom-left-radius`,`border-start-start-radius`,`border-start-end-radius`,`border-end-start-radius`,`border-end-end-radius`,`font`,`font-size`,`font-weight`,`line-height`],Fe=[`font`,`font-weight`,`line-height`],Ie=e=>e.replace(/-([a-z])/g,(e,t)=>t.toUpperCase()),Le=[...A.map(Ie),`paddingHorizontal`,`paddingVertical`,`paddingStart`,`paddingEnd`,`marginHorizontal`,`marginVertical`,`marginStart`,`marginEnd`,`borderTopStartRadius`,`borderTopEndRadius`,`borderBottomStartRadius`,`borderBottomEndRadius`],Re=[`color`,`background`,`background-color`,`border`,`border-color`,...[`top`,`right`,`bottom`,`left`,`inline`,`inline-start`,`inline-end`,`block`,`block-start`,`block-end`].flatMap(e=>[`border-${e}`,`border-${e}-color`]),`outline`,`outline-color`,`fill`,`stroke`,`box-shadow`,`text-shadow`,`text-decoration-color`,`caret-color`,`accent-color`,`column-rule-color`],j=[...Re.map(Ie),`shadowColor`,`tintColor`],ze=[`px`,`rem`,`em`],M={primary:`primary`,secondary:`neutral`,success:`success`,info:`info`,warning:`warning`,danger:`danger`,light:`bg-subtle`,dark:`surface-inverse`},Be={".scss":`scss`,".css":`css`,".cshtml":`markup`,".jsx":`script`,".tsx":`script`,".js":`script`,".ts":`script`},Ve=[`.js`,`.ts`],He=[`node_modules`,`dist`,`generated`,`vendor`,`__tests__`,`__mocks__`],Ue=[`wwwroot/lib/`],We=`bootstrap-ui.md → Tokens: padding, margin, gap, inset, corners, font size, font weight and line height read a space, radius, text, weight or leading token, never a literal.`,Ge=`bootstrap-ui.md → Tokens: a colour is a meaning (var(--color-*) on web, theme.colors["<name>"] on phone), never a hex, rgb(), hsl() or named colour; a product-only colour goes into theme/brand.tokens.json.`,Ke=`bootstrap-ui.md → Tokens: the root font size (html or :root) is the unit the type scale is measured in; never set it.`,qe=`bootstrap-ui.md → Tokens: code reads the colour meaning layer (var(--color-*) on web, theme.colors["<name>"] on phone), never a palette step or a Bootstrap theme colour.`,Je={color:JSON.parse(`{"$type":"color","bg":{"$value":"{palette.bg-page}","$description":"Page background behind the content area."},"bg-subtle":{"$value":"{palette.bg-elevated}","$description":"Subtle raised background for side panels and bands."},"bg-muted":{"$value":"{palette.bg-muted}","$description":"Muted background for grouped areas and quiet controls."},"surface":{"$value":"{palette.bg-light}","$description":"Card and panel surface."},"surface-inverse":{"$value":"{palette.text-heading}","$description":"Inverse band on a page, such as a dark footer or an inverse toast."},"surface-inverse-raised":{"$value":"color-mix(in srgb, {color.text-inverse} 5%, {color.surface-inverse})","$description":"A card or panel one layer up on an inverse band.","$extensions":{"com.webority":{"platforms":["web"]}}},"surface-inverse-elevated":{"$value":"color-mix(in srgb, {color.text-inverse} 9%, {color.surface-inverse})","$description":"A floating or highlighted surface two layers up on an inverse band.","$extensions":{"com.webority":{"platforms":["web"]}}},"text":{"$value":"{palette.text-heading}","$description":"Main heading and body ink."},"text-body":{"$value":"{palette.text-1}","$description":"Body copy on a tinted surface such as an alert body."},"text-muted":{"$value":"{palette.text-2}","$description":"Secondary text for descriptions and muted copy."},"text-subtle":{"$value":"{palette.text-3}","$description":"Tertiary text for hints, captions, timestamps and placeholders."},"text-inverse":{"$value":"{palette.bg-light}","$description":"Text on an inverse surface."},"link":{"$value":"{palette.primary-ink}","$description":"Interactive link text."},"border":{"$value":"{palette.border-light}","$description":"Hairline border of cards, tables and dividers."},"border-subtle":{"$value":"{palette.border-soft}","$description":"Softest border for inner dividers and list edges."},"border-strong":{"$value":"{palette.border-strong}","$description":"Stronger border for emphasised separators, chart axes and unselected control outlines.","$extensions":{"com.webority":{"platforms":["web"]}}},"field-bg":{"$value":"{palette.field-bg}","$description":"Resting fill of input-like controls such as fields and selects."},"field-border":{"$value":"{palette.field-border}","$description":"Resting border of an input-like control such as a field or select."},"field-border-hover":{"$value":"{palette.field-border-hover}","$description":"Hover border of an input-like control.","$extensions":{"com.webority":{"platforms":["web"]}}},"field-border-focus":{"$value":"{palette.primary-30}","$description":"Border of a focused, open or active control such as an input or select."},"focus-ring":{"$value":"{color.primary-text}","$description":"Colour of the keyboard focus ring drawn on focus-visible controls."},"scrim":{"$value":"color-mix(in srgb, {palette.text-heading} 45%, transparent)","$description":"Dim behind page-level backdrops such as drawers, modals and the shell."},"scrim-strong":{"$value":"color-mix(in srgb, {palette.text-heading} 62%, transparent)","$description":"Stronger dim behind media overlays that carry white ink.","$extensions":{"com.webority":{"platforms":["web"]}}},"on-scrim":{"$value":"{palette.bg-light}","$description":"Ink on a scrim, such as the text of an overlay."},"progress-track":{"$value":"{palette.progress-track}","$description":"Unfilled track of a progress bar or meter.","$extensions":{"com.webority":{"platforms":["web"]}}},"progress-label":{"$value":"{palette.bg-light}","$description":"Label text inside a progress bar fill.","$extensions":{"com.webority":{"platforms":["web"]}}},"thumb":{"$value":"{palette.bg-light}","$description":"Raised thumb that marks the selected option of a segmented control.","$extensions":{"com.webority":{"platforms":["web"]}}},"scrollbar":{"$value":"{palette.scrollbar}","$description":"Resting thumb colour of a thin scrollbar.","$extensions":{"com.webority":{"platforms":["web"]}}},"scrollbar-hover":{"$value":"{palette.scrollbar-hover}","$description":"Scrollbar thumb colour while it is hovered.","$extensions":{"com.webority":{"platforms":["web"]}}},"scrollbar-active":{"$value":"{palette.scrollbar-active}","$description":"Scrollbar thumb colour while it is dragged.","$extensions":{"com.webority":{"platforms":["web"]}}},"primary":{"$value":"{palette.primary}","$description":"Primary fill for buttons, selected states and borders."},"primary-hover":{"$value":"{palette.primary-pressed}","$description":"Primary fill while a control is hovered or pressed."},"primary-soft":{"$value":"{palette.primary-10}","$description":"Soft primary tint behind selected and highlighted rows."},"primary-text":{"$value":"{palette.primary-ink}","$description":"Primary as text and small glyphs on a page, passing AA contrast."},"on-primary":{"$value":"{palette.primary-text}","$description":"Text and icon colour on a solid primary fill."},"primary-wash":{"$value":"color-mix(in srgb, {color.primary} 8%, transparent)","$description":"Faint translucent primary wash over a surface.","$extensions":{"com.webority":{"platforms":["web"]}}},"primary-wash-strong":{"$value":"color-mix(in srgb, {color.primary} 20%, transparent)","$description":"Stronger translucent primary wash over a surface.","$extensions":{"com.webority":{"platforms":["web"]}}},"neutral":{"$value":"color-mix(in srgb, {color.text} 8%, transparent)","$description":"Quiet unbranded fill for supporting actions such as Back, Skip and Close."},"neutral-hover":{"$value":"color-mix(in srgb, {color.text} 12%, transparent)","$description":"Neutral fill while a control is hovered."},"neutral-pressed":{"$value":"color-mix(in srgb, {color.text} 16%, transparent)","$description":"Neutral fill while a control is pressed.","$extensions":{"com.webority":{"platforms":["web"]}}},"neutral-soft":{"$value":"color-mix(in srgb, {color.text-subtle} 16%, transparent)","$description":"Soft neutral background of the neutral status pill.","$extensions":{"com.webority":{"platforms":["web"]}}},"neutral-text":{"$value":"{color.text-muted}","$description":"Text on the soft neutral background.","$extensions":{"com.webority":{"platforms":["web"]}}},"on-neutral":{"$value":"{color.text}","$description":"Ink on a neutral fill."},"success":{"$value":"{palette.success}","$description":"Vivid success fill for badges, dots and success buttons."},"success-pressed":{"$value":"{palette.success-active}","$description":"Success fill while a control is pressed.","$extensions":{"com.webority":{"platforms":["web"]}}},"success-soft":{"$value":"{palette.success-10}","$description":"Soft success background of alerts and badges.","$extensions":{"com.webority":{"platforms":["web"]}}},"success-border":{"$value":"{palette.success-30}","$description":"Tinted success border of alerts and badges.","$extensions":{"com.webority":{"platforms":["web"]}}},"success-text":{"$value":"{palette.success-text}","$description":"Success colour as text on a page or a soft success tint."},"success-text-on-soft":{"$value":"{palette.success-text}","$description":"Success text on its own soft tint, such as an alert heading.","$extensions":{"com.webority":{"platforms":["web"]}}},"success-strong":{"$value":"{palette.success-strong}","$description":"Deep success fill that carries its own ink.","$extensions":{"com.webority":{"platforms":["web"]}}},"on-success":{"$value":"#FFFFFF","$description":"Ink on a solid success fill."},"on-success-strong":{"$value":"#FFFFFF","$description":"Ink on a deep success fill.","$extensions":{"com.webority":{"platforms":["web"]}}},"warning":{"$value":"{palette.warning}","$description":"Vivid warning fill for badges, dots and warning buttons."},"warning-pressed":{"$value":"{palette.warning-active}","$description":"Warning fill while a control is pressed.","$extensions":{"com.webority":{"platforms":["web"]}}},"warning-soft":{"$value":"{palette.warning-10}","$description":"Soft warning background of alerts and badges.","$extensions":{"com.webority":{"platforms":["web"]}}},"warning-border":{"$value":"{palette.warning-30}","$description":"Tinted warning border of alerts and badges.","$extensions":{"com.webority":{"platforms":["web"]}}},"warning-text":{"$value":"{palette.warning-text}","$description":"Warning colour as text on a page or a soft warning tint."},"warning-text-on-soft":{"$value":"{palette.warning-text}","$description":"Warning text on its own soft tint, such as an alert heading.","$extensions":{"com.webority":{"platforms":["web"]}}},"warning-strong":{"$value":"{palette.warning-active}","$description":"Deep warning fill that carries its own ink.","$extensions":{"com.webority":{"platforms":["web"]}}},"warning-strong-hover":{"$value":"{palette.warning-strong-hover}","$description":"Deep warning fill while a control is hovered or pressed.","$extensions":{"com.webority":{"platforms":["web"]}}},"on-warning":{"$value":"#FFFFFF","$description":"Ink on a solid warning fill."},"on-warning-strong":{"$value":"#FFFFFF","$description":"Ink on a deep warning fill.","$extensions":{"com.webority":{"platforms":["web"]}}},"danger":{"$value":"{palette.danger}","$description":"Vivid danger fill for badges, dots and danger buttons."},"danger-pressed":{"$value":"{palette.danger-active}","$description":"Danger fill while a control is pressed.","$extensions":{"com.webority":{"platforms":["web"]}}},"danger-soft":{"$value":"{palette.danger-10}","$description":"Soft danger background of alerts and badges.","$extensions":{"com.webority":{"platforms":["web"]}}},"danger-border":{"$value":"{palette.danger-30}","$description":"Tinted danger border of alerts and badges."},"danger-text":{"$value":"{palette.danger-text}","$description":"Danger colour as text on a page or a soft danger tint."},"danger-text-on-soft":{"$value":"{palette.danger-text}","$description":"Danger text on its own soft tint, such as an alert heading.","$extensions":{"com.webority":{"platforms":["web"]}}},"danger-strong":{"$value":"{palette.danger-strong}","$description":"Deep danger fill that carries its own ink.","$extensions":{"com.webority":{"platforms":["web"]}}},"danger-strong-hover":{"$value":"{palette.danger-strong-hover}","$description":"Deep danger fill while a control is hovered or pressed.","$extensions":{"com.webority":{"platforms":["web"]}}},"on-danger":{"$value":"#FFFFFF","$description":"Ink on a solid danger fill."},"on-danger-strong":{"$value":"#FFFFFF","$description":"Ink on a deep danger fill.","$extensions":{"com.webority":{"platforms":["web"]}}},"info":{"$value":"{palette.info}","$description":"Vivid info fill for badges, dots and info buttons."},"info-pressed":{"$value":"{palette.info-active}","$description":"Info fill while a control is pressed.","$extensions":{"com.webority":{"platforms":["web"]}}},"info-soft":{"$value":"{palette.info-10}","$description":"Soft info background of alerts and badges.","$extensions":{"com.webority":{"platforms":["web"]}}},"info-border":{"$value":"{palette.info-30}","$description":"Tinted info border of alerts and badges.","$extensions":{"com.webority":{"platforms":["web"]}}},"info-text":{"$value":"{palette.info-text}","$description":"Info colour as text on a page or a soft info tint."},"info-text-on-soft":{"$value":"{palette.info-text}","$description":"Info text on its own soft tint, such as an alert heading.","$extensions":{"com.webority":{"platforms":["web"]}}},"info-strong":{"$value":"{palette.info-active}","$description":"Deep info fill that carries its own ink.","$extensions":{"com.webority":{"platforms":["web"]}}},"on-info":{"$value":"#FFFFFF","$description":"Ink on a solid info fill."},"on-info-strong":{"$value":"#FFFFFF","$description":"Ink on a deep info fill.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-1":{"$value":"{palette.primary}","$description":"Colour of chart series 1, the brand primary.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-2":{"$value":"{palette.chart-2}","$description":"Colour of chart series 2 of the eight categorical series.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-3":{"$value":"{palette.chart-3}","$description":"Colour of chart series 3 of the eight categorical series.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-4":{"$value":"{palette.chart-4}","$description":"Colour of chart series 4 of the eight categorical series.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-5":{"$value":"{palette.chart-5}","$description":"Colour of chart series 5 of the eight categorical series.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-6":{"$value":"{palette.chart-6}","$description":"Colour of chart series 6 of the eight categorical series.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-7":{"$value":"{palette.chart-7}","$description":"Colour of chart series 7 of the eight categorical series.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-8":{"$value":"{palette.chart-8}","$description":"Colour of chart series 8 of the eight categorical series.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-seq-0":{"$value":"{palette.bg-muted}","$description":"Faintest step of the magnitude ramp, for empty heatmap and calendar cells.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-seq-1":{"$value":"{palette.primary-10}","$description":"First step of the one-hue magnitude ramp for heatmap and calendar cells.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-seq-2":{"$value":"{palette.primary-20}","$description":"Second step of the one-hue magnitude ramp for heatmap and calendar cells.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-seq-3":{"$value":"{palette.primary-30}","$description":"Third step of the one-hue magnitude ramp for heatmap and calendar cells.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-seq-4":{"$value":"{palette.primary-50}","$description":"Fourth step of the one-hue magnitude ramp for heatmap and calendar cells.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-seq-5":{"$value":"{palette.primary-hover}","$description":"Fifth step of the one-hue magnitude ramp for heatmap and calendar cells.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-seq-6":{"$value":"{palette.primary-pressed}","$description":"Strongest step of the one-hue magnitude ramp for heatmap and calendar cells.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-diverging-low":{"$value":"{palette.chart-diverging-low}","$description":"Colour of values below the midpoint in a diverging chart.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-diverging-mid":{"$value":"{palette.chart-diverging-mid}","$description":"Neutral midpoint colour of a diverging chart.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-diverging-high":{"$value":"{palette.chart-diverging-high}","$description":"Colour of values above the midpoint in a diverging chart.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-neutral":{"$value":"{palette.chart-neutral}","$description":"Context series colour, such as the last period, and the folded Other slice.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-grid":{"$value":"{color.border}","$description":"Gridline colour of charts.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-axis":{"$value":"{color.border-strong}","$description":"Axis line colour of charts.","$extensions":{"com.webority":{"platforms":["web"]}}},"chart-label":{"$value":"{color.text-subtle}","$description":"Tick and legend text colour of charts.","$extensions":{"com.webority":{"platforms":["web"]}}},"primary-pressed":{"$value":"{palette.phone-primary-pressed}","$description":"Primary fill while a control is pressed.","$extensions":{"com.webority":{"platforms":["phone"]}}},"on-neutral-strong":{"$value":"{palette.phone-on-neutral-strong}","$description":"Ink on the solid grey fill of a neutral badge, banner or avatar.","$extensions":{"com.webority":{"platforms":["phone"]}}},"text-disabled":{"$value":"{palette.phone-text-disabled}","$description":"Text of a disabled control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"surface-pressed":{"$value":"{palette.phone-surface-pressed}","$description":"Wash over a surface while it is pressed.","$extensions":{"com.webority":{"platforms":["phone"]}}},"surface-hover":{"$value":"{palette.phone-surface-hover}","$description":"Wash over a surface under a pointer.","$extensions":{"com.webority":{"platforms":["phone"]}}},"surface-selected":{"$value":"{palette.phone-surface-selected}","$description":"Wash over a selected surface such as a chosen list row.","$extensions":{"com.webority":{"platforms":["phone"]}}},"surface-disabled":{"$value":"{palette.phone-surface-disabled}","$description":"Fill of a disabled surface.","$extensions":{"com.webority":{"platforms":["phone"]}}},"skeleton":{"$value":"{palette.phone-skeleton}","$description":"Base fill of a loading placeholder.","$extensions":{"com.webority":{"platforms":["phone"]}}},"skeleton-highlight":{"$value":"{palette.phone-skeleton-highlight}","$description":"Moving highlight across a loading placeholder.","$extensions":{"com.webority":{"platforms":["phone"]}}},"glass-fill":{"$value":"{palette.phone-glass-fill}","$description":"Translucent fill of a control sitting on a brand surface.","$extensions":{"com.webority":{"platforms":["phone"]}}},"glass-border":{"$value":"{palette.phone-glass-border}","$description":"Border of a translucent control on a brand surface.","$extensions":{"com.webority":{"platforms":["phone"]}}},"on-glass":{"$value":"{palette.phone-on-glass}","$description":"Ink on a translucent control on a brand surface.","$extensions":{"com.webority":{"platforms":["phone"]}}},"glass-badge":{"$value":"{palette.phone-glass-badge}","$description":"Badge fill on a translucent control on a brand surface.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-bg-focus":{"$value":"{palette.phone-field-bg-focus}","$description":"Fill of a focused input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-bg-disabled":{"$value":"{palette.phone-field-bg-disabled}","$description":"Fill of a disabled input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-border-error":{"$value":"{palette.phone-field-border-error}","$description":"Border of an input-like control holding an invalid value.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-label":{"$value":"{palette.phone-field-label}","$description":"Label above an input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-text":{"$value":"{palette.phone-field-text}","$description":"Value text inside an input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-text-disabled":{"$value":"{palette.phone-field-text-disabled}","$description":"Value text inside a disabled input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-placeholder":{"$value":"{palette.phone-field-placeholder}","$description":"Placeholder text inside an empty input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-placeholder-disabled":{"$value":"{palette.phone-field-placeholder-disabled}","$description":"Placeholder text inside a disabled input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-icon":{"$value":"{palette.phone-field-icon}","$description":"Icon inside an input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-icon-focus":{"$value":"{palette.phone-field-icon-focus}","$description":"Icon inside a focused input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-icon-disabled":{"$value":"{palette.phone-field-icon-disabled}","$description":"Icon inside a disabled input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-caret":{"$value":"{palette.phone-field-caret}","$description":"Text caret inside an input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"field-message":{"$value":"{palette.phone-field-message}","$description":"Error message under an input-like control.","$extensions":{"com.webority":{"platforms":["phone"]}}},"avatar-1":{"$value":"{palette.phone-avatar-1}","$description":"Background behind a person's initials, picked by a hash of the name (slot 1 of 8).","$extensions":{"com.webority":{"platforms":["phone"]}}},"avatar-2":{"$value":"{palette.phone-avatar-2}","$description":"Background behind a person's initials, picked by a hash of the name (slot 2 of 8).","$extensions":{"com.webority":{"platforms":["phone"]}}},"avatar-3":{"$value":"{palette.phone-avatar-3}","$description":"Background behind a person's initials, picked by a hash of the name (slot 3 of 8).","$extensions":{"com.webority":{"platforms":["phone"]}}},"avatar-4":{"$value":"{palette.phone-avatar-4}","$description":"Background behind a person's initials, picked by a hash of the name (slot 4 of 8).","$extensions":{"com.webority":{"platforms":["phone"]}}},"avatar-5":{"$value":"{palette.phone-avatar-5}","$description":"Background behind a person's initials, picked by a hash of the name (slot 5 of 8).","$extensions":{"com.webority":{"platforms":["phone"]}}},"avatar-6":{"$value":"{palette.phone-avatar-6}","$description":"Background behind a person's initials, picked by a hash of the name (slot 6 of 8).","$extensions":{"com.webority":{"platforms":["phone"]}}},"avatar-7":{"$value":"{palette.phone-avatar-7}","$description":"Background behind a person's initials, picked by a hash of the name (slot 7 of 8).","$extensions":{"com.webority":{"platforms":["phone"]}}},"avatar-8":{"$value":"{palette.phone-avatar-8}","$description":"Background behind a person's initials, picked by a hash of the name (slot 8 of 8).","$extensions":{"com.webority":{"platforms":["phone"]}}}}`),effect:{"close-filter":{$type:`filter`,$value:`none`,$description:`Filter applied to a dark-ink close glyph such as the alert close button.`},"pressed-overlay":{$type:`color`,$value:`color-mix(in srgb, currentColor 12%, transparent)`,$description:`Translucent wash laid over a control while it is pressed.`},"hero-gradient":{$type:`gradient`,$value:`radial-gradient(ellipse 120% 80% at 50% 30%, #818CF8 0%, #4F46E5 35%, #4338CA 75%, #312E81 100%)`,$description:`Background gradient of the hero band on marketing pages.`},"cta-gradient":{$type:`gradient`,$value:`radial-gradient(ellipse 120% 100% at 50% 50%, #312E81 0%, #1E1B4B 60%, #0F0D2E 100%)`,$description:`Background gradient of the call-to-action band on marketing pages.`}}},Ye={palette:{"phone-bg":{$value:`#0B0B12`},"phone-bg-subtle":{$value:`#13131C`},"phone-bg-muted":{$value:`#1C1C26`},"phone-surface":{$value:`#1C1C26`},"phone-surface-inverse":{$value:`#FAFAFA`},"phone-text":{$value:`#E2E2E2`},"phone-text-body":{$value:`#FAFAFA`},"phone-text-muted":{$value:`#B4B4BB`},"phone-text-subtle":{$value:`#919199`},"phone-text-inverse":{$value:`#0F0F1A`},"phone-link":{$value:`#9292EE`},"phone-border":{$value:`#27272F`},"phone-border-subtle":{$value:`#1C1C26`},"phone-focus-ring":{$value:`#7C7CE8`},"phone-scrim":{$value:`rgba(0, 0, 0, 0.65)`},"phone-field-bg":{$value:`#13131C`},"phone-field-border":{$value:`#27272F`},"phone-field-border-focus":{$value:`#3D5FB0`},"phone-primary":{$value:`#7C7CE8`},"phone-primary-hover":{$value:`#9292EE`},"phone-primary-soft":{$value:`#1F1F3D`},"phone-primary-text":{$value:`#8989EA`},"phone-on-primary":{$value:`#0F0F1A`},"phone-success":{$value:`#30C780`},"phone-success-text":{$value:`#30C780`},"phone-on-success":{$value:`#0F0F1A`},"phone-warning":{$value:`#FBBF24`},"phone-warning-text":{$value:`#FBBF24`},"phone-danger":{$value:`#F87171`},"phone-danger-text":{$value:`#F87171`},"phone-on-danger":{$value:`#0F0F1A`},"phone-danger-border":{$value:`#F87171`},"phone-info":{$value:`#60A5FA`},"phone-info-text":{$value:`#60A5FA`},"phone-on-info":{$value:`#0F0F1A`},"phone-neutral":{$value:`#1F1F26`},"phone-neutral-hover":{$value:`#2A2A33`},"phone-on-neutral":{$value:`#FAFAFA`},"phone-primary-pressed":{$value:`#A8A8F2`},"phone-on-neutral-strong":{$value:`#0F0F1A`},"phone-text-disabled":{$value:`#52525B`},"phone-surface-pressed":{$value:`rgba(255, 255, 255, 0.08)`},"phone-surface-hover":{$value:`rgba(255, 255, 255, 0.05)`},"phone-surface-selected":{$value:`rgba(124, 124, 232, 0.18)`},"phone-surface-disabled":{$value:`#1C1C26`},"phone-skeleton":{$value:`#1C1C26`},"phone-skeleton-highlight":{$value:`#27272F`},"phone-field-bg-focus":{$value:`#0B0B12`},"phone-field-bg-disabled":{$value:`#1C1C26`},"phone-field-border-error":{$value:`#8A2F42`},"phone-field-label":{$value:`#E4E6EE`},"phone-field-text":{$value:`#FAFAFA`},"phone-field-text-disabled":{$value:`#52525B`},"phone-field-placeholder":{$value:`#84848D`},"phone-field-placeholder-disabled":{$value:`#52525B`},"phone-field-icon":{$value:`#8B8B95`},"phone-field-icon-focus":{$value:`#D4D4DB`},"phone-field-icon-disabled":{$value:`#52525B`},"phone-field-caret":{$value:`#7C9EF0`},"phone-field-message":{$value:`#F87171`},"phone-avatar-1":{$value:`#8B8BEE`},"phone-avatar-2":{$value:`#2DD4BF`},"phone-avatar-3":{$value:`#FCD34D`},"phone-avatar-4":{$value:`#F472B6`},"phone-avatar-5":{$value:`#60A5FA`},"phone-avatar-6":{$value:`#A78BFA`},"phone-avatar-7":{$value:`#34D399`},"phone-avatar-8":{$value:`#F87171`},"phone-shadow-sm":{$value:`rgba(0, 0, 0, 0.4)`},"phone-shadow-md":{$value:`rgba(0, 0, 0, 0.5)`},"phone-shadow-lg":{$value:`rgba(0, 0, 0, 0.55)`},"phone-shadow-xl":{$value:`rgba(0, 0, 0, 0.6)`}},color:{bg:{$value:`{palette.dark-bg-page}`},"bg-subtle":{$value:`{palette.dark-bg-elevated}`},"bg-muted":{$value:`{palette.dark-bg-muted}`},surface:{$value:`{palette.dark-bg-surface}`},"surface-inverse":{$value:`{palette.dark-text}`},text:{$value:`{palette.dark-text}`},"text-body":{$value:`{palette.dark-text}`},"text-muted":{$value:`{palette.dark-text-muted}`},"text-subtle":{$value:`{palette.dark-text-subtle}`},"text-inverse":{$value:`{palette.text-heading}`},link:{$value:`{palette.dark-primary}`},border:{$value:`{palette.dark-border}`},"border-subtle":{$value:`color-mix(in srgb, {palette.dark-border} 50%, transparent)`},"border-strong":{$value:`{palette.dark-border-strong}`},"field-bg":{$value:`{palette.dark-bg-muted}`},"field-border":{$value:`{palette.dark-field-border}`},"field-border-hover":{$value:`{palette.dark-field-border-hover}`},"field-border-focus":{$value:`{palette.dark-primary}`},scrim:{$value:`color-mix(in srgb, #000000 45%, transparent)`},"scrim-strong":{$value:`color-mix(in srgb, #000000 62%, transparent)`},"progress-track":{$value:`{palette.dark-progress-track}`},"progress-label":{$value:`#0F0F0F`},thumb:{$value:`color-mix(in srgb, {palette.dark-text} 12%, {palette.dark-bg-muted})`},primary:{$value:`{palette.dark-primary}`},"primary-hover":{$value:`{palette.dark-primary-hover}`},"primary-soft":{$value:`color-mix(in srgb, {palette.primary} 20%, transparent)`},"primary-text":{$value:`{palette.dark-primary}`},"on-primary":{$value:`#0F0F0F`},"success-soft":{$value:`color-mix(in srgb, {palette.success} 18%, transparent)`},"success-text":{$value:`color-mix(in srgb, {palette.success} 75%, white)`},"success-text-on-soft":{$value:`color-mix(in srgb, {palette.success} 65%, white)`},"success-strong":{$value:`{color.success-text}`},"on-success-strong":{$value:`#0F0F0F`},"warning-soft":{$value:`color-mix(in srgb, {palette.warning} 18%, transparent)`},"warning-text":{$value:`color-mix(in srgb, {palette.warning} 75%, white)`},"warning-text-on-soft":{$value:`color-mix(in srgb, {palette.warning} 65%, white)`},"warning-strong":{$value:`{color.warning-text}`},"on-warning-strong":{$value:`#0F0F0F`},"danger-soft":{$value:`color-mix(in srgb, {palette.danger} 18%, transparent)`},"danger-text":{$value:`color-mix(in srgb, {palette.danger} 75%, white)`},"danger-text-on-soft":{$value:`color-mix(in srgb, {palette.danger} 65%, white)`},"danger-strong":{$value:`{color.danger-text}`},"on-danger-strong":{$value:`#0F0F0F`},"info-soft":{$value:`color-mix(in srgb, {palette.info} 18%, transparent)`},"info-text":{$value:`color-mix(in srgb, {palette.info} 75%, white)`},"info-text-on-soft":{$value:`color-mix(in srgb, {palette.info} 65%, white)`},"info-strong":{$value:`{color.info-text}`},"on-info-strong":{$value:`#0F0F0F`},"chart-1":{$value:`{palette.dark-primary}`},"chart-2":{$value:`{palette.dark-chart-2}`},"chart-3":{$value:`{palette.dark-chart-3}`},"chart-4":{$value:`{palette.dark-chart-4}`},"chart-5":{$value:`{palette.dark-chart-5}`},"chart-6":{$value:`{palette.dark-chart-6}`},"chart-7":{$value:`{palette.dark-chart-7}`},"chart-8":{$value:`{palette.dark-chart-8}`},"chart-seq-0":{$value:`{palette.dark-chart-seq-0}`},"chart-seq-1":{$value:`{palette.dark-chart-seq-1}`},"chart-seq-2":{$value:`{palette.dark-chart-seq-2}`},"chart-seq-3":{$value:`{palette.dark-chart-seq-3}`},"chart-seq-4":{$value:`{palette.dark-chart-seq-4}`},"chart-seq-5":{$value:`{palette.dark-chart-seq-5}`},"chart-seq-6":{$value:`{palette.dark-chart-seq-6}`},"chart-diverging-low":{$value:`{palette.dark-chart-diverging-low}`},"chart-diverging-mid":{$value:`{palette.dark-chart-diverging-mid}`},"chart-diverging-high":{$value:`{palette.dark-chart-diverging-high}`},"chart-neutral":{$value:`{palette.dark-chart-neutral}`}},effect:{"close-filter":{$value:`invert(1) grayscale(100%) brightness(200%)`}},component:{thumb:{md:{shadow:{$value:`0 2px 6px rgba(255, 255, 255, 0.1)`},"shadow-hover":{$value:`0 2px 12px rgba(255, 255, 255, 0.2)`}}}}},Xe={palette:JSON.parse(`{"$description":"Raw colours. Library-internal: product code, phone code and Canvas read meanings, never these.","$extensions":{"com.webority":{"internal":true}},"primary":{"$type":"color","$value":"#4F46E5","$description":"Brand primary fill for primary buttons, selected states and the first chart series."},"primary-hover":{"$type":"color","$value":"#6366F1","$description":"Primary fill while a control is hovered."},"primary-pressed":{"$type":"color","$value":"#4338CA","$description":"Primary fill while a control is pressed or active."},"primary-50":{"$type":"color","$value":"#818CF8","$description":"Strongest soft primary fill or border tint that follows dark mode."},"primary-30":{"$type":"color","$value":"#A5B4FC","$description":"Medium soft primary fill or border tint that follows dark mode."},"primary-20":{"$type":"color","$value":"#C7D2FE","$description":"Light soft primary fill or border tint that follows dark mode."},"primary-15":{"$type":"color","$value":"#DDE1FD","$description":"Lighter soft primary fill or border tint that follows dark mode."},"primary-10":{"$type":"color","$value":"#E0E7FF","$description":"Pale soft primary fill or border tint that follows dark mode."},"primary-5":{"$type":"color","$value":"#EEF2FF","$description":"Faintest soft primary fill or border tint that follows dark mode."},"text-heading":{"$type":"color","$value":"#071437","$description":"Heading ink for page and section titles."},"text-1":{"$type":"color","$value":"#252F4A","$description":"Primary body text, a step softer than the heading ink."},"text-2":{"$type":"color","$value":"#4B5675","$description":"Secondary text for descriptions, sub-labels and muted copy."},"text-3":{"$type":"color","$value":"#687088","$description":"Tertiary text for hints, captions, labels, timestamps and placeholders."},"text-4":{"$type":"color","$value":"#99A1B7","$description":"Decorative faint ink, not for text a person must read."},"text-5":{"$type":"color","$value":"#C4CADA","$description":"Faintest ink, for decorative marks."},"bg-page":{"$type":"color","$value":"#F4F6F8","$description":"Page background behind every surface in light mode."},"bg-light":{"$type":"color","$value":"#FFFFFF","$description":"White card and panel surface, the lightest fill in light mode."},"bg-elevated":{"$type":"color","$value":"#F9FBFC","$description":"Subtle raised surface, one step off the page."},"bg-muted":{"$type":"color","$value":"#F5F6FA","$description":"Muted fill for grouped areas and quiet controls."},"field-bg":{"$type":"color","$value":"#F9FBFC","$description":"Resting fill of every input-like control, such as fields, selects and textareas."},"field-border":{"$type":"color","$value":"#DFE2EA","$description":"Resting border of every input-like control."},"field-border-hover":{"$type":"color","$value":"#C4CADA","$description":"Hover border of every input-like control."},"border-light":{"$type":"color","$value":"#EBEDF3","$description":"Default hairline border of cards, tables and dividers."},"border-soft":{"$type":"color","$value":"#F4F6F8","$description":"Softest border, for inner dividers."},"border-strong":{"$type":"color","$value":"#C4CADA","$description":"Strong border for emphasised separators, chart axes and unselected control outlines."},"progress-track":{"$type":"color","$value":"#E1E5EE","$description":"Unfilled track of a progress bar or meter."},"scrollbar":{"$type":"color","$value":"rgba(145, 158, 171, 0.45)","$description":"Resting thumb colour of a thin scrollbar."},"scrollbar-hover":{"$type":"color","$value":"rgba(145, 158, 171, 0.65)","$description":"Scrollbar thumb colour while it is hovered."},"scrollbar-active":{"$type":"color","$value":"rgba(145, 158, 171, 0.85)","$description":"Scrollbar thumb colour while it is dragged."},"surface-soft":{"$type":"color","$value":"#F2EFFE","$description":"Soft tint surface for marketing callouts and mega-menu hover."},"surface-violet":{"$type":"color","$value":"#ECE4FE","$description":"Violet-tinted surface for marketing section accents and callout cards."},"surface-violet-soft":{"$type":"color","$value":"#FCFCFC","$description":"Near-white surface for marketing section accents."},"surface-mute":{"$type":"color","$value":"#F9FBFC","$description":"Neutral wash surface for marketing sections and panels."},"ink":{"$type":"color","$value":"#000000","$description":"Pure black ink, the highest-contrast text colour."},"fg-2":{"$type":"color","$value":"{palette.text-1}","$description":"Marketing alias of the primary body text ink."},"fg-3":{"$type":"color","$value":"{palette.text-2}","$description":"Marketing alias of the secondary text ink."},"fg-4":{"$type":"color","$value":"{palette.text-3}","$description":"Marketing alias of the tertiary text ink."},"fg-5":{"$type":"color","$value":"{palette.text-5}","$description":"Marketing alias of the faintest text ink."},"neutral-border-dark":{"$type":"color","$value":"#EBEDF3","$description":"Border tone of table emphasis rows and dividers."},"neutral-border-light":{"$type":"color","$value":"#F9FBFC","$description":"Faintest border tone, for dividers."},"neutral-bg-dark":{"$type":"color","$value":"#F5F6FA","$description":"Muted background of table emphasis rows and mega-menu hover."},"neutral-bg-light":{"$type":"color","$value":"#F9FBFC","$description":"Faint background for table emphasis and mega-menu hover."},"accent-dark":{"$type":"color","$value":"{palette.primary-pressed}","$description":"Pressed and hover accent colour in CSS, following the pressed primary."},"primary-text":{"$type":"color","$value":"#FFFFFF","$description":"Text and icon colour on a solid primary fill, such as a primary button label."},"primary-ink":{"$type":"color","$value":"#4F46E5","$description":"Primary as text and small glyphs on light surfaces, passing AA contrast."},"info-text":{"$type":"color","$value":"#1460ba","$description":"Info colour as text on light surfaces."},"info-active":{"$type":"color","$value":"#056EE9","$description":"Info ink for icons and active states on light surfaces."},"info":{"$type":"color","$value":"#056EE9","$description":"Vivid info fill for badges, dots and info buttons."},"info-50":{"$type":"color","$value":"#8DC2FF","$description":"Info tint 50 for borders and the strongest soft info fill."},"info-30":{"$type":"color","$value":"#BBDBFF","$description":"Info tint 30 for soft fills and borders of alerts and badges."},"info-20":{"$type":"color","$value":"#D1E6FF","$description":"Info tint 20 for soft fills behind info alerts and badges."},"info-10":{"$type":"color","$value":"#E9F3FF","$description":"Info tint 10, the soft background of info alerts and badges."},"info-5":{"$type":"color","$value":"#F3F9FF","$description":"Faintest info tint, for hover washes and soft info backgrounds."},"success-text":{"$type":"color","$value":"#0e7531","$description":"Success colour as text on light surfaces, darkened to pass AA."},"success-strong":{"$type":"color","$value":"#0e7531","$description":"Deep success fill behind white text, such as progress-bar labels."},"success-active":{"$type":"color","$value":"#04B440","$description":"Active success fill, the deepest vivid success tone."},"success":{"$type":"color","$value":"#04B440","$description":"Vivid success fill for badges, dots and success buttons."},"success-50":{"$type":"color","$value":"#8BE3A9","$description":"Success tint 50 for borders and the strongest soft success fill."},"success-30":{"$type":"color","$value":"#BAEECC","$description":"Success tint 30 for soft fills and borders of alerts and badges."},"success-20":{"$type":"color","$value":"#D1F4DD","$description":"Success tint 20 for soft fills behind success alerts and badges."},"success-10":{"$type":"color","$value":"#E8FAEE","$description":"Success tint 10, the soft background of success alerts and badges."},"success-5":{"$type":"color","$value":"#F3FCF6","$description":"Faintest success tint, for hover washes and soft success backgrounds."},"warning-text":{"$type":"color","$value":"#876100","$description":"Warning colour as text on light surfaces, darkened to pass AA."},"warning-strong":{"$type":"color","$value":"#9A6B00","$description":"Deep warning fill behind white text, such as the warning button."},"warning-strong-hover":{"$type":"color","$value":"#855C00","$description":"Deep warning fill while a warning button with white text is hovered."},"warning-active":{"$type":"color","$value":"#DFA000","$description":"Active warning fill, the deepest vivid warning tone."},"warning":{"$type":"color","$value":"#DFA000","$description":"Vivid warning fill for badges and dots."},"warning-50":{"$type":"color","$value":"#FBD880","$description":"Warning tint 50 for borders and the strongest soft warning fill."},"warning-30":{"$type":"color","$value":"#FDE8B3","$description":"Warning tint 30 for soft fills and borders of alerts and badges."},"warning-20":{"$type":"color","$value":"#FDEFCC","$description":"Warning tint 20 for soft fills behind warning alerts and badges."},"warning-10":{"$type":"color","$value":"#FFF8E6","$description":"Warning tint 10, the soft background of warning alerts and badges."},"warning-5":{"$type":"color","$value":"#FEFBF2","$description":"Faintest warning tint, for hover washes and soft warning backgrounds."},"danger-text":{"$type":"color","$value":"#CF1735","$description":"Error text colour for validation messages and danger text on light surfaces."},"danger-strong":{"$type":"color","$value":"#C81340","$description":"Deep danger fill behind white text, such as the danger button."},"danger-strong-hover":{"$type":"color","$value":"#AB1036","$description":"Deep danger fill while a danger button with white text is hovered."},"danger-active":{"$type":"color","$value":"#E82646","$description":"Active danger fill, the deepest vivid danger tone."},"danger":{"$type":"color","$value":"#E82646","$description":"Vivid danger fill for badges, dots and danger buttons."},"danger-50":{"$type":"color","$value":"#FC94AD","$description":"Danger tint 50 for borders and the strongest soft danger fill."},"danger-30":{"$type":"color","$value":"#FDBFCE","$description":"Danger tint 30 for soft fills and borders of alerts and badges."},"danger-20":{"$type":"color","$value":"#FED4DE","$description":"Danger tint 20 for soft fills behind danger alerts and badges."},"danger-10":{"$type":"color","$value":"#FFEAEF","$description":"Danger tint 10, the soft background of danger alerts and badges."},"danger-5":{"$type":"color","$value":"#FEF4F6","$description":"Faintest danger tint, for hover washes and soft danger backgrounds."},"chart-1":{"$type":"color","$value":"{palette.primary}","$description":"Colour of chart series 1, the brand primary."},"chart-2":{"$type":"color","$value":"#eb6834","$description":"Colour of chart series 2 of the eight categorical series."},"chart-3":{"$type":"color","$value":"#1baf7a","$description":"Colour of chart series 3 of the eight categorical series."},"chart-4":{"$type":"color","$value":"#eda100","$description":"Colour of chart series 4 of the eight categorical series."},"chart-5":{"$type":"color","$value":"#e87ba4","$description":"Colour of chart series 5 of the eight categorical series."},"chart-6":{"$type":"color","$value":"#008300","$description":"Colour of chart series 6 of the eight categorical series."},"chart-7":{"$type":"color","$value":"#2a78d6","$description":"Colour of chart series 7 of the eight categorical series."},"chart-8":{"$type":"color","$value":"#e34948","$description":"Colour of chart series 8 of the eight categorical series."},"chart-seq-0":{"$type":"color","$value":"{palette.bg-muted}","$description":"Faintest step of the magnitude ramp, for empty heatmap and calendar cells."},"chart-seq-1":{"$type":"color","$value":"{palette.primary-10}","$description":"First step of the one-hue magnitude ramp for heatmap and calendar cells."},"chart-seq-2":{"$type":"color","$value":"{palette.primary-20}","$description":"Second step of the one-hue magnitude ramp for heatmap and calendar cells."},"chart-seq-3":{"$type":"color","$value":"{palette.primary-30}","$description":"Third step of the one-hue magnitude ramp for heatmap and calendar cells."},"chart-seq-4":{"$type":"color","$value":"{palette.primary-50}","$description":"Fourth step of the one-hue magnitude ramp for heatmap and calendar cells."},"chart-seq-5":{"$type":"color","$value":"{palette.primary-hover}","$description":"Fifth step of the one-hue magnitude ramp for heatmap and calendar cells."},"chart-seq-6":{"$type":"color","$value":"{palette.primary-pressed}","$description":"Strongest step of the one-hue magnitude ramp for heatmap and calendar cells."},"chart-diverging-low":{"$type":"color","$value":"#e34948","$description":"Colour of values below the midpoint in a diverging chart."},"chart-diverging-mid":{"$type":"color","$value":"#c4cada","$description":"Neutral midpoint colour of a diverging chart."},"chart-diverging-high":{"$type":"color","$value":"#2a78d6","$description":"Colour of values above the midpoint in a diverging chart."},"chart-neutral":{"$type":"color","$value":"#99a1b7","$description":"Context series colour, such as the last period, and the folded Other slice."},"dark-bg-page":{"$type":"color","$value":"#0f1117","$description":"Dark page background, the base of every dark-mode surface."},"dark-bg-elevated":{"$type":"color","$value":"#0d0f15","$description":"Subtle dark background, one step off the dark page."},"dark-bg-muted":{"$type":"color","$value":"#232733","$description":"Dark muted fill for grouped areas and quiet controls."},"dark-bg-surface":{"$type":"color","$value":"#181b23","$description":"Dark card and panel surface, one step above the dark page."},"dark-border":{"$type":"color","$value":"#2a2f3a","$description":"Dark hairline border of cards, tables and dividers."},"dark-border-strong":{"$type":"color","$value":"#3a414f","$description":"Stronger dark border for emphasised separators."},"dark-field-border":{"$type":"color","$value":"#2a2f3a","$description":"Resting border of input-like controls in dark mode."},"dark-field-border-hover":{"$type":"color","$value":"#3a414f","$description":"Hover border of input-like controls in dark mode."},"dark-progress-track":{"$type":"color","$value":"#323845","$description":"Unfilled track of a progress bar or meter in dark mode."},"dark-text":{"$type":"color","$value":"#e6e8ee","$description":"Primary body text colour in dark mode."},"dark-text-muted":{"$type":"color","$value":"#b4b9c6","$description":"Secondary text colour in dark mode."},"dark-text-subtle":{"$type":"color","$value":"#8a90a0","$description":"Tertiary text colour in dark mode, for hints and captions."},"dark-primary":{"$type":"color","$value":"#9590EF","$description":"Primary as text, rings, focus borders and the fill under dark ink in dark mode."},"dark-primary-hover":{"$type":"color","$value":"#A29DF1","$description":"Primary fill while it is hovered in dark mode."},"dark-chart-2":{"$type":"color","$value":"#d95926","$description":"Dark-mode colour of chart series 2 of the categorical set."},"dark-chart-3":{"$type":"color","$value":"#199e70","$description":"Dark-mode colour of chart series 3 of the categorical set."},"dark-chart-4":{"$type":"color","$value":"#c98500","$description":"Dark-mode colour of chart series 4 of the categorical set."},"dark-chart-5":{"$type":"color","$value":"#d55181","$description":"Dark-mode colour of chart series 5 of the categorical set."},"dark-chart-6":{"$type":"color","$value":"#008300","$description":"Dark-mode colour of chart series 6 of the categorical set."},"dark-chart-7":{"$type":"color","$value":"#3987e5","$description":"Dark-mode colour of chart series 7 of the categorical set."},"dark-chart-8":{"$type":"color","$value":"#e66767","$description":"Dark-mode colour of chart series 8 of the categorical set."},"dark-chart-seq-0":{"$type":"color","$value":"#20242f","$description":"Dark-mode faintest step of the magnitude ramp, for empty heatmap cells."},"dark-chart-seq-1":{"$type":"color","$value":"#262c45","$description":"Dark-mode first step of the magnitude ramp for heatmap and calendar cells."},"dark-chart-seq-2":{"$type":"color","$value":"#2f3a70","$description":"Dark-mode second step of the magnitude ramp for heatmap and calendar cells."},"dark-chart-seq-3":{"$type":"color","$value":"#3b4ba0","$description":"Dark-mode third step of the magnitude ramp for heatmap and calendar cells."},"dark-chart-seq-4":{"$type":"color","$value":"#5168d2","$description":"Dark-mode fourth step of the magnitude ramp for heatmap and calendar cells."},"dark-chart-seq-5":{"$type":"color","$value":"#7a90ef","$description":"Dark-mode fifth step of the magnitude ramp for heatmap and calendar cells."},"dark-chart-seq-6":{"$type":"color","$value":"#b3c1f7","$description":"Dark-mode strongest step of the magnitude ramp for heatmap and calendar cells."},"dark-chart-diverging-low":{"$type":"color","$value":"#e66767","$description":"Dark-mode colour of values below the midpoint in a diverging chart."},"dark-chart-diverging-mid":{"$type":"color","$value":"#3a414f","$description":"Dark-mode neutral midpoint colour of a diverging chart."},"dark-chart-diverging-high":{"$type":"color","$value":"#3987e5","$description":"Dark-mode colour of values above the midpoint in a diverging chart."},"dark-chart-neutral":{"$type":"color","$value":"#5d6475","$description":"Dark-mode context series colour, such as the last period."},"phone-bg":{"$type":"color","$value":"#FFFFFF"},"phone-bg-subtle":{"$type":"color","$value":"#F8F8FB"},"phone-bg-muted":{"$type":"color","$value":"#F1F1F5"},"phone-surface":{"$type":"color","$value":"#FFFFFF"},"phone-surface-inverse":{"$type":"color","$value":"#0F0F1A"},"phone-text":{"$type":"color","$value":"#252F4A"},"phone-text-body":{"$type":"color","$value":"#0F0F1A"},"phone-text-muted":{"$type":"color","$value":"#52525B"},"phone-text-subtle":{"$type":"color","$value":"#62626B"},"phone-text-inverse":{"$type":"color","$value":"#FFFFFF"},"phone-link":{"$type":"color","$value":"#5B5BD6"},"phone-border":{"$type":"color","$value":"#E5E5EC"},"phone-border-subtle":{"$type":"color","$value":"#EFEFF3"},"phone-focus-ring":{"$type":"color","$value":"#5B5BD6"},"phone-scrim":{"$type":"color","$value":"rgba(15, 15, 26, 0.5)"},"phone-on-scrim":{"$type":"color","$value":"#FFFFFF"},"phone-field-bg":{"$type":"color","$value":"#F9FBFC"},"phone-field-border":{"$type":"color","$value":"#EBEDF3"},"phone-field-border-focus":{"$type":"color","$value":"#BED2F9"},"phone-primary":{"$type":"color","$value":"#5B5BD6"},"phone-primary-hover":{"$type":"color","$value":"#4F4FBF"},"phone-primary-soft":{"$type":"color","$value":"#EEEEFC"},"phone-primary-text":{"$type":"color","$value":"#4F4FD3"},"phone-on-primary":{"$type":"color","$value":"#FFFFFF"},"phone-success":{"$type":"color","$value":"#18864F"},"phone-success-text":{"$type":"color","$value":"#147042"},"phone-on-success":{"$type":"color","$value":"#FFFFFF"},"phone-warning":{"$type":"color","$value":"#F59E0B"},"phone-warning-text":{"$type":"color","$value":"#8F5C06"},"phone-on-warning":{"$type":"color","$value":"#0F0F1A"},"phone-danger":{"$type":"color","$value":"#E12C32"},"phone-danger-text":{"$type":"color","$value":"#BC1B20"},"phone-on-danger":{"$type":"color","$value":"#FFFFFF"},"phone-danger-border":{"$type":"color","$value":"#E5484D"},"phone-info":{"$type":"color","$value":"#1B6EF5"},"phone-info-text":{"$type":"color","$value":"#0958D9"},"phone-on-info":{"$type":"color","$value":"#FFFFFF"},"phone-neutral":{"$type":"color","$value":"#F4F4F8"},"phone-neutral-hover":{"$type":"color","$value":"#E9E9F0"},"phone-on-neutral":{"$type":"color","$value":"#0F0F1A"},"phone-primary-pressed":{"$type":"color","$value":"#4040A8"},"phone-on-neutral-strong":{"$type":"color","$value":"#FFFFFF"},"phone-text-disabled":{"$type":"color","$value":"#B4B4BB"},"phone-surface-pressed":{"$type":"color","$value":"rgba(15, 15, 26, 0.06)"},"phone-surface-hover":{"$type":"color","$value":"rgba(15, 15, 26, 0.04)"},"phone-surface-selected":{"$type":"color","$value":"rgba(91, 91, 214, 0.1)"},"phone-surface-disabled":{"$type":"color","$value":"#F1F1F5"},"phone-skeleton":{"$type":"color","$value":"#EBEDF3"},"phone-skeleton-highlight":{"$type":"color","$value":"#F5F6FA"},"phone-glass-fill":{"$type":"color","$value":"rgba(255, 255, 255, 0.28)"},"phone-glass-border":{"$type":"color","$value":"rgba(255, 255, 255, 0.45)"},"phone-on-glass":{"$type":"color","$value":"#0F0F1A"},"phone-glass-badge":{"$type":"color","$value":"#FFFFFF"},"phone-field-bg-focus":{"$type":"color","$value":"#FFFFFF"},"phone-field-bg-disabled":{"$type":"color","$value":"#F5F6FA"},"phone-field-border-error":{"$type":"color","$value":"#FDBFCE"},"phone-field-label":{"$type":"color","$value":"#242F4A"},"phone-field-text":{"$type":"color","$value":"#252F4A"},"phone-field-text-disabled":{"$type":"color","$value":"#C4CADA"},"phone-field-placeholder":{"$type":"color","$value":"#626D8B"},"phone-field-placeholder-disabled":{"$type":"color","$value":"#C4CADA"},"phone-field-icon":{"$type":"color","$value":"#7A849F"},"phone-field-icon-focus":{"$type":"color","$value":"#4B5675"},"phone-field-icon-disabled":{"$type":"color","$value":"#C4CADA"},"phone-field-caret":{"$type":"color","$value":"#5B8DEE"},"phone-field-message":{"$type":"color","$value":"#D81736"},"phone-avatar-1":{"$type":"color","$value":"#5B5BD6"},"phone-avatar-2":{"$type":"color","$value":"#0A7979"},"phone-avatar-3":{"$type":"color","$value":"#A45A05"},"phone-avatar-4":{"$type":"color","$value":"#CD226E"},"phone-avatar-5":{"$type":"color","$value":"#2462EB"},"phone-avatar-6":{"$type":"color","$value":"#7C3AED"},"phone-avatar-7":{"$type":"color","$value":"#047C57"},"phone-avatar-8":{"$type":"color","$value":"#D42222"},"phone-shadow-sm":{"$type":"color","$value":"rgba(0, 0, 0, 0.06)"},"phone-shadow-md":{"$type":"color","$value":"rgba(0, 0, 0, 0.08)"},"phone-shadow-lg":{"$type":"color","$value":"rgba(0, 0, 0, 0.1)"},"phone-shadow-xl":{"$type":"color","$value":"rgba(0, 0, 0, 0.14)"}}`)},Ze={color:{bg:{$value:`{palette.phone-bg}`},"bg-subtle":{$value:`{palette.phone-bg-subtle}`},"bg-muted":{$value:`{palette.phone-bg-muted}`},surface:{$value:`{palette.phone-surface}`},"surface-inverse":{$value:`{palette.phone-surface-inverse}`},text:{$value:`{palette.phone-text}`},"text-body":{$value:`{palette.phone-text-body}`},"text-muted":{$value:`{palette.phone-text-muted}`},"text-subtle":{$value:`{palette.phone-text-subtle}`},"text-inverse":{$value:`{palette.phone-text-inverse}`},link:{$value:`{palette.phone-link}`},border:{$value:`{palette.phone-border}`},"border-subtle":{$value:`{palette.phone-border-subtle}`},"focus-ring":{$value:`{palette.phone-focus-ring}`},scrim:{$value:`{palette.phone-scrim}`},"on-scrim":{$value:`{palette.phone-on-scrim}`},"field-bg":{$value:`{palette.phone-field-bg}`},"field-border":{$value:`{palette.phone-field-border}`},"field-border-focus":{$value:`{palette.phone-field-border-focus}`},primary:{$value:`{palette.phone-primary}`},"primary-hover":{$value:`{palette.phone-primary-hover}`},"primary-soft":{$value:`{palette.phone-primary-soft}`},"primary-text":{$value:`{palette.phone-primary-text}`},"on-primary":{$value:`{palette.phone-on-primary}`},success:{$value:`{palette.phone-success}`},"success-text":{$value:`{palette.phone-success-text}`},"on-success":{$value:`{palette.phone-on-success}`},warning:{$value:`{palette.phone-warning}`},"warning-text":{$value:`{palette.phone-warning-text}`},"on-warning":{$value:`{palette.phone-on-warning}`},danger:{$value:`{palette.phone-danger}`},"danger-text":{$value:`{palette.phone-danger-text}`},"on-danger":{$value:`{palette.phone-on-danger}`},"danger-border":{$value:`{palette.phone-danger-border}`},info:{$value:`{palette.phone-info}`},"info-text":{$value:`{palette.phone-info-text}`},"on-info":{$value:`{palette.phone-on-info}`},neutral:{$value:`{palette.phone-neutral}`},"neutral-hover":{$value:`{palette.phone-neutral-hover}`},"on-neutral":{$value:`{palette.phone-on-neutral}`}},shadow:{card:{$value:{color:`{palette.phone-shadow-sm}`,offsetX:{value:0,unit:`px`},offsetY:{value:2,unit:`px`},blur:{value:4,unit:`px`},spread:{value:0,unit:`px`}},$extensions:{"com.webority":{elevation:2}}},popover:{$value:{color:`{palette.phone-shadow-lg}`,offsetX:{value:0,unit:`px`},offsetY:{value:8,unit:`px`},blur:{value:16,unit:`px`},spread:{value:0,unit:`px`}},$extensions:{"com.webority":{elevation:8}}},modal:{$value:{color:`{palette.phone-shadow-xl}`,offsetX:{value:0,unit:`px`},offsetY:{value:12,unit:`px`},blur:{value:24,unit:`px`},spread:{value:0,unit:`px`}},$extensions:{"com.webority":{elevation:12}}},drawer:{$value:{color:`{palette.phone-shadow-xl}`,offsetX:{value:0,unit:`px`},offsetY:{value:12,unit:`px`},blur:{value:24,unit:`px`},spread:{value:0,unit:`px`}},$extensions:{"com.webority":{elevation:12}}}}},Qe=`no meaning uses this step; propose one on the Webority UI board (bootstrap-ui.md → Tokens)`,$e=new Set(Object.keys(Xe.palette??{}).filter(e=>!e.startsWith(`$`))),N=new Map,et=/^\{palette\.([a-z0-9-]+)\}$/;for(let e of[Je,Ye,Ze])if(!(!e||!e.color||typeof e.color!=`object`)){for(let[t,n]of Object.entries(e.color))if(!t.startsWith(`$`)&&n&&typeof n==`object`&&typeof n.$value==`string`){let e=n.$value.match(et);if(e){let n=e[1],r=N.get(n);r||(r=new Set,N.set(n,r)),r.add(t)}}}function tt(e){let t=N.get(e);return t?[...t].sort():[]}function P(e,t){let n=tt(e);return n.length===0?Qe:t===`web`?`read the meaning: `+n.map(e=>`var(--color-${e})`).join(` or `):`read the meaning: `+n.map(e=>`theme.colors["${e}"]`).join(` or `)}function F(e){return Object.hasOwn(M,e)?`read the meaning: var(--color-${M[e]})`:Qe}var I=e=>e===`{`||e===`}`||e===`;`?` `:e;function nt(e,t){if(t===`markup`)return rt(e);let n=``,r=null,i=!1,a=!1;for(let o=0;o<e.length;o+=1){let s=e[o],c=e[o+1];if(a)s===`*`&&c===`/`?(a=!1,n+=` `,o+=1):n+=s===`
|
|
60
|
+
`?s:` `;else if(r)s===`\\`&&c!==void 0?(n+=`${I(s)}${I(c)}`,o+=1):(s===r&&(r=null),n+=I(s));else if(s===`"`||s===`'`)r=s,n+=s;else if(i)s===`)`&&(i=!1),n+=I(s);else if(s===`/`&&c===`*`)a=!0,n+=` `,o+=1;else if(t===`scss`&&s===`/`&&c===`/`){let t=e.indexOf(`
|
|
61
|
+
`,o);if(t===-1)break;o=t-1}else s===`(`&&n.slice(-3).toLowerCase()===`url`&&(i=!0),n+=s}return n}function rt(e){let t=[[`@*`,`*@`],[`<!--`,`-->`],[`/*`,`*/`]],n=``,r=0;for(;r<e.length;){let i=null;for(let n of t)if(e.startsWith(n[0],r)){i=n;break}if(!i){n+=e[r],r+=1;continue}let a=e.indexOf(i[1],r+i[0].length),o=a===-1?e.length:a+i[1].length;for(let t=r;t<o;t+=1)n+=e[t]===`
|
|
62
|
+
`?`
|
|
63
|
+
`:` `;r=o}return n}function it(e,t){let n=[0];for(let t=0;t<e.length;t+=1)e[t]===`
|
|
64
|
+
`&&n.push(t+1);let r=t.split(`
|
|
65
|
+
`);return e=>{let t=0,i=n.length-1;for(;t<i;){let r=t+i+1>>1;n[r]<=e?t=r:i=r-1}return{line:t+1,text:(r[t]??``).trim().slice(0,160)}}}var at=[...A].sort((e,t)=>t.length-e.length).join(`|`),ot=RegExp(`(?<![\\w$@.#-])(${at})\\s*:(?!:)([^;{}"\\n]*)`,`gi`),st=new Set(`aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen steelblue tan teal thistle tomato turquoise violet wheat white whitesmoke yellow yellowgreen`.split(` `)),ct=/(?<![\w&-])#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})(?![0-9a-f\w-])/,lt=/\b(?:rgba?|hsla?)\(\s*[-.\d]/,ut=/(?<![\w$@#.-])[a-z]+(?![\w-])/g,dt=[...Re].sort((e,t)=>t.length-e.length).join(`|`),ft=RegExp(`(?<![\\w$@.#-])(${dt})\\s*:(?!:)([^;{}"\\n]*)`,`gi`),pt=/var\(\s*--wui-([a-z0-9-]+)\s*[,)]/g,mt=Object.keys(M).join(`|`),ht=RegExp(`var\\(\\s*--bs-(${mt})(?:-rgb)?\\s*[,)]`,`g`),gt=RegExp(`(?<![\\w$-])\\$(${mt})(?![\\w-])`,`g`),_t={"palette-read":0,"raw-colour":1,"raw-measure":2,"root-font-size":3};function vt(e,t){let n=0,r=-1;for(let i=t-1;i>=0;--i){let t=e[i];if(t===`}`)n+=1;else if(t===`{`){if(n===0){r=i;break}--n}}if(r===-1)return!1;let i=r-1;for(;i>=0&&!`{};`.includes(e[i]);)--i;return e.slice(i+1,r).trim().split(`,`).some(e=>{let t=e.trim().toLowerCase();return t===`html`||t===`:root`||/^(?:html|:root)(?:\[|:|\.)/.test(t)})}function yt(e,t){let n=nt(e,t),r=it(n,e),i=[];for(let e of n.matchAll(ot)){let t=e[1].toLowerCase(),a=e[2];bt(t,a)&&i.push({rule:`raw-measure`,...r(e.index),hint:null}),(t===`font-size`||t===`font`)&&vt(n,e.index)&&i.push({rule:`root-font-size`,...r(e.index),hint:null})}for(let e of n.matchAll(ft))xt(e[2])&&i.push({rule:`raw-colour`,...r(e.index),hint:`read a meaning: var(--color-<name>); a product-only colour goes into theme/brand.tokens.json`});for(let e of n.matchAll(pt)){let t=e[1];$e.has(t)&&i.push({rule:`palette-read`,...r(e.index),hint:P(t,`web`)})}for(let e of n.matchAll(ht))i.push({rule:`palette-read`,...r(e.index),hint:F(e[1])});if(t===`scss`)for(let e of n.matchAll(gt)){let t=e.index+e[0].length;for(;t<n.length&&/\s/.test(n[t]);)t+=1;n[t]!==`:`&&i.push({rule:`palette-read`,...r(e.index),hint:F(e[1])})}return i.sort((e,t)=>e.line-t.line||_t[e.rule]-_t[t.rule]),i}function bt(e,t){let n=t.replace(/!important/gi,``).replace(/var\(\s*--[\w-]+/g,`var(`).replace(/\$[\w-]+/g,`$v`);for(let t of n.matchAll(/(?<![\w.#$@-])-?(?:\d+(?:\.\d+)?|\.\d+)([a-zA-Z%]*)/g)){if(parseFloat(t[0])===0)continue;let r=t[1].toLowerCase();if(ze.includes(r))return!0;if(r===``&&Fe.includes(e)){let r=t.index-1;for(;r>=0&&/\s/.test(n[r]);)--r;let i=t.index+t[0].length;for(;i<n.length&&/\s/.test(n[i]);)i+=1;let a=r>=0?n[r]:``,o=i<n.length?n[i]:``;if(a===`*`||o===`*`||(a===`/`||o===`/`)&&e!==`font`)continue;return!0}}return!1}function xt(e){let t=e.replace(/url\([^)]*\)/gi,`url()`).replace(/(["'])(?:\\.|(?!\1).)*\1/g,`""`).replace(/var\(\s*--[\w-]+/g,`var(`).replace(/!important/gi,``).toLowerCase();if(ct.test(t)||lt.test(t))return!0;for(let e of t.matchAll(ut))if(st.has(e[0]))return!0;return!1}var St=/(?:\bfrom\s*|\brequire\(\s*)["']react-native["']/,Ct=[...Le].sort((e,t)=>t.length-e.length),wt=[...Le,...A].sort((e,t)=>t.length-e.length),Tt=Ct.map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`|`),Et=wt.map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`|`),Dt=RegExp(`(?<![\\w$.])(?:(${Tt})|(["'])(${Et})\\2)\\s*:(?!:)`,`g`),Ot=[...j].sort((e,t)=>t.length-e.length),kt=[...j,...j.map(Gt)].sort((e,t)=>t.length-e.length),At=Ot.map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`|`),jt=kt.map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`|`),Mt=RegExp(`(?<![\\w$.])(?:(${At})|(["'])(${jt})\\2)\\s*:(?!:)`,`g`),Nt={"palette-read":0,"raw-colour":1,"raw-measure":2,"root-font-size":3},Pt=Object.keys(M).map(e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)).join(`|`),Ft=RegExp(`var\\(\\s*--bs-(${Pt})(?:-rgb)?\\s*[,)]`,`g`),It=/var\(\s*--wui-([a-z0-9-]+)\s*[,)]/g,Lt=/(?<![\w$])palette\s*(?:\?\.|\.|\[)/g,Rt=/(?<![\w$.])-?(?:\d+(?:\.\d+)?|\.\d+)(?![\w.])/g;function zt(e){return St.test(e)}function Bt(e,{phone:t}){let{blanked:n,lineStarts:r}=Vt(e),i=[];return Ht(n,r,e,i),Ut(n,r,e,i),Jt(n,r,e,i),Yt(n,r,e,i),t&&Xt(n,r,e,i),i.sort((e,t)=>e.line-t.line||Nt[e.rule]-Nt[t.rule]),i}function Vt(e){let t=[],n=[0],r=0,i=!1,a=!1,o=!1,s=!1,c=!1;for(;r<e.length;){let l=e[r],u=e[r+1];if(s){l===`
|
|
66
|
+
`?(s=!1,t.push(l),n.push(t.length)):t.push(` `),r++;continue}if(c){l===`*`&&u===`/`?(c=!1,t.push(` `,` `),r+=2):(l===`
|
|
67
|
+
`?(t.push(l),n.push(t.length)):t.push(` `),r++);continue}if(i){t.push(l),l===`
|
|
68
|
+
`&&n.push(t.length),l===`\\`?(t.push(e[r+1]),r+=2):(l===`'`&&(i=!1),r++);continue}if(a){t.push(l),l===`
|
|
69
|
+
`&&n.push(t.length),l===`\\`?(t.push(e[r+1]),r+=2):(l===`"`&&(a=!1),r++);continue}if(o){t.push(l),l===`
|
|
70
|
+
`&&n.push(t.length),l===`\\`?(t.push(e[r+1]),r+=2):(l==="`"&&(o=!1),r++);continue}if(l===`/`&&u===`/`){s=!0,t.push(` `,` `),r+=2;continue}if(l===`/`&&u===`*`){c=!0,t.push(` `,` `),r+=2;continue}if(l===`'`){i=!0,t.push(l),r++;continue}if(l===`"`){a=!0,t.push(l),r++;continue}if(l==="`"){o=!0,t.push(l),r++;continue}t.push(l),l===`
|
|
71
|
+
`&&n.push(t.length),r++}return{blanked:t.join(``),lineStarts:n}}function L(e,t){let n=0,r=t.length-1;for(;n<=r;){let i=n+r>>1;t[i]<=e?n=i+1:r=i-1}return r+1}function R(e,t){let n=e.split(`
|
|
72
|
+
`);return t>=1&&t<=n.length?n[t-1].trim().slice(0,160):``}function Ht(e,t,n,r){let i;for(;(i=Dt.exec(e))!==null;){let a=i.index,o=a-1;for(;o>=0&&/\s/.test(e[o]);)o--;if(o<0||e[o]!==`{`&&e[o]!==`,`)continue;let s=i[1],c=i[3],l=s||c,u=!!c,d=i.index+i[0].length-1+1,f=Wt(e,d);if(f!==-1&&Kt(e.slice(d,f),u?l:Gt(l))){let e=L(a,t);r.push({rule:`raw-measure`,line:e,text:R(n,e),hint:null})}}}function Ut(e,t,n,r){Mt.lastIndex=0;let i;for(;(i=Mt.exec(e))!==null;){let a=i.index,o=a-1;for(;o>=0&&/\s/.test(e[o]);)o--;if(o<0||e[o]!==`{`&&e[o]!==`,`)continue;let s=i.index+i[0].length-1+1,c=Wt(e,s);if(c===-1||!qt(e.slice(s,c)).some(({content:e})=>xt(e)))continue;let l=L(a,t);r.push({rule:`raw-colour`,line:l,text:R(n,l),hint:`read a meaning: theme.colors["<name>"] on phone, var(--color-<name>) on web; a product-only colour goes into theme/brand.tokens.json`})}}function Wt(e,t){let n=0,r=t,i=!1,a=!1,o=!1;for(;r<e.length;){let t=e[r];if(i){t===`\\`?r+=2:(t===`'`&&(i=!1),r++);continue}if(a){t===`\\`?r+=2:(t===`"`&&(a=!1),r++);continue}if(o){t===`\\`?r+=2:(t==="`"&&(o=!1),r++);continue}if(t===`'`){i=!0,r++;continue}if(t===`"`){a=!0,r++;continue}if(t==="`"){o=!0,r++;continue}if(t===`(`||t===`[`||t===`{`){n++,r++;continue}if(t===`)`||t===`]`||t===`}`){if(n===0)return r;n--,r++;continue}if(n===0&&(t===`,`||t===`}`||t===`)`||t===`]`||t===`;`))return r;r++}return-1}function Gt(e){return e.replace(/([A-Z])/g,(e,t)=>`-`+t.toLowerCase())}function Kt(e,t){let n=qt(e);for(let{content:e}of n)if(bt(t,e))return!0;let r=e;for(let{start:e,end:t}of n)r=r.slice(0,e)+`""`+r.slice(t);Rt.lastIndex=0;let i;for(;(i=Rt.exec(r))!==null;){if(parseFloat(i[0])===0)continue;let e=i.index-1;for(;e>=0&&/\s/.test(r[e]);)e--;if(e>=0&&`[*/`.includes(r[e]))continue;let t=i.index+i[0].length;for(;t<r.length&&/\s/.test(r[t]);)t++;if(!(t<r.length&&`*/`.includes(r[t])))return!0}return!1}function qt(e){let t=[],n=0,r=!1,i=!1,a=!1,o=-1;for(;n<e.length;){let s=e[n];if(r){s===`\\`?n+=2:s===`'`?(r=!1,t.push({start:o,end:n+1,content:e.slice(o+1,n)}),n++):n++;continue}if(i){s===`\\`?n+=2:s===`"`?(i=!1,t.push({start:o,end:n+1,content:e.slice(o+1,n)}),n++):n++;continue}if(a){if(s===`\\`)n+=2;else if(s==="`"){a=!1;let r=e.slice(o+1,n);r=r.replace(/\$\{[^}]*\}/g,``),t.push({start:o,end:n+1,content:r}),n++}else s===`$`&&e[n+1]===`{`?n+=2:n++;continue}if(s===`'`){r=!0,o=n,n++;continue}if(s===`"`){i=!0,o=n,n++;continue}if(s==="`"){a=!0,o=n,n++;continue}n++}return t}function Jt(e,t,n,r){let i;for(;(i=It.exec(e))!==null;){let e=i[1];if($e.has(e)){let a=L(i.index,t);r.push({rule:`palette-read`,line:a,text:R(n,a),hint:P(e,`web`)})}}}function Yt(e,t,n,r){let i;for(;(i=Ft.exec(e))!==null;){let e=i[1],a=L(i.index,t);r.push({rule:`palette-read`,line:a,text:R(n,a),hint:F(e)})}}function Xt(e,t,n,r){let i;for(;(i=Lt.exec(e))!==null;){let a=``,o=e.slice(i.index+i[0].length);if(i[0].endsWith(`[`)){let e=o.match(/^\s*(["'])([^"']*)\1/);e&&(a=e[2])}else{let e=o.match(/^\s*([\w$]+)/);e&&(a=e[1])}let s=L(i.index,t);r.push({rule:`palette-read`,line:s,text:R(n,s),hint:P(a,`phone`)})}}function Zt(e){let t=o(e);return!!(e.split(`/`).slice(0,-1).some(e=>He.includes(e))||Ue.some(t=>e.toLowerCase().includes(t))||t.includes(`.generated.`)||t.endsWith(`.min.css`)||/\.(?:test|spec)\.[cm]?[jt]sx?$/i.test(t))}function Qt(e,n=null){let i=n?n.map(t=>C(e,t)):null,a=T(e,Object.keys(Be).map(e=>`*${e}`)).filter(n=>t(l(e,n))&&!Zt(n)&&(!i||i.some(e=>e===`.`||n===e||n.startsWith(`${e}/`)))),o=[];for(let t of a){let n=c(t).toLowerCase(),i=Be[n],a=r(l(e,t),`utf8`),s=[];if(i===`scss`||i===`css`||i===`markup`)s=yt(a,i);else if(i===`script`){let e=zt(a);if(Ve.includes(n)&&!e)continue;s=Bt(a,{phone:e})}for(let e of s)o.push({id:`${e.rule}:${t}`,line:e.line,text:e.text,hint:e.hint})}return o.sort((e,t)=>e.id<t.id?-1:e.id>t.id?1:e.line-t.line)}function $t(e){let t={};for(let n of e)t[n.id]=(t[n.id]||0)+1;return t}var en=process.argv.slice(2),z=new Set(en.filter(e=>e.startsWith(`--`))),B=en.filter(e=>!e.startsWith(`--`)),tn=z.has(`--sync-hook`),V=e=>process.stdout.write(`${e}\n`),H=e=>process.stderr.write(`${e}\n`),nn=new Set([`--json`,`--baseline-init`,`--baseline-shrink`,`--sync-hook`]),rn=[...z].filter(e=>!nn.has(e));(rn.length||z.has(`--baseline-init`)&&z.has(`--baseline-shrink`)||tn&&(z.size>1||B.length))&&(H(`repo-checks: unknown or conflicting options ${rn.join(` `)}`.trim()),H(`usage: webority-repo-checks [--json] [--baseline-init | --baseline-shrink] [app folder ...]`),H(` webority-repo-checks --sync-hook`),process.exit(2));var U=be(process.cwd());if(U||(H(`repo-checks: not inside a git repository.`),process.exit(2)),tn){let t=l(U,O);n(s(t),{recursive:!0}),a(t,_),e(t,493),V(`repo-checks: wrote ${t}`),process.exit(0)}var W=Pe(U,B.length?B.map(e=>f(process.cwd(),e)):null).sort((e,t)=>e.pkg===t.pkg?0:e.pkg<t.pkg?-1:1),G=Qt(U,B.length?B.map(e=>f(process.cwd(),e)):null),K={findings:W.map(e=>ne(e.pkg,e.id)),counts:$t(G)},an=new Map(W.map(e=>[ne(e.pkg,e.id),e]));if(z.has(`--baseline-init`)){B.length&&(H(`repo-checks: --baseline-init reads the whole repository; run it without folder arguments.`),process.exit(2)),t(l(U,`.webority/repo-checks-baseline.json`))&&(H(`repo-checks: ${p} already exists. It only shrinks: fix a new finding, or run --baseline-shrink after fixing old ones.`),process.exit(2)),ie(U,ae(K));let e=Object.keys(K.counts).length;V(`repo-checks: recorded ${W.length} finding(s) and ${e} counted file(s) (${G.length} code finding(s)) in ${p}.`),process.exit(0)}var q=(()=>{try{return re(U)}catch(e){throw e instanceof m&&(H(`repo-checks: ${e.message}`),process.exit(2)),e}})();if(z.has(`--baseline-shrink`)){B.length&&(H(`repo-checks: --baseline-shrink reads the whole repository; run it without folder arguments.`),process.exit(2)),q===null&&(H(`repo-checks: no ${p}; run webority-repo-checks --baseline-init first.`),process.exit(2));let e=g(q,K);ie(U,se(q,K)),V(`repo-checks: dropped ${e.stale.length} fixed finding(s) and lowered ${e.fallen.length} count(s) in ${p}.`),process.exit(0)}var J=new Set(B.map(e=>d(U,f(process.cwd(),e)).split(`\\`).join(`/`)||`.`)),on=B.length?{pkgs:J,dirs:[...J]}:null,Y=g(oe(q??{version:2,findings:[],counts:{}},on),K),sn={"raw-measure":We,"palette-read":qe,"raw-colour":Ge,"root-font-size":Ke},cn=e=>sn[e.slice(0,e.indexOf(`:`))],X=Y.fresh.map(e=>an.get(e)),Z=Y.known.map(e=>an.get(e)),Q=Y.over.map(e=>({pkg:`.`,id:e.id,message:`${e.current} found, ${e.baseline} recorded. ${cn(e.id)}`,lines:G.filter(t=>t.id===e.id).map(({line:e,text:t,hint:n})=>({line:e,text:t,hint:n}))})),$=Y.within.map(e=>({pkg:`.`,id:e.id,message:`${e.current} found, ${e.baseline} recorded.`})),ln=[...Y.stale.map(h),...Y.fallen.map(e=>[`.`,e.id])];if(z.has(`--json`)&&(V(JSON.stringify({root:U,new:[...X,...Q],known:[...Z,...$],stale:ln},null,2)),process.exit(+!![...X,...Q].length)),X.length||Q.length){if(X.length){H(`repo-checks: ${X.length} new finding(s)`);let e=null;for(let t of X)t.pkg!==e&&(e=t.pkg,H(` ${e}`)),H(` - ${t.id}: ${t.message}`)}if(Q.length){H(`repo-checks: ${Q.length} file(s) above their recorded count`);for(let e of Q){H(` ${e.id}: ${e.message}`);for(let t of e.lines)H(` ${t.line}: ${t.text}`),t.hint!==null&&H(` ${t.hint}`)}}process.exit(1)}if(V(`repo-checks: no new findings.`),Z.length||$.length){let e=Y.within.reduce((e,t)=>e+t.current,0);V(`repo-checks: ${Z.length} known finding(s) and ${e} counted code finding(s) in ${$.length} file(s) recorded in ${p}.`)}if(Y.stale.length){V(`repo-checks: ${Y.stale.length} baseline entr${Y.stale.length===1?`y is`:`ies are`} fixed; drop them with webority-repo-checks --baseline-shrink:`);for(let e of Y.stale.map(h))V(` ${e[0]} ${e[1]}`)}if(Y.fallen.length){V(`repo-checks: ${Y.fallen.length} count(s) fell; record them with webority-repo-checks --baseline-shrink:`);for(let e of Y.fallen)V(` ${e.id} ${e.baseline} -> ${e.current}`)}process.exit(0);export{};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/repo-checks",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Repository checks for Webority React web portals
|
|
3
|
+
"version": "0.88.0",
|
|
4
|
+
"description": "Repository checks for Webority React web portals, React Native apps and Razor sites: banned and required dependencies, pnpm only, exact pins, the shared Biome preset, and token use in style, markup and component code. Run before a push; existing findings and per-file counts sit in a baseline that only shrinks.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"publishConfig": {
|