From 0dfec6edbba3baa753461bf6f96e7abaf991e2ff Mon Sep 17 00:00:00 2001 From: Florian Cerizay Date: Tue, 27 Oct 2026 15:25:59 +0100 Subject: [PATCH] =?UTF-8?q?SQL=20des=20cl=C3=A9s=20=C3=A9trang=C3=A8res=20?= =?UTF-8?q?et=20conditions,=20badges=20color=C3=A9s,=20boutons=20=C2=AB=20?= =?UTF-8?q?semblables=20=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - src/core/sql.ts : découpage d'une clé étrangère ou d'une condition (mots-clés connus, chaînes, nombres, identifiants), testé - SqlText : mots-clés en bleu gras, chaînes en vert ; dans la vue d'une table, chaque clé étrangère et condition s'affiche en SQL et se modifie par un crayon (un élément vide s'édite d'emblée) - badges de présence des fichiers attendus colorés (obligatoire rouge, recommandé orange, facultatif vert, thème sombre compris) ; contraintes des colonnes colorées (valeur obligatoire, colonne obligatoire, unique) - « Monter » et « Descendre » retirés des fichiers attendus - bouton « Équivalents » : « Appliquer aux colonnes / fichiers / listes semblables » - tests : sql, e2e (SQL, badges, boutons), test des clés étrangères par le crayon Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + src/core/sql.ts | 25 ++++++++++++++++ src/ui/components/EquivalentsDialog.vue | 5 +++- src/ui/components/ModelView.vue | 11 +++---- src/ui/components/SqlText.vue | 33 ++++++++++++++++++++ src/ui/components/TableView.vue | 40 ++++++++++++++++++------- src/ui/theme.css | 36 ++++++++++++++++++++++ tests/e2e/002-us2-table.spec.ts | 3 ++ tests/e2e/sql-badges.spec.ts | 29 ++++++++++++++++++ tests/unit/sql.test.ts | 28 +++++++++++++++++ 10 files changed, 193 insertions(+), 18 deletions(-) create mode 100644 src/core/sql.ts create mode 100644 src/ui/components/SqlText.vue create mode 100644 tests/e2e/sql-badges.spec.ts create mode 100644 tests/unit/sql.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 3143459..3f755ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ et le versionnement sur [Semantic Versioning](http://semver.org/). ### Changed +- Clés étrangères et conditions affichées comme du SQL (mots-clés en bleu gras, chaînes en vert), modifiables par un crayon. Badges colorés : présence des fichiers attendus (obligatoire en rouge, recommandé en orange, facultatif en vert), contraintes des colonnes (valeur obligatoire, colonne obligatoire, unique). « Monter » et « Descendre » retirés des fichiers attendus. Bouton « Équivalents » renommé « Appliquer aux colonnes / fichiers / listes semblables ». - Arborescence des fichiers attendus (arbre et vue du modèle) : à chaque niveau, les fichiers d'abord, puis les dossiers. Regex mises en valeur : encadrées en police à chasse fixe, variables de `variables.json` en bleu gras, variables facultatives en jaune. Accueil de l'éditeur en ligne : pleine largeur, sans les paragraphes de confidentialité et de commandes. - Vue d'un modèle en onglets « Modèle », « Fichiers », « Tables » (nouveau : modèles de table du modèle avec présence, nombre de colonnes et problèmes, tables non référencées) et « Listes de codes » ; l'onglet suit l'adresse (fichier de l'arbre, problème cliqué). Bandeau de synthèse en tuiles qui ouvrent l'onglet correspondant, types de fichiers au pluriel. Bouton « Listes de codes (N) » retiré. « Télécharger le JSON » (ou le CSV) à côté des onglets Vue / Source, et non plus dans le titre. - Vue d'un modèle (`files.json`) : fichiers attendus rangés selon leur arborescence, dossiers sur fond bleuté et contenu en retrait avec un filet bleu, icône par type de fichier. diff --git a/src/core/sql.ts b/src/core/sql.ts new file mode 100644 index 0000000..ef42366 --- /dev/null +++ b/src/core/sql.ts @@ -0,0 +1,25 @@ +// Découpage d'une clé étrangère ou d'une condition (syntaxe SQL du validator) pour l'affichage : +// mots-clés connus, chaînes, nombres, identifiants et le reste, dans l'ordre du texte. +export type SqlKind = 'keyword' | 'string' | 'number' | 'identifier' | 'other' +export interface SqlToken { + kind: SqlKind + text: string +} + +export const SQL_KEYWORDS = new Set([ + 'REFERENCES', 'AND', 'OR', 'NOT', 'IS', 'NULL', 'IN', 'LIKE', 'ILIKE', 'BETWEEN', 'TRUE', 'FALSE', + 'CASE', 'WHEN', 'THEN', 'ELSE', 'END', 'EXISTS', 'SELECT', 'FROM', 'WHERE', 'LENGTH', 'UPPER', 'LOWER', 'SUBSTRING', +]) + +const TOKEN = /('(?:[^']|'')*'?)|(\b\d+(?:\.\d+)?\b)|(\b[A-Za-z_][A-Za-z0-9_]*\b)|(\s+|[^\sA-Za-z0-9_']+)/g + +export function sqlTokens(text: string): SqlToken[] { + const out: SqlToken[] = [] + for (const [all, string, number, word] of text.matchAll(TOKEN)) { + const kind: SqlKind = string ? 'string' : number ? 'number' : word ? (SQL_KEYWORDS.has(word.toUpperCase()) ? 'keyword' : 'identifier') : 'other' + const last = out.at(-1) + if (kind === 'other' && last?.kind === 'other') last.text += all + else out.push({ kind, text: all }) + } + return out +} diff --git a/src/ui/components/EquivalentsDialog.vue b/src/ui/components/EquivalentsDialog.vue index 9a8dfbb..8b162d5 100644 --- a/src/ui/components/EquivalentsDialog.vue +++ b/src/ui/components/EquivalentsDialog.vue @@ -18,6 +18,9 @@ const all = ref(false) const property = ref() const unchecked = ref(new Set()) +// Libellé du bouton selon l'élément : colonnes, fichiers ou listes semblables des autres modèles. +const BUTTON: Record = { column: 'Appliquer aux colonnes semblables', file: 'Appliquer aux fichiers semblables', code: 'Appliquer aux listes semblables' } + const LABELS: Record = { '/type': 'Type', '/title': 'Titre', '/description': 'Description', '/constraints/required': 'Valeur obligatoire', '/constraints/presenceRequired': 'Colonne obligatoire', '/constraints/unique': 'Unique', '/constraints/minLength': 'Longueur minimale', @@ -93,7 +96,7 @@ function apply() {