refactor(js): extract import/export module from app.js monofile (§3.1)

Third slice of the app.js split. Moves the encrypted export container,
CSV/JSON import parsing (parseCSV, findColumn, parseEntriesFromCSV,
parseEntriesFromJSON), and the doImport/doExport/doExportCSV flows to
js/app.import.js. encryptImportEntry moves here too (also called by
app.sync.js — resolved via shared global scope at call time).

- Byte-for-byte identical to the extracted block; no duplicate const;
  no top-level import ref left in app.js.
- Load order: BEFORE app.js (pure declarations, no top-level side effects),
  alongside app.crypto.js. Full order: argon2 → crypto → import → app → sync.
- index.html + BuildAssets whitelist + harness APP_PARTS updated.
- Safety net: the 14 CSV tests exercise parseCSV/parseEntriesFromCSV from
  the extracted file and stay green (42/42).

app.js: 11936 → 10253 lines (crypto + sync + import now separate, ~1700
lines moved into 3 modules).

NOTE: assets.res not regenerated here (needs brcc32/Delphi) — run
BuildAssets before the next Delphi build to embed js/app.import.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
r-zakarya
2026-07-05 16:24:11 +01:00
parent 2d309f8988
commit 97a19836a0
7 changed files with 1036 additions and 1007 deletions
+6
View File
@@ -33,11 +33,16 @@ visibles des suivants exactement comme dans le monofichier. Ordre actuel :
``` ```
js/argon2.js (IIFE, globalThis.NobleArgon2) js/argon2.js (IIFE, globalThis.NobleArgon2)
js/app.crypto.js (KDF, verifier, encrypt/decrypt — extrait §3.1) js/app.crypto.js (KDF, verifier, encrypt/decrypt — extrait §3.1)
js/app.import.js (export container + import CSV/JSON — extrait §3.1)
js/app.js (le reste : state, Bridge, api, UI…) js/app.js (le reste : state, Bridge, api, UI…)
js/app.sync.js (WebDAV + merge — extrait §3.1, APRÈS app.js car js/app.sync.js (WebDAV + merge — extrait §3.1, APRÈS app.js car
effet de bord top-level `Bridge.onWebdavResult = …`) effet de bord top-level `Bridge.onWebdavResult = …`)
``` ```
`app.import.js` contient `encryptImportEntry`, appelé aussi par
`app.sync.js` (`applyRemoteSnapshot`) — OK, référence cross-fichier résolue
au call-time via le scope global partagé.
Note ordre : un module **sans** exécution top-level (que des déclarations, Note ordre : un module **sans** exécution top-level (que des déclarations,
comme `app.crypto.js`) peut se charger AVANT `app.js`. Un module **avec** un comme `app.crypto.js`) peut se charger AVANT `app.js`. Un module **avec** un
effet de bord top-level qui touche un global d'`app.js` (`Bridge`, `state`…) effet de bord top-level qui touche un global d'`app.js` (`Bridge`, `state`…)
@@ -94,6 +99,7 @@ parsing CSV d'import, et l'arbitrage merge/tombstone de sync
| Handlers REST | `delphi-backend/Handlers/PM.Handler.*.pas` | | Handlers REST | `delphi-backend/Handlers/PM.Handler.*.pas` |
| Frontend principal (en cours de découpage §3.1) | `js/app.js` | | Frontend principal (en cours de découpage §3.1) | `js/app.js` |
| Crypto frontend (KDF, verifier, AES-GCM) — extrait §3.1 | `js/app.crypto.js` | | Crypto frontend (KDF, verifier, AES-GCM) — extrait §3.1 | `js/app.crypto.js` |
| Import/export frontend (CSV/JSON parse, export container) — extrait §3.1 | `js/app.import.js` |
| Sync frontend (WebDAV, snapshot, merge) — extrait §3.1 | `js/app.sync.js` | | Sync frontend (WebDAV, snapshot, merge) — extrait §3.1 | `js/app.sync.js` |
| Argon2id vendé (bundle `@noble/hashes`, IIFE) | `js/argon2.js` | | Argon2id vendé (bundle `@noble/hashes`, IIFE) | `js/argon2.js` |
| HTML racine | `index.html` | | HTML racine | `index.html` |
+5 -1
View File
@@ -228,8 +228,12 @@ réécriture des call-sites, risque quasi nul vs conversion en modules ES).
identique, 42 tests verts, pas de `const` dupliqué. Chargé AVANT app.js. identique, 42 tests verts, pas de `const` dupliqué. Chargé AVANT app.js.
-`js/app.sync.js` extrait (WebDAV, snapshot, merge `applyRemoteSnapshot`) -`js/app.sync.js` extrait (WebDAV, snapshot, merge `applyRemoteSnapshot`)
— byte-for-byte identique, couvert par les tests merge, chargé APRÈS app.js — byte-for-byte identique, couvert par les tests merge, chargé APRÈS app.js
(effet de bord top-level `Bridge.onWebdavResult`). Pattern + règles d'ordre (effet de bord top-level `Bridge.onWebdavResult`).
-`js/app.import.js` extrait (export container + parsing CSV/JSON +
`doImport`/`doExport`) — byte-for-byte identique, couvert par les 14 tests
CSV, chargé AVANT app.js (pures déclarations). Pattern + règles d'ordre
documentés dans CLAUDE.md « Découpage frontend ». documentés dans CLAUDE.md « Découpage frontend ».
- `app.js` : 11 936 → **10 253 lignes** (crypto + sync + import sortis).
- Reste à extraire (grosses sections cohésives) : slideover, settings, - Reste à extraire (grosses sections cohésives) : slideover, settings,
quicksearch, autofill, auto-backup… quicksearch, autofill, auto-backup…
-`node --check` en pré-étape de `BuildAssets.ps1` : **déjà fait** (cf. §3.2). -`node --check` en pré-étape de `BuildAssets.ps1` : **déjà fait** (cf. §3.2).
+1
View File
@@ -53,6 +53,7 @@ $patterns = @(
'index.html', 'index.html',
'js\argon2.js', 'js\argon2.js',
'js\app.crypto.js', 'js\app.crypto.js',
'js\app.import.js',
'js\app.js', 'js\app.js',
'js\app.sync.js', 'js\app.sync.js',
'css\style.css' 'css\style.css'
+1
View File
@@ -1194,6 +1194,7 @@
<script src="js/argon2.js"></script> <script src="js/argon2.js"></script>
<script src="js/app.crypto.js"></script> <script src="js/app.crypto.js"></script>
<script src="js/app.import.js"></script>
<script src="js/app.js"></script> <script src="js/app.js"></script>
<script src="js/app.sync.js"></script> <script src="js/app.sync.js"></script>
</body> </body>
+1020
View File
File diff suppressed because it is too large Load Diff
+2 -1005
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -30,7 +30,7 @@ const { webcrypto } = require('node:crypto');
// top-level const/let across separate runInContext calls, so we CONCATENATE // top-level const/let across separate runInContext calls, so we CONCATENATE
// the app.* parts (in <script> load order) into one script. argon2.js is a // the app.* parts (in <script> load order) into one script. argon2.js is a
// self-contained IIFE and loads separately (see below). // self-contained IIFE and loads separately (see below).
const APP_PARTS = ['app.crypto.js', 'app.js', 'app.sync.js'].map(f => path.join(__dirname, '..', f)); const APP_PARTS = ['app.crypto.js', 'app.import.js', 'app.js', 'app.sync.js'].map(f => path.join(__dirname, '..', f));
// In-memory Storage stub (Web Storage API surface used by app.js). // In-memory Storage stub (Web Storage API surface used by app.js).
function makeStorage() { function makeStorage() {