diff --git a/src/lib/aggregates.ts b/src/lib/aggregates.ts
index 00e8a4b..e984c29 100644
--- a/src/lib/aggregates.ts
+++ b/src/lib/aggregates.ts
@@ -1,6 +1,22 @@
+import type { Article, SectionTa, Textelr, TexteVersion } from "$lib/legal"
+
+export interface Aggregate {
+ article?: { [id: string]: Article }
+ id?: string
+ ids?: string[]
+ section_ta?: { [id: string]: SectionTa }
+ texte_version?: { [id: string]: TexteVersion }
+ textelr?: { [id: string]: Textelr }
+}
+
export type Follow = typeof allFollows[number]
export const allFollows = [
"LIENS.LIEN[@sens=cible,@typelien=CREATION].@id",
+ "STRUCT.LIEN_ART.@id",
+ "STRUCT.LIEN_SECTION_TA.@id",
+ "STRUCTURE_TA.LIEN_ART.@id",
+ "STRUCTURE_TA.LIEN_SECTION_TA.@id",
+ "TEXTELR",
] as const
export const allFollowsMutable = [...allFollows]
diff --git a/src/lib/auditors/search_params.ts b/src/lib/auditors/search_params.ts
index 1bf9570..1c17df7 100644
--- a/src/lib/auditors/search_params.ts
+++ b/src/lib/auditors/search_params.ts
@@ -57,7 +57,7 @@ export function auditLimitSearchParam(
(value: number) => value <= 100,
"Value must be less than or equal to 100",
),
- auditSetNullish(10),
+ auditSetNullish(20),
),
)
}
diff --git a/src/lib/components/ArticleView.svelte b/src/lib/components/ArticleView.svelte
new file mode 100644
index 0000000..0ef1206
--- /dev/null
+++ b/src/lib/components/ArticleView.svelte
@@ -0,0 +1,21 @@
+
+
+{#if summary !== undefined}
+
+
+
+{/if}
+
+{@html article.BLOC_TEXTUEL.CONTENU}
diff --git a/src/lib/components/IdPagesSwitcher.svelte b/src/lib/components/IdPagesSwitcher.svelte
new file mode 100644
index 0000000..db9c5fa
--- /dev/null
+++ b/src/lib/components/IdPagesSwitcher.svelte
@@ -0,0 +1,20 @@
+
+
+{#if items !== undefined}
+
+ {#each items as { href, label }}
+
{label}
+ {/each}
+
+{/if}
diff --git a/src/lib/components/Pagination.svelte b/src/lib/components/Pagination.svelte
index 8aaac44..f823f9e 100644
--- a/src/lib/components/Pagination.svelte
+++ b/src/lib/components/Pagination.svelte
@@ -38,7 +38,17 @@
function newPaginationUrl(
pathname: string,
- query: Partial | { [key: string]: string },
+ query:
+ | Partial
+ | {
+ [key: string]:
+ | boolean
+ | number
+ | string
+ | undefined
+ | null
+ | Array
+ },
{ limit, offset }: { limit?: number; offset?: number } = {},
) {
query = { ...query }
@@ -53,10 +63,20 @@
delete query.offset
}
const search = new URLSearchParams(
- Object.entries(query).map(([key, value]) => [
- key,
- typeof value === "number" ? value.toString() : value,
- ]),
+ Object.entries(query).reduce((couples, [key, value]) => {
+ if (value != null) {
+ if (Array.isArray(value)) {
+ for (const item of value) {
+ if (item != null) {
+ couples.push([key, item.toString()])
+ }
+ }
+ } else {
+ couples.push([key, value.toString()])
+ }
+ }
+ return couples
+ }, [] as Array<[string, string]>),
).toString()
return search ? `${pathname}?${search}` : pathname
}
diff --git a/src/lib/components/SectionTaView.svelte b/src/lib/components/SectionTaView.svelte
new file mode 100644
index 0000000..a342907
--- /dev/null
+++ b/src/lib/components/SectionTaView.svelte
@@ -0,0 +1,50 @@
+
+
+
+
+
+ {#if showArticles}
+ {#each [...iterArrayOrSingleton(sectionTa.STRUCTURE_TA.LIEN_ART)] as lienArt}
+ {@const article = data.article?.[lienArt["@id"]]}
+ {#if article !== undefined}
+
+ {/if}
+ {/each}
+ {:else if sectionTa.STRUCTURE_TA.LIEN_ART !== undefined}
+
+ {#each [...iterArrayOrSingleton(sectionTa.STRUCTURE_TA.LIEN_ART)] as lienArt}
+ -
+ Article {lienArt["@num"]}
+
+ {/each}
+
+ {/if}
+
+ {#each [...iterArrayOrSingleton(sectionTa.STRUCTURE_TA.LIEN_SECTION_TA)] as lienSectionTa}
+ {@const sectionTa = data.section_ta?.[lienSectionTa["@id"]]}
+ {#if sectionTa !== undefined}
+
+ {/if}
+ {/each}
+
diff --git a/src/lib/components/TexteVersionView.svelte b/src/lib/components/TexteVersionView.svelte
new file mode 100644
index 0000000..4c411d3
--- /dev/null
+++ b/src/lib/components/TexteVersionView.svelte
@@ -0,0 +1,36 @@
+
+
+{#if summary !== undefined}
+
+{/if}
+
+{#if textelr !== undefined}
+
+{/if}
diff --git a/src/lib/components/TextelrView.svelte b/src/lib/components/TextelrView.svelte
new file mode 100644
index 0000000..d6fe0f2
--- /dev/null
+++ b/src/lib/components/TextelrView.svelte
@@ -0,0 +1,37 @@
+
+
+{#if showArticles}
+ {#each [...iterArrayOrSingleton(textelr.STRUCT.LIEN_ART)] as lienArt}
+ {@const article = data.article?.[lienArt["@id"]]}
+ {#if article !== undefined}
+
+ {/if}
+ {/each}
+{:else if textelr.STRUCT.LIEN_ART !== undefined}
+
+ {#each [...iterArrayOrSingleton(textelr.STRUCT.LIEN_ART)] as lienArt}
+ -
+ Article {lienArt["@num"]}
+
+ {/each}
+
+{/if}
+
+{#each [...iterArrayOrSingleton(textelr.STRUCT.LIEN_SECTION_TA)] as lienSectionTa}
+ {@const sectionTa = data.section_ta?.[lienSectionTa["@id"]]}
+ {#if sectionTa !== undefined}
+
+ {/if}
+{/each}
diff --git a/src/lib/legal.ts b/src/lib/legal.ts
index 1b4a565..671df52 100644
--- a/src/lib/legal.ts
+++ b/src/lib/legal.ts
@@ -140,6 +140,17 @@ export interface LienArt {
"@origine": "LEGI"
}
+export interface LienSectionTa {
+ "@id": string
+ "@cid": string
+ "@fin": string
+ "@niv": string
+ "@url": string
+ "@etat": Etat
+ "@debut": string
+ "#text": string
+}
+
export interface MetaCommun {
ID: string
}
@@ -165,6 +176,7 @@ export interface SectionTa {
TITRE_TA: string
STRUCTURE_TA: {
LIEN_ART?: LienArt | LienArt[]
+ LIEN_SECTION_TA?: LienSectionTa | LienSectionTa[]
}
}
@@ -186,6 +198,7 @@ export interface Textelr {
}
STRUCT: {
LIEN_ART?: LienArt | LienArt[]
+ LIEN_SECTION_TA?: LienSectionTa | LienSectionTa[]
}
VERSIONS: {
VERSION: TextelrVersion | TextelrVersion[]
@@ -293,7 +306,7 @@ export const appMenu: MenuItem[] = [
{
items: [
{ href: "/idcc", label: "Accords de branche et conventions collectives" },
- { href: "/texte_version", label: "Codes, lois et règlements" },
+ { href: "/textes", label: "Codes, lois et règlements" },
{ href: "/dossier_legislatif", label: "Dossiers législatifs" },
{ href: "/jo", label: "Journal officiel" },
],
@@ -355,36 +368,34 @@ export function bestItemForDate(
return items[0]
}
+export function menuItemsFromLegalId(
+ id: string | undefined | null,
+): MenuItem[] | undefined {
+ if (id == null) {
+ return undefined
+ }
+ const rootType = rootTypeFromLegalId(id)
+ if (rootType === undefined) {
+ return undefined
+ }
+ switch (rootType) {
+ case "texte_version":
+ return [
+ { href: `/textes/${id}`, label: "Présentation" },
+ { href: `/texte_version/${id}`, label: "TEXTE_VERSION" },
+ { href: `/textelr/${id}`, label: "TEXTELR" },
+ ]
+ default:
+ return undefined
+ }
+}
+
export function pathnameFromLegalId(id: string): string | undefined {
- if (id.match(/^[A-Z]{4}ARTI/) !== null) {
- return `/article/${id}`
+ const rootType = rootTypeFromLegalId(id)
+ if (rootType === undefined) {
+ return undefined
}
- if (id.match(/^[A-Z]{4}DOLE/) !== null) {
- return `/dossier_legislatif/${id}`
- }
- if (id.match(/^KALICONT/) !== null) {
- return `/idcc/${id}`
- }
- if (id.match(/^JORFCONT/) !== null) {
- return `/jo/${id}`
- }
- if (id.match(/^[A-Z]{4}SCTA/) !== null) {
- return `/section_ta/${id}`
- }
- if (id.match(/^[A-Z]{4}TEXT/) !== null) {
- return `/texte_version/${id}`
- }
- // TODO: Ce test est redondant avec le précédent (pour KALITEXT).
- // => Trouver quel lien mettre par défaut.
- // if (id.match(/^KALITEXT/) !== null) {
- // return `/textekali/${id}`
- // }
- // TODO: Ce test est redondant avec le précédent (pour JORFTEXT & LEGITEXT).
- // => Trouver quel lien mettre par défaut.
- // if (id.match(/^[A-Z]{4}TEXT/) !== null) {
- // return `/textelr/${id}`
- // }
- return undefined
+ return `/${rootType}/${id}`
}
export function pathnameFromLegalObject(
@@ -450,3 +461,28 @@ export function pathnameFromLegalObjectId(
assertNeverLegalObjectType(type)
}
}
+
+export function rootTypeFromLegalId(id: string): LegalObjectType | undefined {
+ if (!id) {
+ return undefined
+ }
+ if (id.match(/^[A-Z]{4}ARTI/) !== null) {
+ return "article"
+ }
+ if (id.match(/^[A-Z]{4}DOLE/) !== null) {
+ return "dossier_legislatif"
+ }
+ if (id.match(/^KALICONT/) !== null) {
+ return "idcc"
+ }
+ if (id.match(/^JORFCONT/) !== null) {
+ return "jo"
+ }
+ if (id.match(/^[A-Z]{4}SCTA/) !== null) {
+ return "section_ta"
+ }
+ if (id.match(/^[A-Z]{4}TEXT/) !== null) {
+ return "texte_version"
+ }
+ throw new Error(`Unexpected legal ID: "${id}"`)
+}
diff --git a/src/lib/server/aggregates.ts b/src/lib/server/aggregates.ts
index bb7bf63..83c700c 100644
--- a/src/lib/server/aggregates.ts
+++ b/src/lib/server/aggregates.ts
@@ -1,20 +1,24 @@
import { iterArrayOrSingleton } from "@tricoteuses/explorer-tools"
-import type { Follow } from "$lib/aggregates"
-import type { Article, Lien } from "$lib/legal"
+import type { Aggregate, Follow } from "$lib/aggregates"
+import {
+ rootTypeFromLegalId,
+ type Article,
+ type LegalObjectType,
+ type SectionTa,
+ type Textelr,
+ type TexteVersion,
+} from "$lib/legal"
import { db } from "$lib/server/database"
-export interface Aggregate {
- article?: { [id: string]: Article }
- id?: string
- ids?: string[]
-}
-
export class Aggregator {
article: { [id: string]: Article } = {}
follow: Set
- requestedIds: Set = new Set()
- visitedIds: Set = new Set()
+ requestedTypeAndIds: Set = new Set()
+ section_ta: { [id: string]: SectionTa } = {}
+ texte_version: { [id: string]: TexteVersion } = {}
+ textelr: { [id: string]: Textelr } = {}
+ visitedTypeAndIds: Set = new Set()
constructor(follow: Iterable) {
this.follow = new Set(follow)
@@ -33,46 +37,135 @@ export class Aggregator {
}
}
- addToVisitedIds(ids: string[]) {
- for (const id of ids) {
- this.visitedIds.add(id)
+ addSectionTa(sectionTa: SectionTa): void {
+ const id = sectionTa.ID
+ this.section_ta[id] = sectionTa
+
+ if (this.follow.has("STRUCTURE_TA.LIEN_ART.@id")) {
+ for (const lien of iterArrayOrSingleton(
+ sectionTa.STRUCTURE_TA.LIEN_ART,
+ )) {
+ this.requestId(lien["@id"])
+ }
+ }
+
+ if (this.follow.has("STRUCTURE_TA.LIEN_SECTION_TA.@id")) {
+ for (const lien of iterArrayOrSingleton(
+ sectionTa.STRUCTURE_TA.LIEN_SECTION_TA,
+ )) {
+ this.requestId(lien["@id"])
+ }
}
}
- deleteFromRequestedIds(ids: string[]) {
- for (const id of ids) {
- this.requestedIds.delete(id)
+ addTextelr(textelr: Textelr): void {
+ const id = textelr.META.META_COMMUN.ID
+ this.textelr[id] = textelr
+
+ if (this.follow.has("STRUCT.LIEN_ART.@id")) {
+ for (const lien of iterArrayOrSingleton(textelr.STRUCT.LIEN_ART)) {
+ this.requestId(lien["@id"])
+ }
+ }
+
+ if (this.follow.has("STRUCT.LIEN_SECTION_TA.@id")) {
+ for (const lien of iterArrayOrSingleton(textelr.STRUCT.LIEN_SECTION_TA)) {
+ this.requestId(lien["@id"])
+ }
+ }
+ }
+
+ addTexteVersion(texteVersion: TexteVersion): void {
+ const id = texteVersion.META.META_COMMUN.ID
+ this.texte_version[id] = texteVersion
+
+ if (this.follow.has("TEXTELR")) {
+ this.requestTypeAndId(["textelr", id])
+ }
+ }
+
+ addToVisitedTypeAndIds(typeAndIds: TypeAndId[]) {
+ for (const typeAndId of typeAndIds) {
+ this.visitedTypeAndIds.add(typeAndId)
+ }
+ }
+
+ deleteFromRequestedTypeAndIds(typeAndIds: TypeAndId[]) {
+ for (const typeAndId of typeAndIds) {
+ this.requestedTypeAndIds.delete(typeAndId)
}
}
async getAll(): Promise {
while (true) {
- if (this.requestedIds.size === 0) {
+ if (this.requestedTypeAndIds.size === 0) {
break
}
- console.log("this.requestedIds.size", this.requestedIds.size)
+ console.log(
+ "this.requestedTypeAndIds.size",
+ this.requestedTypeAndIds.size,
+ )
{
- const articleIds = [...this.requestedIds].filter(
- (id) => id.match(/^[A-Z]{4}ARTI/) !== null,
+ const articleTypeAndIds = [...this.requestedTypeAndIds].filter(
+ ([type]) => type === "article",
)
- if (articleIds.length > 0) {
- this.deleteFromRequestedIds(articleIds)
+ if (articleTypeAndIds.length > 0) {
+ this.deleteFromRequestedTypeAndIds(articleTypeAndIds)
for (const { data } of await db<{ id: string; data: Article }[]>`
SELECT id, data FROM article
- WHERE id IN ${db(articleIds)}
+ WHERE id IN ${db(articleTypeAndIds.map(([, id]) => id))}
`) {
this.addArticle(data)
}
- this.addToVisitedIds(articleIds)
+ this.addToVisitedTypeAndIds(articleTypeAndIds)
+ }
+ }
+
+ {
+ const sectionTaTypeAndIds = [...this.requestedTypeAndIds].filter(
+ ([type]) => type === "section_ta",
+ )
+ if (sectionTaTypeAndIds.length > 0) {
+ this.deleteFromRequestedTypeAndIds(sectionTaTypeAndIds)
+ for (const { data } of await db<{ id: string; data: SectionTa }[]>`
+ SELECT id, data FROM section_ta
+ WHERE id IN ${db(sectionTaTypeAndIds.map(([, id]) => id))}
+ `) {
+ this.addSectionTa(data)
+ }
+ this.addToVisitedTypeAndIds(sectionTaTypeAndIds)
+ }
+ }
+
+ {
+ const textelrTypeAndIds = [...this.requestedTypeAndIds].filter(
+ ([type]) => type === "textelr",
+ )
+ if (textelrTypeAndIds.length > 0) {
+ this.deleteFromRequestedTypeAndIds(textelrTypeAndIds)
+ for (const { data } of await db<{ id: string; data: Textelr }[]>`
+ SELECT id, data FROM textelr
+ WHERE id IN ${db(textelrTypeAndIds.map(([, id]) => id))}
+ `) {
+ this.addTextelr(data)
+ }
+ this.addToVisitedTypeAndIds(textelrTypeAndIds)
}
}
}
}
requestId(id: string): void {
- if (!this.visitedIds.has(id)) {
- this.requestedIds.add(id)
+ const rootType = rootTypeFromLegalId(id)
+ if (rootType !== undefined) {
+ return this.requestTypeAndId([rootType, id])
+ }
+ }
+
+ requestTypeAndId(typeAndId: TypeAndId): void {
+ if (!this.visitedTypeAndIds.has(typeAndId)) {
+ this.requestedTypeAndIds.add(typeAndId)
}
}
@@ -81,6 +174,17 @@ export class Aggregator {
if (Object.keys(this.article).length > 0) {
json.article = this.article
}
+ if (Object.keys(this.section_ta).length > 0) {
+ json.section_ta = this.section_ta
+ }
+ if (Object.keys(this.texte_version).length > 0) {
+ json.texte_version = this.texte_version
+ }
+ if (Object.keys(this.textelr).length > 0) {
+ json.textelr = this.textelr
+ }
return json
}
}
+
+export type TypeAndId = [LegalObjectType, string]
diff --git a/src/lib/server/doers/recherche.ts b/src/lib/server/doers/recherche.ts
index 3711fa0..48b1342 100644
--- a/src/lib/server/doers/recherche.ts
+++ b/src/lib/server/doers/recherche.ts
@@ -1,13 +1,13 @@
import { type Audit, auditSetNullish, cleanAudit } from "@auditors/core"
import { error } from "@sveltejs/kit"
-import type { Follow } from "$lib/aggregates"
+import type { Aggregate, Follow } from "$lib/aggregates"
import {
auditFollowSearchParams,
auditQSearchParam,
} from "$lib/auditors/search_params"
import type { Article } from "$lib/legal"
-import { type Aggregate, Aggregator } from "$lib/server/aggregates"
+import { Aggregator } from "$lib/server/aggregates"
import { db } from "$lib/server/database"
export function auditSearchParams(
@@ -41,15 +41,15 @@ export function auditSearchParams(
export const doGetRecherche = async (
url: URL,
): Promise<
- | (Aggregate & {
- q: string
- })
- | null
+ Aggregate & {
+ follow: Follow[]
+ q?: string
+ }
> => {
const [query, queryError] = auditSearchParams(
cleanAudit,
url.searchParams,
- ) as [{ follow: Follow[]; q?: string }, unknown]
+ ) as [{ follow: Set; q?: string }, unknown]
if (queryError !== null) {
console.error(
`Error in ${url.pathname} query:\n${JSON.stringify(
@@ -62,6 +62,8 @@ export const doGetRecherche = async (
}
const { follow, q } = query
+ const aggregator = new Aggregator(follow)
+ let id: string | undefined = undefined
if (q !== undefined) {
// https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006308296/
// https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006308296/1983-12-30/
@@ -69,23 +71,25 @@ export const doGetRecherche = async (
// https://www.legifrance.gouv.fr/loda/article_lc/LEGIARTI000036456533
// https://www.legifrance.gouv.fr/loda/article_lc/LEGIARTI000036456533/2018-01-01
// https://www.legifrance.gouv.fr/loda/id/LEGIARTI000006317314/1983-12-30
- const articleId = q.match(/LEGIARTI\d+/)?.[0]
- if (articleId != null) {
+ id = q.match(/LEGIARTI\d+/)?.[0]
+ if (id != null) {
const article = (
await db<{ data: Article }[]>`
SELECT data FROM article
- WHERE id = ${articleId}
- LIMIT 1
+ WHERE id = ${id}
`
).map(({ data }) => data)[0]
if (article !== undefined) {
- const aggregator = new Aggregator(follow)
aggregator.addArticle(article)
- await aggregator.getAll()
-
- return { ...aggregator.toJson(), id: article.META.META_COMMUN.ID, q }
}
}
}
- return null
+ await aggregator.getAll()
+
+ return {
+ ...aggregator.toJson(),
+ follow: [...follow],
+ id,
+ q,
+ }
}
diff --git a/src/lib/server/doers/textes.ts b/src/lib/server/doers/textes.ts
new file mode 100644
index 0000000..7a12cd8
--- /dev/null
+++ b/src/lib/server/doers/textes.ts
@@ -0,0 +1,178 @@
+import { type Audit, auditSetNullish, cleanAudit } from "@auditors/core"
+import { error } from "@sveltejs/kit"
+
+import type { Aggregate, Follow } from "$lib/aggregates"
+import {
+ auditFollowSearchParams,
+ auditLimitSearchParam,
+ auditOffsetSearchParam,
+ auditQSearchParam,
+} from "$lib/auditors/search_params"
+import type { TexteVersion } from "$lib/legal"
+import { Aggregator } from "$lib/server/aggregates"
+import { db } from "$lib/server/database"
+
+export function auditGetTexteSearchParams(
+ audit: Audit,
+ query: URLSearchParams,
+): [unknown, unknown] {
+ if (query == null) {
+ return [query, null]
+ }
+ if (!(query instanceof URLSearchParams)) {
+ return audit.unexpectedType(query, "URLSearchParams")
+ }
+
+ const data: { [key: string]: unknown } = {}
+ for (const [key, value] of query.entries()) {
+ let values = data[key] as string[] | undefined
+ if (values === undefined) {
+ values = data[key] = []
+ }
+ values.push(value)
+ }
+ const errors: { [key: string]: unknown } = {}
+ const remainingKeys = new Set(Object.keys(data))
+
+ auditFollowSearchParams(audit, data, errors, remainingKeys)
+
+ return audit.reduceRemaining(data, errors, remainingKeys, auditSetNullish({}))
+}
+
+export function auditListTextesSearchParams(
+ audit: Audit,
+ query: URLSearchParams,
+): [unknown, unknown] {
+ if (query == null) {
+ return [query, null]
+ }
+ if (!(query instanceof URLSearchParams)) {
+ return audit.unexpectedType(query, "URLSearchParams")
+ }
+
+ const data: { [key: string]: unknown } = {}
+ for (const [key, value] of query.entries()) {
+ let values = data[key] as string[] | undefined
+ if (values === undefined) {
+ values = data[key] = []
+ }
+ values.push(value)
+ }
+ const errors: { [key: string]: unknown } = {}
+ const remainingKeys = new Set(Object.keys(data))
+
+ auditFollowSearchParams(audit, data, errors, remainingKeys)
+ auditLimitSearchParam(audit, data, errors, remainingKeys)
+ auditOffsetSearchParam(audit, data, errors, remainingKeys)
+ auditQSearchParam(audit, data, errors, remainingKeys)
+
+ return audit.reduceRemaining(data, errors, remainingKeys, auditSetNullish({}))
+}
+
+export const doGetTexte = async (
+ id: string,
+ url: URL,
+): Promise<
+ Aggregate & {
+ follow: Follow[]
+ }
+> => {
+ const [query, queryError] = auditGetTexteSearchParams(
+ cleanAudit,
+ url.searchParams,
+ ) as [
+ {
+ follow: Set
+ },
+ unknown,
+ ]
+ if (queryError !== null) {
+ console.error(
+ `Error in ${url.pathname} query:\n${JSON.stringify(
+ query,
+ null,
+ 2,
+ )}\n\nError:\n${JSON.stringify(queryError, null, 2)}`,
+ )
+ throw error(400, JSON.stringify(queryError, null, 2))
+ }
+ const { follow } = query
+ const texteVersion = (
+ await db<{ data: TexteVersion }[]>`
+ SELECT data FROM texte_version
+ WHERE ID = ${id}
+ `
+ ).map(({ data }) => data)[0]
+ if (texteVersion === undefined) {
+ throw error(404, `TEXTE_VERSION ${id} non trouvé`)
+ }
+
+ const aggregator = new Aggregator(follow)
+ aggregator.addTexteVersion(texteVersion)
+ await aggregator.getAll()
+
+ return {
+ ...aggregator.toJson(),
+ follow: [...follow],
+ id,
+ }
+}
+
+export const doListTextes = async (
+ url: URL,
+): Promise<
+ Aggregate & {
+ follow: Follow[]
+ limit: number
+ offset: number
+ q?: string
+ }
+> => {
+ const [query, queryError] = auditListTextesSearchParams(
+ cleanAudit,
+ url.searchParams,
+ ) as [
+ {
+ follow: Set
+ limit: number
+ offset: number
+ q?: string
+ },
+ unknown,
+ ]
+ if (queryError !== null) {
+ console.error(
+ `Error in ${url.pathname} query:\n${JSON.stringify(
+ query,
+ null,
+ 2,
+ )}\n\nError:\n${JSON.stringify(queryError, null, 2)}`,
+ )
+ throw error(400, JSON.stringify(queryError, null, 2))
+ }
+ const { follow, limit, offset, q } = query
+ const texteVersionArray = (
+ await db<{ data: TexteVersion }[]>`
+ SELECT data FROM texte_version
+ OFFSET ${offset}
+ LIMIT ${limit}
+ `
+ ).map(({ data }) => data)
+
+ const aggregator = new Aggregator(follow)
+ for (const texteVersion of texteVersionArray) {
+ aggregator.addTexteVersion(texteVersion)
+ }
+ await aggregator.getAll()
+
+ return {
+ ...aggregator.toJson(),
+ follow: [...follow],
+ ids: texteVersionArray.map(
+ (texteVersion) => texteVersion.META.META_COMMUN.ID,
+ ),
+ limit,
+ offset,
+ q,
+ }
+}
diff --git a/src/lib/summaries.ts b/src/lib/summaries.ts
index 5972e8a..9433b49 100644
--- a/src/lib/summaries.ts
+++ b/src/lib/summaries.ts
@@ -14,6 +14,7 @@ import {
type LegalObjectType,
type Lien,
type LienArt,
+ type LienSectionTa,
pathnameFromLegalId,
pathnameFromLegalObject,
pathnameFromLegalObjectId,
@@ -261,7 +262,7 @@ export function summarizeLegalObject(
]
return {
items: [
- `Article ${metaArticle.TYPE} ${metaArticle.ETAT} n° ${metaArticle.NUM}, en vigueur`,
+ `Article ${metaArticle.NUM} ${metaArticle.TYPE} ${metaArticle.ETAT}, en vigueur`,
...(metaArticle.DATE_FIN === "2999-01-01"
? ([
" depuis le ",
@@ -373,7 +374,7 @@ export const summarizeLienArt: Summarizer = (access, value) => {
return undefined
}
return {
- content: `Article n° ${lienArt["@num"]}`,
+ content: `Article ${lienArt["@num"]}`,
href: pathnameFromLegalObjectId("article", lienArt["@id"]),
type: "link",
}
@@ -423,6 +424,36 @@ export const summarizeLienId: Summarizer = (access, value) => {
}
}
+export const summarizeLienSectionTa: Summarizer = (access, value) => {
+ const lienSectionTa = value as LienSectionTa | undefined
+ if (lienSectionTa === undefined) {
+ return undefined
+ }
+ return {
+ content: lienSectionTa["#text"],
+ href: pathnameFromLegalObjectId("section_ta", lienSectionTa["@id"]),
+ type: "link",
+ }
+}
+
+export const summarizeLienSectionTaId: Summarizer = (access, value) => {
+ const lienSectionTa = value as LienSectionTa | undefined
+ if (lienSectionTa === undefined) {
+ return undefined
+ }
+ return {
+ items: [
+ {
+ content: JSON.stringify(lienSectionTa["@id"]),
+ type: "raw_data",
+ },
+ { class: "mt-1 mx-1", icon: arrowRight, inline: true, type: "icon" },
+ summarizeLienSectionTa(access, lienSectionTa)!,
+ ],
+ type: "concatenation",
+ }
+}
+
export const summarizeSectionTaProperties: Summarizer = (access, value) => {
if (access?.key === "section_ta" && typeof value !== "number") {
return summarizeLegalObject(access, "section_ta", value)
@@ -434,6 +465,14 @@ export const summarizeSectionTaProperties: Summarizer = (access, value) => {
if (access?.key === "@cid" && access?.access?.key === "TEXTE") {
return summarizeLegalIdToLink(access, value)
}
+ if (
+ access?.key === "@cid" &&
+ (access?.access?.key === "LIEN_SECTION_TA" ||
+ (typeof access?.access?.key === "number" &&
+ access?.access?.access?.key === "LIEN_SECTION_TA"))
+ ) {
+ return summarizeLegalIdToLink(access, value)
+ }
if (
access?.key === "@id" &&
(access?.access?.key === "LIEN_ART" ||
@@ -442,12 +481,27 @@ export const summarizeSectionTaProperties: Summarizer = (access, value) => {
) {
return summarizeLienArtId(access.access, access.parent)
}
+ if (
+ access?.key === "@id" &&
+ (access?.access?.key === "LIEN_SECTION_TA" ||
+ (typeof access?.access?.key === "number" &&
+ access?.access?.access?.key === "LIEN_SECTION_TA"))
+ ) {
+ return summarizeLienSectionTaId(access.access, access.parent)
+ }
if (
(access?.key === "LIEN_ART" && !Array.isArray(value)) ||
(typeof access?.key === "number" && access?.access?.key === "LIEN_ART")
) {
return summarizeLienArt(access, value)
}
+ if (
+ (access?.key === "LIEN_SECTION_TA" && !Array.isArray(value)) ||
+ (typeof access?.key === "number" &&
+ access?.access?.key === "LIEN_SECTION_TA")
+ ) {
+ return summarizeLienSectionTa(access, value)
+ }
return undefined
}
@@ -490,6 +544,14 @@ export const summarizeTextelrProperties: Summarizer = (access, value) => {
return summarizeLegalObjectToLink(access, "textelr", value)
}
+ if (
+ access?.key === "@cid" &&
+ (access?.access?.key === "LIEN_SECTION_TA" ||
+ (typeof access?.access?.key === "number" &&
+ access?.access?.access?.key === "LIEN_SECTION_TA"))
+ ) {
+ return summarizeLegalIdToLink(access, value)
+ }
if (
access?.key === "@id" &&
(access?.access?.key === "LIEN_ART" ||
@@ -498,6 +560,14 @@ export const summarizeTextelrProperties: Summarizer = (access, value) => {
) {
return summarizeLienArtId(access.access, access.parent)
}
+ if (
+ access?.key === "@id" &&
+ (access?.access?.key === "LIEN_SECTION_TA" ||
+ (typeof access?.access?.key === "number" &&
+ access?.access?.access?.key === "LIEN_SECTION_TA"))
+ ) {
+ return summarizeLienSectionTaId(access.access, access.parent)
+ }
if (access?.key === "CID") {
return summarizeLegalIdToLink(access, value)
}
@@ -507,6 +577,13 @@ export const summarizeTextelrProperties: Summarizer = (access, value) => {
) {
return summarizeLienArt(access, value)
}
+ if (
+ (access?.key === "LIEN_SECTION_TA" && !Array.isArray(value)) ||
+ (typeof access?.key === "number" &&
+ access?.access?.key === "LIEN_SECTION_TA")
+ ) {
+ return summarizeLienSectionTa(access, value)
+ }
if (access?.key === "LIEN_TXT") {
return summarizeTextelrVersionLienTxt(access, value)
}
diff --git a/src/routes/api/recherche/+server.ts b/src/routes/api/recherche/+server.ts
index a0ed47e..5b43846 100644
--- a/src/routes/api/recherche/+server.ts
+++ b/src/routes/api/recherche/+server.ts
@@ -4,11 +4,9 @@ import type { RequestHandler } from "./$types"
export const GET: RequestHandler = async ({ url }) => {
const result = await doGetRecherche(url)
- return result === null
- ? new Response(null, { status: 204 })
- : new Response(JSON.stringify(result, null, 2), {
- headers: {
- "Content-Type": "application/json; charset=utf-8",
- },
- })
+ return new Response(JSON.stringify(result, null, 2), {
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ })
}
diff --git a/src/routes/api/textes/+server.ts b/src/routes/api/textes/+server.ts
new file mode 100644
index 0000000..e374aa1
--- /dev/null
+++ b/src/routes/api/textes/+server.ts
@@ -0,0 +1,12 @@
+import { doListTextes } from "$lib/server/doers/textes"
+
+import type { RequestHandler } from "./$types"
+
+export const GET: RequestHandler = async ({ url }) => {
+ const result = await doListTextes(url)
+ return new Response(JSON.stringify(result, null, 2), {
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ })
+}
diff --git a/src/routes/api/textes/[id]/+server.ts b/src/routes/api/textes/[id]/+server.ts
new file mode 100644
index 0000000..553e8c1
--- /dev/null
+++ b/src/routes/api/textes/[id]/+server.ts
@@ -0,0 +1,12 @@
+import { doGetTexte } from "$lib/server/doers/textes"
+
+import type { RequestHandler } from "./$types"
+
+export const GET: RequestHandler = async ({ params, url }) => {
+ const result = await doGetTexte(params.id, url)
+ return new Response(JSON.stringify(result, null, 2), {
+ headers: {
+ "Content-Type": "application/json; charset=utf-8",
+ },
+ })
+}
diff --git a/src/routes/section_ta/[id]/+page.server.ts b/src/routes/section_ta/[id]/+page.server.ts
index c1d60d9..4068773 100644
--- a/src/routes/section_ta/[id]/+page.server.ts
+++ b/src/routes/section_ta/[id]/+page.server.ts
@@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params }) => {
).map(({ data }) => data)[0]
if (sectionTa === undefined) {
- throw error(404, `Section TA ${params.id} non trouvée`)
+ throw error(404, `SECTION_TA ${params.id} non trouvé`)
}
return { section_ta: sectionTa }
}
diff --git a/src/routes/texte_version/[id]/+page.server.ts b/src/routes/texte_version/[id]/+page.server.ts
index 23aaf6b..47213e2 100644
--- a/src/routes/texte_version/[id]/+page.server.ts
+++ b/src/routes/texte_version/[id]/+page.server.ts
@@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params }) => {
).map(({ data }) => data)[0]
if (texteVersion === undefined) {
- throw error(404, `Texte version ${params.id} non trouvé`)
+ throw error(404, `TEXTE_VERSION ${params.id} non trouvé`)
}
return { texte_version: texteVersion }
}
diff --git a/src/routes/texte_version/[id]/+page.svelte b/src/routes/texte_version/[id]/+page.svelte
index 6b5be11..93583b3 100644
--- a/src/routes/texte_version/[id]/+page.svelte
+++ b/src/routes/texte_version/[id]/+page.svelte
@@ -1,6 +1,7 @@
+
+
TEXTE_VERSION
{#if summary !== undefined}
diff --git a/src/routes/textekali/[id]/+page.server.ts b/src/routes/textekali/[id]/+page.server.ts
index 67336c3..f2d3555 100644
--- a/src/routes/textekali/[id]/+page.server.ts
+++ b/src/routes/textekali/[id]/+page.server.ts
@@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params }) => {
).map(({ data }) => data)[0]
if (textekali === undefined) {
- throw error(404, `Texte KALI ${params.id} non trouvé`)
+ throw error(404, `TEXTEKALI ${params.id} non trouvé`)
}
return { textekali }
}
diff --git a/src/routes/textelr/[id]/+page.server.ts b/src/routes/textelr/[id]/+page.server.ts
index 125ef4a..40b8cd3 100644
--- a/src/routes/textelr/[id]/+page.server.ts
+++ b/src/routes/textelr/[id]/+page.server.ts
@@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params }) => {
).map(({ data }) => data)[0]
if (textelr === undefined) {
- throw error(404, `Texte LR ${params.id} non trouvé`)
+ throw error(404, `TEXTELR ${params.id} non trouvé`)
}
return { textelr: textelr }
}
diff --git a/src/routes/textelr/[id]/+page.svelte b/src/routes/textelr/[id]/+page.svelte
index e941d59..7e1ecda 100644
--- a/src/routes/textelr/[id]/+page.svelte
+++ b/src/routes/textelr/[id]/+page.svelte
@@ -1,6 +1,7 @@
+
+