From 126aebd7b1486170586c0a2248204165f781ed95 Mon Sep 17 00:00:00 2001 From: Emmanuel Raviart Date: Sat, 11 Feb 2023 15:15:23 +0100 Subject: [PATCH] Add validation of articles --- .../{dossiers_legislatifs.ts => dole.ts} | 3 +- src/lib/auditors/jorf/articles.ts | 773 +++++++++++++++ src/lib/auditors/jorf/index.ts | 1 + src/lib/auditors/legi/articles.ts | 912 ++++++++++++++++++ src/lib/auditors/legi/index.ts | 1 + src/lib/index.ts | 63 +- src/lib/legal/dole.ts | 82 ++ src/lib/{legal.ts => legal/index.ts} | 146 ++- src/lib/legal/jorf.ts | 190 ++++ src/lib/legal/legi.ts | 215 +++++ src/scripts/import_dole.ts | 2 +- src/scripts/import_jorf.ts | 24 +- src/scripts/import_kali.ts | 4 +- src/scripts/import_legi.ts | 30 +- 14 files changed, 2335 insertions(+), 111 deletions(-) rename src/lib/auditors/{dossiers_legislatifs.ts => dole.ts} (99%) create mode 100644 src/lib/auditors/jorf/articles.ts create mode 100644 src/lib/auditors/jorf/index.ts create mode 100644 src/lib/auditors/legi/articles.ts create mode 100644 src/lib/auditors/legi/index.ts create mode 100644 src/lib/legal/dole.ts rename src/lib/{legal.ts => legal/index.ts} (88%) create mode 100644 src/lib/legal/jorf.ts create mode 100644 src/lib/legal/legi.ts diff --git a/src/lib/auditors/dossiers_legislatifs.ts b/src/lib/auditors/dole.ts similarity index 99% rename from src/lib/auditors/dossiers_legislatifs.ts rename to src/lib/auditors/dole.ts index 473a14a..57014af 100644 --- a/src/lib/auditors/dossiers_legislatifs.ts +++ b/src/lib/auditors/dole.ts @@ -473,9 +473,8 @@ function auditLigne(audit: Audit, dataUnknown: unknown): [unknown, unknown] { remainingKeys, auditSwitch( [auditNumber, auditInteger, auditFunction((numero) => numero.toString())], - auditTrimString, + [auditTrimString, auditEmptyToNull], ), - auditEmptyToNull, ) return audit.reduceRemaining(data, errors, remainingKeys) diff --git a/src/lib/auditors/jorf/articles.ts b/src/lib/auditors/jorf/articles.ts new file mode 100644 index 0000000..3d6db26 --- /dev/null +++ b/src/lib/auditors/jorf/articles.ts @@ -0,0 +1,773 @@ +import { + type Audit, + auditRequire, + auditDateIso8601String, + auditTrimString, + auditInteger, + auditFunction, + auditEmptyToNull, + auditNullish, + auditSwitch, + auditNumber, + auditCleanArray, + auditOptions, + auditHttpUrl, +} from "@auditors/core" + +import { + allJorfArticleEtatsMutable, + allJorfArticleLienArticleOriginesMutable, + allJorfArticleNaturesMutable, + allJorfArticleOriginesMutable, + allJorfArticleTexteNaturesMutable, + allJorfArticleTypesMutable, +} from "$lib/legal" + +function auditBlocTextuel( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "CONTENU", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditContexte(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "TEXTE", + true, + errors, + remainingKeys, + auditTexte, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditEliAlias(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "ID_ELI_ALIAS", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditHttpUrl, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +export function auditJorfArticle( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "BLOC_TEXTUEL", + true, + errors, + remainingKeys, + auditBlocTextuel, + auditEmptyToNull, + ) + audit.attribute( + data, + "CONTEXTE", + true, + errors, + remainingKeys, + auditContexte, + auditRequire, + ) + audit.attribute( + data, + "LIENS", + true, + errors, + remainingKeys, + auditSwitch(auditTrimString, auditLiens), + auditEmptyToNull, + auditNullish, + ) + audit.attribute( + data, + "META", + true, + errors, + remainingKeys, + auditMeta, + auditRequire, + ) + audit.attribute( + data, + "SM", + true, + errors, + remainingKeys, + auditSm, + auditEmptyToNull, + auditNullish, + ) + audit.attribute( + data, + "VERSIONS", + true, + errors, + remainingKeys, + auditVersions, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditLienArt(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + for (const key of ["@debut", "@fin"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "@etat", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allJorfArticleEtatsMutable), + ) + audit.attribute( + data, + "@id", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + audit.attribute( + data, + "@num", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + audit.attribute( + data, + "@origine", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allJorfArticleLienArticleOriginesMutable), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditLiens(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +/// Mots-clés articles +function auditMcsArt(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "MC", + true, + errors, + remainingKeys, + auditFunction((lien) => (Array.isArray(lien) ? lien : [lien])), + auditCleanArray( + auditSwitch( + [auditNumber, auditInteger, auditFunction((num) => num.toString())], + [auditTrimString, auditEmptyToNull], + ), + ), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditMeta(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "META_COMMUN", + true, + errors, + remainingKeys, + auditMetaCommun, + auditRequire, + ) + audit.attribute( + data, + "META_SPEC", + true, + errors, + remainingKeys, + auditMetaSpec, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditMetaArticle( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + for (const key of ["DATE_DEBUT", "DATE_FIN"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "MCS_ART", + true, + errors, + remainingKeys, + auditSwitch([auditTrimString, auditEmptyToNull, auditNullish], auditMcsArt), + ) + audit.attribute( + data, + "NUM", + true, + errors, + remainingKeys, + auditSwitch( + [auditNumber, auditFunction((num) => num.toString())], + [auditTrimString, auditEmptyToNull], + ), + ) + audit.attribute( + data, + "TYPE", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allJorfArticleTypesMutable), + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditMetaCommun( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "ANCIEN_ID", + true, + errors, + remainingKeys, + auditSwitch( + [auditNumber, auditInteger, auditFunction((id) => id.toString())], + [auditTrimString, auditEmptyToNull], + ), + ) + audit.attribute(data, "ELI_ALIAS", true, errors, remainingKeys, auditEliAlias) + for (const key of ["ID", "URL"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + } + audit.attribute( + data, + "ID_ELI", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditHttpUrl, + ) + audit.attribute( + data, + "NATURE", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allJorfArticleNaturesMutable), + ) + audit.attribute( + data, + "ORIGINE", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allJorfArticleOriginesMutable), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditMetaSpec(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "META_ARTICLE", + true, + errors, + remainingKeys, + auditMetaArticle, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditSm(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "CONTENU", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditNullish, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditTexte(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "@cid", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + for (const key of ["@date_publi", "@date_signature"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditFunction((date) => date.replace(/^11992-12-27$/, "1992-12-27")), + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "@nature", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allJorfArticleTexteNaturesMutable), + ) + for (const key of ["@nor", "@num", "@num_parution_jo"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + } + audit.attribute( + data, + "TITRE_TXT", + true, + errors, + remainingKeys, + auditFunction((titreTxt) => + Array.isArray(titreTxt) ? titreTxt : [titreTxt], + ), + auditCleanArray(auditTitreTxt), + auditRequire, + ) + audit.attribute(data, "TM", true, errors, remainingKeys, auditTm) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditTitreTm(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "#text", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + for (const key of ["@debut", "@fin"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "@id", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditTitreTxt(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "#text", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + audit.attribute( + data, + "@c_titre_court", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + for (const key of ["@debut", "@fin"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "@id_txt", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +/// Table des matières +function auditTm(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "TITRE_TM", + true, + errors, + remainingKeys, + auditTitreTm, + auditRequire, + ) + audit.attribute(data, "TM", true, errors, remainingKeys, auditTm) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditVersion(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "@etat", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allJorfArticleEtatsMutable), + ) + audit.attribute( + data, + "LIEN_ART", + true, + errors, + remainingKeys, + auditLienArt, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditVersions(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "VERSION", + true, + errors, + remainingKeys, + auditFunction((version) => (Array.isArray(version) ? version : [version])), + auditCleanArray(auditVersion), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} diff --git a/src/lib/auditors/jorf/index.ts b/src/lib/auditors/jorf/index.ts new file mode 100644 index 0000000..b35bcbb --- /dev/null +++ b/src/lib/auditors/jorf/index.ts @@ -0,0 +1 @@ +export { auditJorfArticle } from "./articles" diff --git a/src/lib/auditors/legi/articles.ts b/src/lib/auditors/legi/articles.ts new file mode 100644 index 0000000..6c556d1 --- /dev/null +++ b/src/lib/auditors/legi/articles.ts @@ -0,0 +1,912 @@ +import { + type Audit, + auditRequire, + auditDateIso8601String, + auditTrimString, + auditInteger, + auditFunction, + auditEmptyToNull, + auditSwitch, + auditNumber, + auditCleanArray, + auditOptions, + auditHttpUrl, +} from "@auditors/core" + +import { + allLegiArticleEtatsMutable, + allLegiArticleLienArticleOriginesMutable, + allLegiArticleLienNaturesMutable, + allLegiArticleLienSensMutable, + allLegiArticleLienTypesMutable, + allLegiArticleNaturesMutable, + allLegiArticleOriginesMutable, + allLegiArticleTexteNaturesMutable, + allLegiArticleTypesMutable, +} from "$lib/legal" + +export const legiArticleStats: { + countByEtat: { [etat: string]: number } + countByLienArtEtat: { [etat: string]: number } + countByLienNature: { [nature: string]: number } + countByLienType: { [type: string]: number } + countByTexteNature: { [nature: string]: number } + countByVersionEtat: { [etat: string]: number } +} = { + countByEtat: {}, + countByLienArtEtat: {}, + countByLienNature: {}, + countByLienType: {}, + countByTexteNature: {}, + countByVersionEtat: {}, +} + +function auditBlocTextuel( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "CONTENU", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditContexte(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "TEXTE", + true, + errors, + remainingKeys, + auditTexte, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditEliAlias(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "ID_ELI_ALIAS", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditHttpUrl, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +export function auditLegiArticle( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "BLOC_TEXTUEL", + true, + errors, + remainingKeys, + auditBlocTextuel, + auditEmptyToNull, + ) + audit.attribute( + data, + "CONTEXTE", + true, + errors, + remainingKeys, + auditContexte, + auditRequire, + ) + audit.attribute( + data, + "LIENS", + true, + errors, + remainingKeys, + auditSwitch(auditTrimString, auditLiens), + auditEmptyToNull, + ) + audit.attribute( + data, + "META", + true, + errors, + remainingKeys, + auditMeta, + auditRequire, + ) + audit.attribute( + data, + "NOTA", + true, + errors, + remainingKeys, + auditNota, + auditEmptyToNull, + ) + audit.attribute( + data, + "VERSIONS", + true, + errors, + remainingKeys, + auditVersions, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditLien(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "#text", + true, + errors, + remainingKeys, + auditSwitch( + [auditNumber, auditInteger, auditFunction((num) => num.toString())], + [auditTrimString, auditEmptyToNull], + ), + ) + for (const key of ["@cidtexte", "@id", "@nortexte"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + } + for (const key of ["@datesignatexte"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditDateIso8601String, + ) + } + audit.attribute( + data, + "@naturetexte", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + // auditFunction((nature) => { + // legiArticleStats.countByLienNature[nature] = + // (legiArticleStats.countByLienNature[nature] ?? 0) + 1 + // return nature + // }), + auditOptions(allLegiArticleLienNaturesMutable), + ) + audit.attribute( + data, + "@num", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + audit.attribute( + data, + "@numtexte", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + audit.attribute( + data, + "@sens", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allLegiArticleLienSensMutable), + auditRequire, + ) + audit.attribute( + data, + "@typelien", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + // auditFunction((type) => { + // legiArticleStats.countByLienType[type] = + // (legiArticleStats.countByLienType[type] ?? 0) + 1 + // return type + // }), + auditOptions(allLegiArticleLienTypesMutable), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditLienArt(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + for (const key of ["@debut", "@fin"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "@etat", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + // auditFunction((etat) => { + // legiArticleStats.countByLienArtEtat[etat] = + // (legiArticleStats.countByLienArtEtat[etat] ?? 0) + 1 + // return etat + // }), + auditOptions(allLegiArticleEtatsMutable), + ) + audit.attribute( + data, + "@id", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + audit.attribute( + data, + "@num", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + audit.attribute( + data, + "@origine", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allLegiArticleLienArticleOriginesMutable), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditLiens(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "LIEN", + true, + errors, + remainingKeys, + auditFunction((lien) => (Array.isArray(lien) ? lien : [lien])), + auditCleanArray(auditLien), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditMeta(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "META_COMMUN", + true, + errors, + remainingKeys, + auditMetaCommun, + auditRequire, + ) + audit.attribute( + data, + "META_SPEC", + true, + errors, + remainingKeys, + auditMetaSpec, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditMetaArticle( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + for (const key of ["DATE_DEBUT", "DATE_FIN"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "ETAT", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + // auditFunction((etat) => { + // legiArticleStats.countByEtat[etat] = + // (legiArticleStats.countByEtat[etat] ?? 0) + 1 + // return etat + // }), + auditOptions(allLegiArticleEtatsMutable), + ) + audit.attribute( + data, + "NUM", + true, + errors, + remainingKeys, + auditSwitch( + [auditNumber, auditFunction((num) => num.toString())], + [auditTrimString, auditEmptyToNull], + ), + ) + audit.attribute( + data, + "TYPE", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allLegiArticleTypesMutable), + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditMetaCommun( + audit: Audit, + dataUnknown: unknown, +): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "ANCIEN_ID", + true, + errors, + remainingKeys, + auditSwitch( + [auditNumber, auditInteger, auditFunction((id) => id.toString())], + [auditTrimString, auditEmptyToNull], + ), + ) + for (const key of ["ID", "URL"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + } + audit.attribute( + data, + "NATURE", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allLegiArticleNaturesMutable), + auditRequire, + ) + audit.attribute( + data, + "ORIGINE", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditOptions(allLegiArticleOriginesMutable), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditMetaSpec(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "META_ARTICLE", + true, + errors, + remainingKeys, + auditMetaArticle, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditNota(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "CONTENU", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditTexte(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "@autorite", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + audit.attribute( + data, + "@cid", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + for (const key of ["@date_publi", "@date_signature"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditFunction((date) => date.replace(/^11992-12-27$/, "1992-12-27")), + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "@ministere", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + audit.attribute( + data, + "@nature", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + // auditFunction((nature) => { + // legiArticleStats.countByTexteNature[nature] = + // (legiArticleStats.countByTexteNature[nature] ?? 0) + 1 + // return nature + // }), + auditOptions(allLegiArticleTexteNaturesMutable), + ) + for (const key of ["@nor", "@num", "@num_parution_jo"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + ) + } + audit.attribute( + data, + "TITRE_TXT", + true, + errors, + remainingKeys, + auditFunction((titreTxt) => + Array.isArray(titreTxt) ? titreTxt : [titreTxt], + ), + auditCleanArray(auditTitreTxt), + auditRequire, + ) + audit.attribute(data, "TM", true, errors, remainingKeys, auditTm) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditTitreTm(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "#text", + true, + errors, + remainingKeys, + auditSwitch( + [auditNumber, auditInteger, auditFunction((num) => num.toString())], + [auditTrimString, auditEmptyToNull], + ), + auditRequire, + ) + for (const key of ["@debut", "@fin"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "@id", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditTitreTxt(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "#text", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + audit.attribute( + data, + "@c_titre_court", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + for (const key of ["@debut", "@fin"]) { + audit.attribute( + data, + key, + true, + errors, + remainingKeys, + auditDateIso8601String, + auditRequire, + ) + } + audit.attribute( + data, + "@id_txt", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +/// Table des matières +function auditTm(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "TITRE_TM", + true, + errors, + remainingKeys, + auditFunction((titreTm) => (Array.isArray(titreTm) ? titreTm : [titreTm])), + auditCleanArray(auditTitreTm), + auditRequire, + ) + audit.attribute(data, "TM", true, errors, remainingKeys, auditTm) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditVersion(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "@etat", + true, + errors, + remainingKeys, + auditTrimString, + auditEmptyToNull, + // auditFunction((etat) => { + // legiArticleStats.countByVersionEtat[etat] = + // (legiArticleStats.countByVersionEtat[etat] ?? 0) + 1 + // return etat + // }), + auditOptions(allLegiArticleEtatsMutable), + ) + audit.attribute( + data, + "LIEN_ART", + true, + errors, + remainingKeys, + auditLienArt, + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} + +function auditVersions(audit: Audit, dataUnknown: unknown): [unknown, unknown] { + if (dataUnknown == null) { + return [dataUnknown, null] + } + if (typeof dataUnknown !== "object") { + return audit.unexpectedType(dataUnknown, "object") + } + + const data = { ...dataUnknown } + const errors: { [key: string]: unknown } = {} + const remainingKeys = new Set(Object.keys(data)) + + audit.attribute( + data, + "VERSION", + true, + errors, + remainingKeys, + auditFunction((version) => (Array.isArray(version) ? version : [version])), + auditCleanArray(auditVersion), + auditRequire, + ) + + return audit.reduceRemaining(data, errors, remainingKeys) +} diff --git a/src/lib/auditors/legi/index.ts b/src/lib/auditors/legi/index.ts new file mode 100644 index 0000000..7fd3907 --- /dev/null +++ b/src/lib/auditors/legi/index.ts @@ -0,0 +1 @@ +export { auditLegiArticle, legiArticleStats } from "./articles" diff --git a/src/lib/index.ts b/src/lib/index.ts index ea9b235..1a19f2f 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -7,24 +7,71 @@ export { type GetRechercheResult, type GetTexteResult, type ListTextesResult, -} from "$lib/aggregates" +} from "./aggregates" -export { default as ArticleView } from "$lib/components/ArticleView.svelte" +export { default as ArticleView } from "./components/ArticleView.svelte" -export { default as LienView } from "$lib/components/LienView.svelte" +export { default as LienView } from "./components/LienView.svelte" -export { default as SectionTaView } from "$lib/components/SectionTaView.svelte" +export { default as SectionTaView } from "./components/SectionTaView.svelte" -export { default as TextelrView } from "$lib/components/TextelrView.svelte" +export { default as TextelrView } from "./components/TextelrView.svelte" -export { default as TexteVersionView } from "$lib/components/TexteVersionView.svelte" +export { default as TexteVersionView } from "./components/TexteVersionView.svelte" + +export { + allJorfArticleEtats, + allJorfArticleEtatsMutable, + allJorfArticleLienArticleOrigines, + allJorfArticleLienArticleOriginesMutable, + allJorfArticleNatures, + allJorfArticleNaturesMutable, + allJorfArticleOrigines, + allJorfArticleOriginesMutable, + allJorfArticleTexteNatures, + allJorfArticleTexteNaturesMutable, + allJorfArticleTypes, + allJorfArticleTypesMutable, + allLegiArticleEtats, + allLegiArticleEtatsMutable, + allLegiArticleLienArticleOrigines, + allLegiArticleLienArticleOriginesMutable, + allLegiArticleLienNatures, + allLegiArticleLienNaturesMutable, + allLegiArticleLienSens, + allLegiArticleLienSensMutable, + allLegiArticleNatures, + allLegiArticleNaturesMutable, + allLegiArticleOrigines, + allLegiArticleOriginesMutable, + allLegiArticleTexteNatures, + allLegiArticleTexteNaturesMutable, + allLegiArticleTypes, + allLegiArticleTypesMutable, + type DossierLegislatif, + type JorfArticle, + type JorfArticleEtat, + type JorfArticleLienArticleOrigine, + type JorfArticleNature, + type JorfArticleOrigine, + type JorfArticleTexteNature, + type JorfArticleType, + type LegiArticle, + type LegiArticleEtat, + type LegiArticleLienArticleOrigine, + type LegiArticleLienNature, + type LegiArticleLienSens, + type LegiArticleNature, + type LegiArticleOrigine, + type LegiArticleTexteNature, + type LegiArticleType, +} from "./legal" export { type Article, type ArticleVersion, bestItemForDate, type Contexte, - type DossierLegislatif, type Etat, type Idcc, type Jo, @@ -50,4 +97,4 @@ export { type Tm, type TmLienTxt, type Versions, -} from "$lib/legal" +} from "./legal" diff --git a/src/lib/legal/dole.ts b/src/lib/legal/dole.ts new file mode 100644 index 0000000..afff939 --- /dev/null +++ b/src/lib/legal/dole.ts @@ -0,0 +1,82 @@ +export interface ArborescenceLien { + "#text"?: string + "@id": string + "@libelle"?: string + "@lien"?: string +} + +export interface ArborescenceNiveau { + "@id": string + "@libelle": string + LIEN?: ArborescenceLien[] + NIVEAU?: ArborescenceNiveau +} + +export interface DossierLegislatif { + CONTENU: { + ARBORESCENCE: { + LIEN?: ArborescenceLien[] + NIVEAU?: ArborescenceNiveau + } + CONTENU_DOSSIER_1?: string + CONTENU_DOSSIER_2?: string + CONTENU_DOSSIER_3?: string + CONTENU_DOSSIER_4?: string + CONTENU_DOSSIER_5?: string + ECHEANCIER?: { + "@derniere_maj"?: string + LIGNE: Ligne[] + } + EXPOSE_MOTIF?: string + LIBELLE_TEXTE_1?: string + LIBELLE_TEXTE_2?: string + LIBELLE_TEXTE_3?: string + LIBELLE_TEXTE_4?: string + LIBELLE_TEXTE_5?: string + } + META: { + META_COMMUN: { + // MetaCommun + ANCIEN_ID?: string + ID: string + URL: string + // NATURE?: Nature // Never used + ORIGINE: "JORF" // Origine + } + META_DOSSIER_LEGISLATIF: { + DATE_CREATION: string + DATE_DERNIERE_MODIFICATION: string + ID_TEXTE_1?: string + ID_TEXTE_2?: string + ID_TEXTE_3?: string + ID_TEXTE_4?: string + ID_TEXTE_5?: string + LEGISLATURE: { + DATE_DEBUT: string + DATE_FIN: string + LIBELLE: string + NUMERO: number + } + TITRE: string + TYPE?: + | "LOI_PUBLIEE" + | "PROJET_LOI" + | "PROPOSITION_LOI" + | "ORDONNANCE_PUBLIEE" + } + } +} + +export interface Ligne { + ARTICLE?: string + BASE_LEGALE?: string + CID_LOI_CIBLE?: string // Always a JORFTEXT ID + DATE_PREVUE?: string + DECRET?: string + LIEN_ARTICLE?: Array<{ + "@id": string // Always a JORFARTI ID + "#text": string + }> + NUMERO_ORDRE?: string + OBJET?: string +} diff --git a/src/lib/legal.ts b/src/lib/legal/index.ts similarity index 88% rename from src/lib/legal.ts rename to src/lib/legal/index.ts index c67c834..ead56ad 100644 --- a/src/lib/legal.ts +++ b/src/lib/legal/index.ts @@ -1,18 +1,59 @@ import type { MenuItem } from "@tricoteuses/explorer-tools" -export interface ArborescenceLien { - "#text"?: string - "@id": string - "@libelle"?: string - "@lien"?: string -} +import type { DossierLegislatif } from "./dole" -export interface ArborescenceNiveau { - "@id": string - "@libelle": string - LIEN?: ArborescenceLien[] - NIVEAU?: ArborescenceNiveau -} +export type { DossierLegislatif } from "./dole" +export { + allJorfArticleEtats, + allJorfArticleEtatsMutable, + allJorfArticleLienArticleOrigines, + allJorfArticleLienArticleOriginesMutable, + allJorfArticleNatures, + allJorfArticleNaturesMutable, + allJorfArticleOrigines, + allJorfArticleOriginesMutable, + allJorfArticleTexteNatures, + allJorfArticleTexteNaturesMutable, + allJorfArticleTypes, + allJorfArticleTypesMutable, + type JorfArticle, + type JorfArticleEtat, + type JorfArticleLienArticleOrigine, + type JorfArticleNature, + type JorfArticleOrigine, + type JorfArticleTexteNature, + type JorfArticleType, +} from "./jorf" +export { + allLegiArticleEtats, + allLegiArticleEtatsMutable, + allLegiArticleLienArticleOrigines, + allLegiArticleLienArticleOriginesMutable, + allLegiArticleLienNatures, + allLegiArticleLienNaturesMutable, + allLegiArticleLienSens, + allLegiArticleLienSensMutable, + allLegiArticleLienTypes, + allLegiArticleLienTypesMutable, + allLegiArticleNatures, + allLegiArticleNaturesMutable, + allLegiArticleOrigines, + allLegiArticleOriginesMutable, + allLegiArticleTexteNatures, + allLegiArticleTexteNaturesMutable, + allLegiArticleTypes, + allLegiArticleTypesMutable, + type LegiArticle, + type LegiArticleEtat, + type LegiArticleLienArticleOrigine, + type LegiArticleLienNature, + type LegiArticleLienSens, + type LegiArticleLienType, + type LegiArticleNature, + type LegiArticleOrigine, + type LegiArticleTexteNature, + type LegiArticleType, +} from "./legi" export interface Article { META: { @@ -62,61 +103,6 @@ export interface Contexte { } } -export interface DossierLegislatif { - META: { - META_COMMUN: { - // MetaCommun - ANCIEN_ID?: string - ID: string - URL: string - // NATURE?: Nature // Never used - ORIGINE: "JORF" // Origine - } - META_DOSSIER_LEGISLATIF: { - DATE_CREATION: string - DATE_DERNIERE_MODIFICATION: string - ID_TEXTE_1?: string - ID_TEXTE_2?: string - ID_TEXTE_3?: string - ID_TEXTE_4?: string - ID_TEXTE_5?: string - LEGISLATURE: { - DATE_DEBUT: string - DATE_FIN: string - LIBELLE: string - NUMERO: number - } - TITRE: string - TYPE?: - | "LOI_PUBLIEE" - | "PROJET_LOI" - | "PROPOSITION_LOI" - | "ORDONNANCE_PUBLIEE" - } - } - CONTENU: { - ARBORESCENCE: { - LIEN?: ArborescenceLien[] - NIVEAU?: ArborescenceNiveau - } - CONTENU_DOSSIER_1?: string - CONTENU_DOSSIER_2?: string - CONTENU_DOSSIER_3?: string - CONTENU_DOSSIER_4?: string - CONTENU_DOSSIER_5?: string - ECHEANCIER?: { - "@derniere_maj"?: string - LIGNE: Ligne[] - } - EXPOSE_MOTIF?: string - LIBELLE_TEXTE_1?: string - LIBELLE_TEXTE_2?: string - LIBELLE_TEXTE_3?: string - LIBELLE_TEXTE_4?: string - LIBELLE_TEXTE_5?: string - } -} - export type Etat = | "" | "ABROGE_DIFF" @@ -260,20 +246,6 @@ export interface LienSectionTa { "#text": string } -export interface Ligne { - ARTICLE?: string - BASE_LEGALE?: string - CID_LOI_CIBLE?: string // Always a JORFTEXT ID - DATE_PREVUE?: string - DECRET?: string - LIEN_ARTICLE?: Array<{ - "@id": string // Always a JORFARTI ID - "#text": string - }> - NUMERO_ORDRE?: string - OBJET?: string -} - export interface MetaCommun { ID: string URL: string @@ -463,18 +435,18 @@ export interface TexteVersion { } export interface TitreTm { - "@id": string - "@fin": string "#text": string "@debut": string + "@fin": string + "@id": string } export interface TitreTxt { - "@fin": string - "@debut": string - "@id_txt": string - "@c_titre_court": string "#text": string + "@c_titre_court": string + "@debut": string + "@fin": string + "@id_txt": string } /// Table des matières (TM) diff --git a/src/lib/legal/jorf.ts b/src/lib/legal/jorf.ts new file mode 100644 index 0000000..494b3a8 --- /dev/null +++ b/src/lib/legal/jorf.ts @@ -0,0 +1,190 @@ +export interface JorfArticle { + BLOC_TEXTUEL?: { + CONTENU: string // HTML + } + CONTEXTE: { + TEXTE: { + "@cid": string + "@date_publi": string + "@date_signature": string + "@nature"?: JorfArticleTexteNature + "@nor"?: string + "@num"?: string + "@num_parution_jo"?: string + TITRE_TXT: Array<{ + "#text": string + "@c_titre_court"?: string + "@debut": string + "@fin": string + "@id_txt": string + }> + TM?: JorfArticleTm + } + } + META: { + META_COMMUN: { + ANCIEN_ID?: string + ELI_ALIAS?: { + ID_ELI_ALIAS: string + } + ID: string + ID_ELI?: string + NATURE?: JorfArticleNature + URL: string + ORIGINE: JorfArticleOrigine + } + META_SPEC: { + META_ARTICLE: { + DATE_FIN: string + DATE_DEBUT: string + /// Mots-clés + MCS_ART?: { MC: string[] } + NUM?: string + TYPE?: JorfArticleType + } + } + } + VERSIONS: { + VERSION: Array<{ + "@etat"?: JorfArticleEtat + LIEN_ART: { + "@debut": string + "@etat"?: JorfArticleEtat + "@fin": string + "@id": string + "@num"?: string + "@origine": JorfArticleLienArticleOrigine + } + }> + } +} + +export type JorfArticleEtat = (typeof allJorfArticleEtats)[number] + +export type JorfArticleLienArticleOrigine = + (typeof allJorfArticleLienArticleOrigines)[number] + +export type JorfArticleNature = (typeof allJorfArticleNatures)[number] + +export type JorfArticleOrigine = (typeof allJorfArticleOrigines)[number] + +export type JorfArticleTexteNature = (typeof allJorfArticleTexteNatures)[number] + +export type JorfArticleType = (typeof allJorfArticleTypes)[number] + +/// Table des matières (TM) +export interface JorfArticleTm { + TITRE_TM: { + "#text"?: string + "@debut": string + "@fin": string + "@id": string + } + TM?: JorfArticleTm +} + +export const allJorfArticleEtats = [ + "ABROGE", + "ABROGE_DIFF", + "ANNULE", + "MODIFIE", + "MODIFIE_MORT_NE", + "PERIME", + "TRANSFERE", + "VIGUEUR", + "VIGUEUR_DIFF", +] as const +export const allJorfArticleEtatsMutable = [...allJorfArticleEtats] + +export const allJorfArticleLienArticleOrigines = ["JORF", "LEGI"] as const +export const allJorfArticleLienArticleOriginesMutable = [ + ...allJorfArticleLienArticleOrigines, +] + +export const allJorfArticleNatures = ["Article"] as const +export const allJorfArticleNaturesMutable = [...allJorfArticleNatures] + +export const allJorfArticleOrigines = ["JORF"] as const +export const allJorfArticleOriginesMutable = [...allJorfArticleOrigines] + +export const allJorfArticleTexteNatures = [ + "DECRET", // 555543 + "LOI", // 64957 + "ARRETE", // 1228598 + "DECISION", // 244100 + "LISTE", // 24279 + "AVIS", // 101688 + "CODE", // 14737 + "RESULTATS", // 14954 + "MODIFICATION", // 724 + "RAPPORT", // 2491 + "REGLEMENT", // 1930 + "LOI_ORGANIQUE", // 1144 + "CIRCULAIRE", // 3933 + "LOI_PROGRAMME", // 10 + "CITATION", // 423 + "ORDONNANCE", // 33582 + "DELIBERATION", // 11012 + "INSTRUCTION", // 1207 + "AVENANT", // 533 + "DECLARATION", // 77 + "OBSERVATION", // 623 + "INFORMATION", // 143 + "RECOMMANDATION", // 204 + "SAISINE", // 1075 + "EXEQUATUR", // 173 + "TABLEAU", // 1063 + "REMISE", // 119 + "ACCORD", // 153 + "MEMOIRE", // 72 + "DECISION_CC", // 51 + "LOI_CONSTIT", // 76 + "LETTRE", // 10 + "ELECTIONDUPRESIDENTDELAREPUBLIQU", // 16 + "CONVENTION", // 972 + "ARRET", // 23 + "CONTRAT", // 32 + "COMPOSITION", // 19 + "ADDITIF", // 139 + "VOCABULAIRE", // 170 + "DATE", // 1 + "PROTOCOLE", // 25 + "PROPOSITION", // 11 + "DECRET_LOI", // 85 + "COMMUNIQUE", // 3 + "PROCLAMATION", // 17 + "CONSTITUTION", // 41 + "DIRECTIVE", // 11 + "DECISION_EURO", // 15 + "ABROGATION", // 10 + "PREMIER", // 1 + "PUBLICATION", // 2 + "RECTIFICATIF", // 3 + "DEUXIEME", // 5 + "DELEGATION", // 1 + "ANNEXE", // 2 + "RELEVE", // 2 + "COMPLEMENT", // 2 + "ARRANGEMENT", // 1 + "TROISIEME", // 2 + "ELECTION", // 1 + "SUSPENSION", // 2 + "ATTESTATION", // 1 + "CANDIDAT", // 2 + "CHARTE", // 1 + "PROJET", // 6 + "INFORMATIONS_DIVERSES", // 524 + "INFORMATIONS_PARLEMENTAIRES", // 6335 + "INFORMATIONS_CESE", // 285 + "ANNONCES", // 755 + "Accord multilatéral", // 3 + "ACCORD_FONCTION_PUBLIQUE", // +] as const +export const allJorfArticleTexteNaturesMutable = [...allJorfArticleTexteNatures] + +export const allJorfArticleTypes = [ + "AUTONOME", + "ENTIEREMENT_MODIF", + "PARTIELLEMENT_MODIF", +] as const +export const allJorfArticleTypesMutable = [...allJorfArticleTypes] diff --git a/src/lib/legal/legi.ts b/src/lib/legal/legi.ts new file mode 100644 index 0000000..08cdca6 --- /dev/null +++ b/src/lib/legal/legi.ts @@ -0,0 +1,215 @@ +export interface LegiArticle { + BLOC_TEXTUEL?: { + CONTENU: string // HTML + } + CONTEXTE: { + TEXTE: { + "@cid": string + "@date_publi": string + "@date_signature": string + "@nature"?: LegiArticleTexteNature + "@nor"?: string + "@num"?: string + "@num_parution_jo"?: string + TITRE_TXT: Array<{ + "#text": string + "@c_titre_court"?: string + "@debut": string + "@fin": string + "@id_txt": string + }> + TM?: LegiArticleTm + } + } + META: { + META_COMMUN: { + ANCIEN_ID?: string + ELI_ALIAS?: { + ID_ELI_ALIAS: string + } + ID: string + ID_ELI?: string + NATURE?: LegiArticleNature + URL: string + ORIGINE: LegiArticleOrigine + } + META_SPEC: { + META_ARTICLE: { + DATE_FIN: string + DATE_DEBUT: string + /// Mots-clés + MCS_ART?: { MC: string[] } + NUM?: string + TYPE?: LegiArticleType + } + } + } + VERSIONS: { + VERSION: Array<{ + "@etat"?: LegiArticleEtat + LIEN_ART: { + "@debut": string + "@etat"?: LegiArticleEtat + "@fin": string + "@id": string + "@num"?: string + "@origine": LegiArticleLienArticleOrigine + } + }> + } +} + +export type LegiArticleEtat = (typeof allLegiArticleEtats)[number] + +export type LegiArticleLienArticleOrigine = + (typeof allLegiArticleLienArticleOrigines)[number] + +export type LegiArticleLienNature = (typeof allLegiArticleLienNatures)[number] + +export type LegiArticleLienSens = (typeof allLegiArticleLienSens)[number] + +export type LegiArticleLienType = (typeof allLegiArticleLienTypes)[number] + +export type LegiArticleNature = (typeof allLegiArticleNatures)[number] + +export type LegiArticleOrigine = (typeof allLegiArticleOrigines)[number] + +export type LegiArticleTexteNature = (typeof allLegiArticleTexteNatures)[number] + +export type LegiArticleType = (typeof allLegiArticleTypes)[number] + +/// Table des matières (TM) +export interface LegiArticleTm { + TITRE_TM: { + "#text"?: string + "@debut": string + "@fin": string + "@id": string + } + TM?: LegiArticleTm +} + +export const allLegiArticleEtats = [ + "ABROGE_DIFF", // 16233 + "ABROGE", // 341353 + "ANNULE", // 1955 + "DISJOINT", // 87 + "MODIFIE_MORT_NE", // 6929 + "MODIFIE", // 429664 + "PERIME", // 19628 + "TRANSFERE", // 14757 + "VIGUEUR_DIFF", // 14629 + "VIGUEUR", // 619477 +] as const +export const allLegiArticleEtatsMutable = [...allLegiArticleEtats] + +export const allLegiArticleLienArticleOrigines = ["JORF", "LEGI"] as const +export const allLegiArticleLienArticleOriginesMutable = [ + ...allLegiArticleLienArticleOrigines, +] + +export const allLegiArticleLienNatures = [ + "Accord de branche", // 10 + "ACCORD_FONCTION_PUBLIQUE", // 68 + "Accord", // 9 + "ARRETE", // 878512 + "Avenant", // 24 + "AVENANT", // 7 + "AVIS", // 139 + "CIRCULAIRE", // 73 + "CODE", // 3276729 + "CONSTITUTION", // 1086 + "Convention collective nationale", // 7 + "Convention collective", // 1 + "CONVENTION", // 3 + "DECISION_EURO", // 1 + "DECISION", // 1735 + "DECRET_LOI", // 1184 + "DECRET", // 2037090 + "DELIBERATION", // 4172 + "DIRECTIVE_EURO", // 180 + "DIRECTIVE", // 64 + "INSTRUCTION", // 4 + "LOI_CONSTIT", // 111 + "LOI_ORGANIQUE", // 5681 + "LOI_PROGRAMME", // 335 + "LOI", // 645965 + "ORDONNANCE", // 225464 + "RAPPORT", // 15802 + "RECOMMANDATION", // 6 + "REGLEMENTEUROPEEN", // 3 +] as const +export const allLegiArticleLienNaturesMutable = [...allLegiArticleLienNatures] + +export const allLegiArticleLienSens = ["cible", "source"] as const +export const allLegiArticleLienSensMutable = [...allLegiArticleLienSens] + +export const allLegiArticleLienTypes = [ + "ABROGATION", // 237556 + "ABROGE", // 480524 + "ANNULATION", // 1801 + "ANNULE", // 13 + "APPLICATION", // 398 + "CITATION", // 4028139 + "CODIFICATION", // 380434 + "CODIFIE", // 29 + "CONCORDANCE", // 315976 + "CONCORDE", // 192980 + "CREATION", // 174907 + "CREE", // 265183 + "DEPLACE", // 12605 + "DEPLACEMENT", // 307 + "DISJOINT", // 46 + "DISJONCTION", // 77 + "ETEND", // 43 + "HISTO", // 14499 + "MODIFICATION", // 390927 + "MODIFIE", // 570147 + "PEREMPTION", // 7001 + "PERIME", // 1024 + "PILOTE_SUIVEUR", // 4734 + "RATIFICATION", // 259 + "RATIFIE", // 56 + "RECTIFICATION", // 1439 + "SPEC_APPLI", // 87345 + "TRANSFERE", // 16828 + "TRANSFERT", // 10641 + "TXT_ASSOCIE", // 47348 + "TXT_SOURCE", // 263557 +] as const +export const allLegiArticleLienTypesMutable = [...allLegiArticleLienTypes] + +export const allLegiArticleNatures = ["Article"] as const +export const allLegiArticleNaturesMutable = [...allLegiArticleNatures] + +export const allLegiArticleOrigines = ["LEGI"] as const +export const allLegiArticleOriginesMutable = [...allLegiArticleOrigines] + +export const allLegiArticleTexteNatures = [ + "ACCORD_FONCTION_PUBLIQUE", // 9, + "ARRETE", // 566126, + "AVIS", // 12, + "CIRCULAIRE", // 8, + "CODE", // 475255, + "CONSTITUTION", // 255, + "CONVENTION", // 1, + "DECISION", // 44, + "DECRET_LOI", // 905, + "DECRET", // 513465, + "DELIBERATION", // 1467, + "DIRECTIVE", // 57, + "LOI_CONSTIT", // 103, + "LOI_ORGANIQUE", // 1468, + "LOI_PROGRAMME", // 65, + "LOI", // 94775, + "ORDONNANCE", // 26800, + "RAPPORT", // 22, +] as const +export const allLegiArticleTexteNaturesMutable = [...allLegiArticleTexteNatures] + +export const allLegiArticleTypes = [ + "AUTONOME", + "ENTIEREMENT_MODIF", + "PARTIELLEMENT_MODIF", +] as const +export const allLegiArticleTypesMutable = [...allLegiArticleTypes] diff --git a/src/scripts/import_dole.ts b/src/scripts/import_dole.ts index ac8a28b..ecc9c07 100644 --- a/src/scripts/import_dole.ts +++ b/src/scripts/import_dole.ts @@ -7,7 +7,7 @@ import path from "path" import type { JSONValue } from "postgres" import sade from "sade" -import { auditDossierLegislatif } from "$lib/auditors/dossiers_legislatifs" +import { auditDossierLegislatif } from "$lib/auditors/dole" import type { DossierLegislatif, XmlHeader } from "$lib/legal" import { db } from "$lib/server/database" import { walkDir } from "$lib/server/file_systems" diff --git a/src/scripts/import_jorf.ts b/src/scripts/import_jorf.ts index b0711b7..cad46f8 100644 --- a/src/scripts/import_jorf.ts +++ b/src/scripts/import_jorf.ts @@ -8,9 +8,10 @@ import type { JSONValue } from "postgres" import sade from "sade" import { auditId, auditVersions } from "$lib/auditors/legal" +import { auditJorfArticle } from "$lib/auditors/jorf" import type { - Article, Jo, + JorfArticle, SectionTa, Textelr, TexteVersion, @@ -107,7 +108,7 @@ async function importJorf( ).map(({ eli }) => eli), ) - const dataDir = path.join(dilaDir, "dole") + const dataDir = path.join(dilaDir, "jorf") assert(await fs.pathExists(dataDir)) iterXmlFiles: for (const relativeSplitPath of walkDir(dataDir)) { const relativePath = path.join(...relativeSplitPath) @@ -134,7 +135,7 @@ async function importJorf( for (const [key, element] of Object.entries(xmlData) as [ string, ( - | Article + | JorfArticle | Jo | SectionTa | Textelr @@ -151,7 +152,19 @@ async function importJorf( break } case "ARTICLE": { - const article = element as Article + const [article, error] = auditChain(auditJorfArticle, auditRequire)( + strictAudit, + element, + ) as [JorfArticle, unknown] + assert.strictEqual( + error, + null, + `Unexpected format for ARTICLE:\n${JSON.stringify( + article, + null, + 2, + )}\nError:\n${JSON.stringify(error, null, 2)}`, + ) await db` INSERT INTO article ( id, @@ -184,7 +197,6 @@ async function importJorf( 2, )}\nError:\n${JSON.stringify(idError, null, 2)}`, ) - assert await db` INSERT INTO id ( eli, @@ -249,7 +261,7 @@ async function importJorf( ) VALUES ( ${texteVersion.META.META_COMMUN.ID}, ${db.json(texteVersion as unknown as JSONValue)}, - ${texteVersion.META.META_COMMUN.NATURE} + ${texteVersion.META.META_COMMUN.NATURE}, setweight(to_tsvector('french', ${textAFragments.join( " ", )}), 'A') diff --git a/src/scripts/import_kali.ts b/src/scripts/import_kali.ts index bfb1f10..5127791 100644 --- a/src/scripts/import_kali.ts +++ b/src/scripts/import_kali.ts @@ -97,7 +97,7 @@ async function importKali( ).map(({ id }) => id), ) - const dataDir = path.join(dilaDir, "dole") + const dataDir = path.join(dilaDir, "kali") assert(await fs.pathExists(dataDir)) iterXmlFiles: for (const relativeSplitPath of walkDir(dataDir)) { const relativePath = path.join(...relativeSplitPath) @@ -206,7 +206,7 @@ async function importKali( ) VALUES ( ${texteVersion.META.META_COMMUN.ID}, ${db.json(texteVersion as unknown as JSONValue)}, - ${texteVersion.META.META_COMMUN.NATURE} + ${texteVersion.META.META_COMMUN.NATURE}, setweight(to_tsvector('french', ${textAFragments.join( " ", )}), 'A') diff --git a/src/scripts/import_legi.ts b/src/scripts/import_legi.ts index 4dc0cd2..d26965d 100644 --- a/src/scripts/import_legi.ts +++ b/src/scripts/import_legi.ts @@ -8,8 +8,12 @@ import type { JSONValue } from "postgres" import sade from "sade" import { auditId, auditVersions } from "$lib/auditors/legal" +import { + auditLegiArticle, + // legiArticleStats +} from "$lib/auditors/legi" import type { - Article, + LegiArticle, SectionTa, Textelr, TexteVersion, @@ -98,7 +102,7 @@ async function importLegi( ).map(({ eli }) => eli), ) - const dataDir = path.join(dilaDir, "dole") + const dataDir = path.join(dilaDir, "legi") assert(await fs.pathExists(dataDir)) iterXmlFiles: for (const relativeSplitPath of walkDir(dataDir)) { const relativePath = path.join(...relativeSplitPath) @@ -124,7 +128,7 @@ async function importLegi( const xmlData = xmlParser.parse(xmlString) for (const [key, element] of Object.entries(xmlData) as [ string, - Article | SectionTa | Textelr | TexteVersion | Versions | XmlHeader, + LegiArticle | SectionTa | Textelr | TexteVersion | Versions | XmlHeader, ][]) { switch (key) { case "?xml": { @@ -134,7 +138,19 @@ async function importLegi( break } case "ARTICLE": { - const article = element as Article + const [article, error] = auditChain(auditLegiArticle, auditRequire)( + strictAudit, + element, + ) as [LegiArticle, unknown] + assert.strictEqual( + error, + null, + `Unexpected format for ARTICLE:\n${JSON.stringify( + article, + null, + 2, + )}\nError:\n${JSON.stringify(error, null, 2)}`, + ) await db` INSERT INTO article ( id, @@ -215,7 +231,7 @@ async function importLegi( ) VALUES ( ${texteVersion.META.META_COMMUN.ID}, ${db.json(texteVersion as unknown as JSONValue)}, - ${texteVersion.META.META_COMMUN.NATURE} + ${texteVersion.META.META_COMMUN.NATURE}, setweight(to_tsvector('french', ${textAFragments.join( " ", )}), 'A') @@ -342,6 +358,10 @@ async function importLegi( ` } } + // console.log( + // "LEGI articles stats =", + // JSON.stringify(legiArticleStats, null, 2), + // ) } sade("import_legi ", true)