Compare commits

..

No commits in common. "master" and "issue-121-xmldom-js-yaml-floors" have entirely different histories.

5 changed files with 58 additions and 233 deletions

6
.gitignore vendored
View file

@ -40,9 +40,3 @@ yarn-error.*
# generated native folders
/ios
/android
# Next.js build output (web companion)
/.next/
# autopilot daily reports
/reports/

View file

@ -1,26 +1,21 @@
# STATE — simpl-liste
> Derniere MAJ : 2026-10-06 (par fix-issue #133, #134, #135 — PR #138)
> Derniere MAJ : 2026-09-25 (par fix-issue #117)
## Position actuelle
Version 1.6.6 (versionCode 18). `npm audit` = 40 entrees (0 critical) au 2026-10-06 apres
PR #138, pour 5 advisories sans correctif publie (le reste est de la cascade de parents) :
`braces` (high, #130), `node-forge` (high, #123), `postcss-selector-parser` GHSA-rj75
(moderate, #136, sortie = tailwind 4), `sprintf-js` (moderate, #137) et la chaine
`expo-router` -> `query-string@7` -> `decode-uri-component` (risque accepte #120). Toutes
sont de l'outillage de build/dev : rien dans l'APK.
Version 1.6.6 (versionCode 18). Remediation securite en continu via overrides.
Apres #117 (PR #119, 2026-09-25), `npm audit` = 6 findings : **2 HIGH** (`@xmldom/xmldom`
<=0.8.14 et `js-yaml` 3.15.1 / 4.3.1, advisories publiees apres les planchers poses
en avril/septembre — pas encore d'issue), 3 moderate (chaine `expo-router` ->
`query-string@7` -> `decode-uri-component`, #120 bloquee sur un bump de SDK), 1 low
(`postcss-selector-parser`).
La remediation passe par des overrides de plancher dans `package.json` :
`esbuild`, `@xmldom/xmldom@^0.8.15`, `uuid`, `postcss`, `js-yaml` (3.15.2 / 4.3.2), `brace-expansion` (1.1.21 / 2.1.7 / 5.0.12),
`@babel/core`, `browserslist@^4.28.7`, `@react-navigation/core@^7.22.1`,
`http-cache-semantics@^4` (4.3.0), `postcss-selector-parser@^6` (6.1.3), `source-map-js@^1` (1.2.2),
`react-devtools-core > shell-quote` (^1.11.0), `@expo/cli > compression` (^1.8.2), et les 14
`esbuild`, `@xmldom/xmldom`, `uuid`, `postcss`, `js-yaml`, `brace-expansion`,
`@babel/core`, `browserslist@^4.28.7`, `@react-navigation/core@^7.22.1`, et les 14
paquets `metro@^0.83.8`. Le smoke test verrouille la chaine de build (presets Expo
hoistes a la racine, un seul SDK Expo, metro 0.83.x partout) et les planchers
`brace-expansion` / `undici` / `http-cache-semantics` / `postcss-selector-parser` /
`shell-quote` / `compression` / `source-map-js` (plancher + appel de l'API consommee) /
comportement de `minimatch` (majeurs 3, 9, 10).
hoistes a la racine, un seul SDK Expo, metro 0.83.x partout).
**Caveat sur l'override metro** (releve par la review de PR #114) : `0.83.3 -> 0.83.8`
n'est pas un bump de patch pur cote API privee. Trois shims de `@expo/metro@54.2.0`,
@ -36,21 +31,18 @@ Coolify malgre la spec). Procedure en memoire `simpl-liste-web-deploy`.
## Decisions recentes
- 2026-10-06 : #133, #134, #135 fermees (PR #138 merged) — `shell-quote` ^1.11.0 (CRITICAL GHSA-pqg4, releve le plancher de #95), `@expo/cli > compression` ^1.8.2 (HIGH), `source-map-js@^1.0.0` ^1.2.2 (HIGH, pipeline CSS). `npm audit` 43 -> 40, critical 0. Export identique octet pour octet (44 fichiers), serveur de dev sert le bundle en gzip. Ouvertes le meme jour en plancher : #136 (`postcss-selector-parser` GHSA-rj75, aucun correctif 6.x) et #137 (`sprintf-js`, tete publiee vulnerable). `/analyse-vulnerabilite` cherche desormais les antecedents fermes avant de proposer.
- 2026-10-05 : #128 et #129 fermees (PR #131 merged) — planchers version-scoped `http-cache-semantics@^4.0.0` -> ^4.3.0 (GHSA-ch52 high : l'advisory ne liste aucun patch, mais 4.3.0 sort de la borne `<=4.2.0` ; tunnel `@expo/ngrok` seulement) et `postcss-selector-parser@^6.0.0` -> ^6.1.3 (low, pipeline tailwind). `npm audit` 33 -> 31. Preuve du livrable : bundle JS (`expo export --no-bytecode --clear`) identique octet pour octet. **Le hash `.hbc` n'est pas une preuve** : Hermes n'est pas deterministe ici (deux exports du meme arbre different).
- 2026-10-05 : #126 fermee, acceptation de #120 maintenue — `decode-uri-component@0.5.0` est ESM pur, `query-string@7` le `require()`. Declencheur de sortie : `expo-router@58.0.13` (SDK 58) retire `query-string`, pas encore backporte sur sdk-54..57. #130 ouverte : `braces` plancher (3.0.3 = tete publiee, vulnerable).
- 2026-10-02 : #124 et #125 fermees (PR #127 merged) — planchers `brace-expansion` ^1.1.21 / ^2.1.7 / ^5.0.12 (9 advisories DoS neuves, toujours version-scoped) et `@expo/cli > undici` ^6.28.1 (resolu 6.29.0). Outillage de build seulement. Trois gardes au smoke test, dont le test `minimatch` qui manquait depuis #103. `npm audit` 12 -> 10. Ouvertes le meme jour : #123 (`node-forge`, tete publiee 1.4.0 vulnerable) et #126 (`decode-uri-component@0.5.0` publiee).
- 2026-09-27 : #120 fermee en risque accepte (rectification du cadrage « attend un bump de SDK »). Aucune version d'expo-router (jusqu'a 58.0.8 / sdk-57) ne quitte `query-string@7`. expo-router n'appelle que `queryString.stringify()`, qui ne touche jamais `decode-uri-component` (le seul `parse()` du fork est commente) : code vulnerable inatteignable. A re-verifier a chaque bump d'expo-router.
- 2026-09-25 : #121 fermee (PR #122 merged) — planchers `@xmldom/xmldom@^0.8.15` et `js-yaml` ^3.15.2 / ^4.3.2 (advisories HIGH du 2026-09-08, outillage de build seulement, hash du bundle Hermes inchange). Le Defenseur ne les avait pas signalees : hypothese de dedup par paquet contre issues fermees -> agent-defenseurs#139.
- 2026-09-25 : #117 fermee (PR #119 merged) — override `@react-navigation/core@^7.22.1`, qui ne depend plus de `query-string` (GHSA-vcc3-ghjq-m6fr). Lock : 2 entrees. PR #118 du Defenseur fermee : son `npm audit fix` global desinstallait `babel-preset-expo`/`@expo/metro-config` de la racine et nichait un Expo 57 (build casse, tests verts). Gardes de toolchain ajoutees au smoke test. Residu `expo-router` -> #120.
- 2026-09-04 : #115 ouverte + PR #116 — `browserslist@^4.28.7` (2 advisories HIGH publiees le 2026-09-01, `first_patched_version = 4.28.7`). Resout en 4.28.9, derniere HIGH de l'arbre. Bundle Hermes au hash identique avant/apres : cibles de compilation inchangees.
- 2026-09-04 : #112 fermee doublon de #108 ; PR #113 fermee sans merge (son diff ne contenait aucune occurrence d'`image-size` — 633/584 de churn de lockfile sans rapport).
- 2026-09-04 : #108 fermee (PR #114 merged) — `image-size` retiree de l'arbre via overrides `metro@^0.83.8`. Le blocage upstream tient toujours (`first_patched_version = None`, `2.0.2` reste la derniere publiee) ; c'est metro qui a **supprime** la dependance et vendore un parseur reduit sans les formats ICNS/JXL/HEIF vises. Backport sur la ligne 0.83.x le 2026-08-19 — pas besoin du bump de SDK Expo anticipe. 9 HIGH -> 1 HIGH.
- 2026-07-27 : #68 merged (PR #101) — Feedback Hub integre (bouton Reglages > A propos, POST feedback.lacompagniemaximus.com app_id simpl-liste, opt-in contexte + identite Loi 25 ; client sans dependance teste via node:test).
- 2026-05-30 : #90 merged (PR #93, ThemeToggle eslint-disable) + premier deploy web depuis 7 sem (rsync source/ + docker compose --build sur VPS) — #70 et #90 live sur liste.lacompagniemaximus.com.
- 2026-05-30 : PR #89 merged — display name web resolu via userInfo (ordre fallback de la vitrine), fix #70.
- 2026-05-30 : nettoyage lint web/ (PR #91, 2 prefer-const + import inutilise) ; #90 analyse (ThemeToggle set-state-in-effect, decision : eslint-disable documente).
- 2026-05-10 : Aligne 6 patches Expo SDK 54 via expo install --fix — expo-doctor 17/17 (ref #87)
- 2026-05-08 : Defenseur rerun confirme 0 findings — overrides existants suffisent, pas de PR necessaire (ref #81)
## Blockers actifs
- #120 (`status:blocked`) : `decode-uri-component` via `expo-router` 6.0.x -> `query-string@7`. Seul correctif (0.5.0) ESM-only, non overridable ; attend un bump de SDK Expo.
- Essai sur appareil a faire avant le prochain APK : core 7.22.1 tourne avec native/native-stack/bottom-tabs publies contre 7.14 (deep link vers une tache, onglets, pile).
- #130 : `braces` <=3.0.3 sans version corrigee. Surveiller `braces` > 3.0.3 ou `micromatch` qui la largue.
- #123 : `node-forge` <=1.4.0 sans version corrigee. Surveiller `node-forge` > 1.4.0 ou le retrait de la dependance par `@expo/code-signing-certificates` / `@expo/cli`.
- #136 : `postcss-selector-parser` GHSA-rj75 sans correctif 6.x. Surveiller un backport 6.x ou la migration NativeWind 5 / tailwind 4.
- #137 : `sprintf-js` <=1.1.3 sans version corrigee. Surveiller une version hors borne ou une `@istanbuljs/load-nyc-config` 2.x.

77
package-lock.json generated
View file

@ -3289,9 +3289,9 @@
}
},
"node_modules/@react-native/codegen/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@ -4338,9 +4338,9 @@
}
},
"node_modules/brace-expansion": {
"version": "5.0.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
"integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
@ -4861,15 +4861,14 @@
}
},
"node_modules/compression": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.2.tgz",
"integrity": "sha512-o8vI5RE5A6EVVOd9o41jKp41aJom+QTEO/Bx8MYNjexMo/Bv2WOjUfZr+aL0WnYSgymUy6zeguqLTsIhV0gMvQ==",
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
"integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
"license": "MIT",
"dependencies": {
"bytes": "3.1.2",
"compressible": "~2.0.18",
"debug": "2.6.9",
"destroy": "1.2.0",
"negotiator": "~0.6.4",
"on-headers": "~1.1.0",
"safe-buffer": "5.2.1",
@ -4877,10 +4876,6 @@
},
"engines": {
"node": ">= 0.8.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/compression/node_modules/debug": {
@ -6409,9 +6404,9 @@
}
},
"node_modules/expo/node_modules/brace-expansion": {
"version": "2.1.7",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
"integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz",
"integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
@ -7073,9 +7068,9 @@
}
},
"node_modules/http-cache-semantics": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.3.0.tgz",
"integrity": "sha512-M5t5LlJpS1UHMjvwRQVdFHvPISGeLAxNcrWuJkeGh0KxsqCHZ1O3NXZU/8x7cD0BDcGW8kapxMKTvwlqrNkHkA==",
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
"license": "BSD-2-Clause"
},
"node_modules/http-errors": {
@ -9687,9 +9682,9 @@
}
},
"node_modules/postcss-selector-parser": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz",
"integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==",
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
@ -10562,9 +10557,9 @@
}
},
"node_modules/react-native/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@ -10982,9 +10977,9 @@
}
},
"node_modules/rimraf/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@ -11288,9 +11283,9 @@
}
},
"node_modules/shell-quote": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.12.0.tgz",
"integrity": "sha512-PcByqNyT/38F2kDNi006HAMRJaULuBzq/FOsw3qdZvX/GA9W/jamDaRskgHjubHiftXK5sIFxLNkvrXUwcof6Q==",
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz",
"integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -11359,9 +11354,9 @@
}
},
"node_modules/source-map-js": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
"integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@ -11708,9 +11703,9 @@
}
},
"node_modules/test-exclude/node_modules/brace-expansion": {
"version": "1.1.21",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
"integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
"version": "1.1.18",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
@ -11936,9 +11931,9 @@
}
},
"node_modules/undici": {
"version": "6.29.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.29.0.tgz",
"integrity": "sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==",
"version": "6.28.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
"integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
"license": "MIT",
"engines": {
"node": ">=18.17"

View file

@ -71,24 +71,20 @@
"@xmldom/xmldom": "^0.8.15",
"uuid": "^11.1.1",
"postcss": "^8.5.18",
"postcss-selector-parser@^6.0.0": "^6.1.3",
"source-map-js@^1.0.0": "^1.2.2",
"http-cache-semantics@^4.0.0": "^4.3.0",
"js-yaml@^3.0.0": "^3.15.2",
"js-yaml@^4.0.0": "^4.3.2",
"brace-expansion@^1.0.0": "^1.1.21",
"brace-expansion@^2.0.0": "^2.1.7",
"brace-expansion@^5.0.0": "^5.0.12",
"brace-expansion@^1.0.0": "^1.1.18",
"brace-expansion@^2.0.0": "^2.1.4",
"brace-expansion@^5.0.0": "^5.0.9",
"@babel/core": "^7.29.6",
"browserslist": "^4.28.7",
"@expo/cli": {
"compression": "^1.8.2",
"ws": "^8.20.1",
"undici": "^6.28.1",
"undici": "^6.28.0",
"tar": "^7.5.21"
},
"react-devtools-core": {
"shell-quote": "^1.11.0",
"shell-quote": "^1.8.4",
"ws": "^7.5.11"
},
"react-native": {

View file

@ -264,158 +264,6 @@ check('@react-navigation/core deep link round trip keeps query params', () => {
assert.equal(getPathFromState(state, config), '/task/abc?x=1&y=a%20b');
});
// --- Override floors for build-tool transitive deps (#124, #125) ---
// brace-expansion is overridden per major (version-scoped): a blanket override
// forces one major onto every minimatch and breaks minimatch@3 (#103). The
// floors below are the patched head of each major; any other major is either
// vulnerable (4.x) or unexpected, and must fail loudly.
function versionAtLeast(version, floor) {
const a = version.split('.').map(Number);
const b = floor.split('.').map(Number);
for (let i = 0; i < 3; i++) {
if (a[i] !== b[i]) return a[i] > b[i];
}
return true;
}
const BRACE_EXPANSION_FLOORS = { 1: '1.1.21', 2: '2.1.7', 5: '5.0.12' };
check('every installed brace-expansion copy is at or above its major floor', () => {
const copies = installedCopies('brace-expansion');
assert.ok(copies.length > 0, 'brace-expansion is not installed');
const strays = copies.filter((c) => {
const floor = BRACE_EXPANSION_FLOORS[majorOf(c.version)];
return !floor || !versionAtLeast(c.version, floor);
});
assert.deepEqual(
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
[],
`expected floors ${JSON.stringify(BRACE_EXPANSION_FLOORS)}`
);
});
check('every installed undici copy is >= 6.28.1', () => {
const copies = installedCopies('undici');
assert.ok(copies.length > 0, 'undici is not installed');
const strays = copies.filter((c) => !versionAtLeast(c.version, '6.28.1'));
assert.deepEqual(
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
[],
'undici must be >= 6.28.1'
);
});
// --- Override floors (#128, #129) ---
// http-cache-semantics: version-scoped to major 4, a single copy (@expo/ngrok > got).
// postcss-selector-parser: version-scoped to major 6 (tailwindcss@3 pipeline);
// any other major is unexpected and must fail loudly.
check('every installed http-cache-semantics copy is >= 4.3.0', () => {
const copies = installedCopies('http-cache-semantics');
assert.ok(copies.length > 0, 'http-cache-semantics is not installed');
const strays = copies.filter((c) => !versionAtLeast(c.version, '4.3.0'));
assert.deepEqual(
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
[],
'http-cache-semantics must be >= 4.3.0'
);
});
check('every installed postcss-selector-parser copy is 6.x and >= 6.1.3', () => {
const copies = installedCopies('postcss-selector-parser');
assert.ok(copies.length > 0, 'postcss-selector-parser is not installed');
const strays = copies.filter(
(c) => majorOf(c.version) !== '6' || !versionAtLeast(c.version, '6.1.3')
);
assert.deepEqual(
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
[],
'postcss-selector-parser must be 6.x >= 6.1.3'
);
});
// --- Override floors (#133, #134, #135) ---
// shell-quote: scoped to react-devtools-core (raised from #95's ^1.8.4).
// compression: scoped to @expo/cli (dev server middleware).
// source-map-js: version-scoped to major 1 (postcss, tailwindcss pipeline).
// Each floor is paired with a call to the API its consumer actually uses.
check('every installed shell-quote copy is >= 1.11.0 and still quotes/parses', () => {
const copies = installedCopies('shell-quote');
assert.ok(copies.length > 0, 'shell-quote is not installed');
const strays = copies.filter((c) => !versionAtLeast(c.version, '1.11.0'));
assert.deepEqual(
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
[],
'shell-quote must be >= 1.11.0'
);
for (const c of copies) {
const { quote, parse } = require(c.dir);
const where = `shell-quote ${c.version} at ${path.relative(ROOT, c.dir)}`;
assert.equal(quote(['code', '-g', 'a b.js:1']), "code -g 'a b.js:1'", `${where}: quote`);
assert.deepEqual(parse('a "b c" d'), ['a', 'b c', 'd'], `${where}: parse`);
}
});
check('every installed compression copy is >= 1.8.2 and builds a middleware', () => {
const copies = installedCopies('compression');
assert.ok(copies.length > 0, 'compression is not installed');
const strays = copies.filter((c) => !versionAtLeast(c.version, '1.8.2'));
assert.deepEqual(
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
[],
'compression must be >= 1.8.2'
);
for (const c of copies) {
const middleware = require(c.dir)();
assert.equal(typeof middleware, 'function', `compression ${c.version}: middleware`);
assert.equal(middleware.length, 3, `compression ${c.version}: (req, res, next) signature`);
}
});
check('every installed source-map-js copy is 1.x >= 1.2.2 and round-trips a mapping', () => {
const copies = installedCopies('source-map-js');
assert.ok(copies.length > 0, 'source-map-js is not installed');
const strays = copies.filter(
(c) => majorOf(c.version) !== '1' || !versionAtLeast(c.version, '1.2.2')
);
assert.deepEqual(
strays.map((c) => `${c.version} at ${path.relative(ROOT, c.dir)}`),
[],
'source-map-js must be 1.x >= 1.2.2'
);
for (const c of copies) {
const { SourceMapGenerator, SourceMapConsumer } = require(c.dir);
const gen = new SourceMapGenerator({ file: 'out.css' });
gen.addMapping({
source: 'in.css',
original: { line: 3, column: 2 },
generated: { line: 1, column: 0 },
});
const pos = new SourceMapConsumer(gen.toJSON()).originalPositionFor({ line: 1, column: 0 });
const where = `source-map-js ${c.version} at ${path.relative(ROOT, c.dir)}`;
assert.deepEqual([pos.source, pos.line, pos.column], ['in.css', 3, 2], where);
}
});
// The call that broke under the blanket override: each minimatch copy must
// still expand braces through its own brace-expansion major.
check('every installed minimatch copy still matches globs and braces', () => {
const copies = installedCopies('minimatch');
const majors = [...new Set(copies.map((c) => majorOf(c.version)))].sort();
assert.deepEqual(majors, ['10', '3', '9'], 'expected minimatch majors 3, 9 and 10');
for (const c of copies) {
const mod = require(c.dir);
const minimatch = mod.minimatch || mod; // v3 exports the function itself
const where = `minimatch ${c.version} at ${path.relative(ROOT, c.dir)}`;
assert.equal(minimatch('foo/bar.js', '**/*.js'), true, `${where}: globstar`);
assert.equal(minimatch('a/b.js', 'a/{b,c}.js'), true, `${where}: brace match`);
assert.equal(minimatch('a/d.js', 'a/{b,c}.js'), false, `${where}: brace miss`);
assert.equal(minimatch('f3.js', 'f{1..3}.js'), true, `${where}: numeric range`);
}
});
if (failed === 0) {
console.log('\nsmoke OK');
process.exit(0);