Add presentation page for "Codes, lois et règlements".
This commit is contained in:
parent
72399dfb07
commit
7fb08b413d
26 changed files with 855 additions and 90 deletions
|
@ -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 type Follow = typeof allFollows[number]
|
||||||
|
|
||||||
export const allFollows = [
|
export const allFollows = [
|
||||||
"LIENS.LIEN[@sens=cible,@typelien=CREATION].@id",
|
"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
|
] as const
|
||||||
export const allFollowsMutable = [...allFollows]
|
export const allFollowsMutable = [...allFollows]
|
||||||
|
|
|
@ -57,7 +57,7 @@ export function auditLimitSearchParam(
|
||||||
(value: number) => value <= 100,
|
(value: number) => value <= 100,
|
||||||
"Value must be less than or equal to 100",
|
"Value must be less than or equal to 100",
|
||||||
),
|
),
|
||||||
auditSetNullish(10),
|
auditSetNullish(20),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
21
src/lib/components/ArticleView.svelte
Normal file
21
src/lib/components/ArticleView.svelte
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
import type { Aggregate } from "$lib/aggregates"
|
||||||
|
import type { Article } from "$lib/legal"
|
||||||
|
import { summarizeLegalObject } from "$lib/summaries"
|
||||||
|
|
||||||
|
export let article: Article
|
||||||
|
export let data: Aggregate
|
||||||
|
export let level = 1
|
||||||
|
|
||||||
|
$: summary = summarizeLegalObject({ key: "article" }, "article", article)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if summary !== undefined}
|
||||||
|
<svelte:element this={`h${Math.min(level, 6)}`} class="text-lg font-bold">
|
||||||
|
<SummaryView {summary} />
|
||||||
|
</svelte:element>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{@html article.BLOC_TEXTUEL.CONTENU}
|
20
src/lib/components/IdPagesSwitcher.svelte
Normal file
20
src/lib/components/IdPagesSwitcher.svelte
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { page } from "$app/stores"
|
||||||
|
import { menuItemsFromLegalId } from "$lib/legal"
|
||||||
|
|
||||||
|
export let id: string | undefined | null
|
||||||
|
|
||||||
|
$: items = menuItemsFromLegalId(id)
|
||||||
|
|
||||||
|
$: pathname = $page.url.pathname
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if items !== undefined}
|
||||||
|
<div class="tabs">
|
||||||
|
{#each items as { href, label }}
|
||||||
|
<a class="tab tab-bordered" class:tab-active={href === pathname} {href}
|
||||||
|
>{label}</a
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
|
@ -38,7 +38,17 @@
|
||||||
|
|
||||||
function newPaginationUrl(
|
function newPaginationUrl(
|
||||||
pathname: string,
|
pathname: string,
|
||||||
query: Partial<PaginationQuery> | { [key: string]: string },
|
query:
|
||||||
|
| Partial<PaginationQuery>
|
||||||
|
| {
|
||||||
|
[key: string]:
|
||||||
|
| boolean
|
||||||
|
| number
|
||||||
|
| string
|
||||||
|
| undefined
|
||||||
|
| null
|
||||||
|
| Array<boolean | number | string | undefined | null>
|
||||||
|
},
|
||||||
{ limit, offset }: { limit?: number; offset?: number } = {},
|
{ limit, offset }: { limit?: number; offset?: number } = {},
|
||||||
) {
|
) {
|
||||||
query = { ...query }
|
query = { ...query }
|
||||||
|
@ -53,10 +63,20 @@
|
||||||
delete query.offset
|
delete query.offset
|
||||||
}
|
}
|
||||||
const search = new URLSearchParams(
|
const search = new URLSearchParams(
|
||||||
Object.entries(query).map(([key, value]) => [
|
Object.entries(query).reduce((couples, [key, value]) => {
|
||||||
key,
|
if (value != null) {
|
||||||
typeof value === "number" ? value.toString() : value,
|
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()
|
).toString()
|
||||||
return search ? `${pathname}?${search}` : pathname
|
return search ? `${pathname}?${search}` : pathname
|
||||||
}
|
}
|
||||||
|
|
50
src/lib/components/SectionTaView.svelte
Normal file
50
src/lib/components/SectionTaView.svelte
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { iterArrayOrSingleton } from "@tricoteuses/explorer-tools"
|
||||||
|
import { SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
import type { Aggregate } from "$lib/aggregates"
|
||||||
|
import ArticleView from "$lib/components/ArticleView.svelte"
|
||||||
|
import type { SectionTa } from "$lib/legal"
|
||||||
|
import { summarizeLegalObject } from "$lib/summaries"
|
||||||
|
|
||||||
|
export let data: Aggregate
|
||||||
|
export let level = 1
|
||||||
|
export let sectionTa: SectionTa
|
||||||
|
export let showArticles: boolean
|
||||||
|
|
||||||
|
$: summary = summarizeLegalObject(
|
||||||
|
{ key: "section_ta" },
|
||||||
|
"section_ta",
|
||||||
|
sectionTa,
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:element this={`h${Math.min(level, 6)}`} class="text-1xl font-extrabold">
|
||||||
|
{sectionTa.TITRE_TA}
|
||||||
|
</svelte:element>
|
||||||
|
|
||||||
|
<div class="ml-4">
|
||||||
|
{#if showArticles}
|
||||||
|
{#each [...iterArrayOrSingleton(sectionTa.STRUCTURE_TA.LIEN_ART)] as lienArt}
|
||||||
|
{@const article = data.article?.[lienArt["@id"]]}
|
||||||
|
{#if article !== undefined}
|
||||||
|
<ArticleView {article} {data} level={level + 1} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{:else if sectionTa.STRUCTURE_TA.LIEN_ART !== undefined}
|
||||||
|
<ul class="inline">
|
||||||
|
{#each [...iterArrayOrSingleton(sectionTa.STRUCTURE_TA.LIEN_ART)] as lienArt}
|
||||||
|
<li class="inline after:content-[',_'] after:last:content-['']">
|
||||||
|
Article {lienArt["@num"]}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#each [...iterArrayOrSingleton(sectionTa.STRUCTURE_TA.LIEN_SECTION_TA)] as lienSectionTa}
|
||||||
|
{@const sectionTa = data.section_ta?.[lienSectionTa["@id"]]}
|
||||||
|
{#if sectionTa !== undefined}
|
||||||
|
<svelte:self {data} level={level + 1} {sectionTa} {showArticles} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</div>
|
36
src/lib/components/TexteVersionView.svelte
Normal file
36
src/lib/components/TexteVersionView.svelte
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
import type { Aggregate } from "$lib/aggregates"
|
||||||
|
import TextelrView from "$lib/components/TextelrView.svelte"
|
||||||
|
import type { TexteVersion } from "$lib/legal"
|
||||||
|
import { summarizeLegalObject } from "$lib/summaries"
|
||||||
|
|
||||||
|
export let data: Aggregate
|
||||||
|
export let level = 1
|
||||||
|
export let showArticles: boolean
|
||||||
|
export let texteVersion: TexteVersion
|
||||||
|
|
||||||
|
$: id = texteVersion.META.META_COMMUN.ID
|
||||||
|
|
||||||
|
$: textelr = data.textelr?.[id]
|
||||||
|
|
||||||
|
$: summary = summarizeLegalObject(
|
||||||
|
{ key: "texte_version" },
|
||||||
|
"texte_version",
|
||||||
|
texteVersion,
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if summary !== undefined}
|
||||||
|
<svelte:element
|
||||||
|
this={`h${Math.min(level, 6)}`}
|
||||||
|
class="text-4xl font-extrabold"
|
||||||
|
>
|
||||||
|
<SummaryView {summary} />
|
||||||
|
</svelte:element>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if textelr !== undefined}
|
||||||
|
<TextelrView {data} {level} {showArticles} {textelr} />
|
||||||
|
{/if}
|
37
src/lib/components/TextelrView.svelte
Normal file
37
src/lib/components/TextelrView.svelte
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { iterArrayOrSingleton } from "@tricoteuses/explorer-tools"
|
||||||
|
|
||||||
|
import type { Aggregate } from "$lib/aggregates"
|
||||||
|
import ArticleView from "$lib/components/ArticleView.svelte"
|
||||||
|
import SectionTaView from "$lib/components/SectionTaView.svelte"
|
||||||
|
import type { Textelr } from "$lib/legal"
|
||||||
|
|
||||||
|
export let data: Aggregate
|
||||||
|
export let level = 1
|
||||||
|
export let showArticles: boolean
|
||||||
|
export let textelr: Textelr
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if showArticles}
|
||||||
|
{#each [...iterArrayOrSingleton(textelr.STRUCT.LIEN_ART)] as lienArt}
|
||||||
|
{@const article = data.article?.[lienArt["@id"]]}
|
||||||
|
{#if article !== undefined}
|
||||||
|
<ArticleView {article} {data} level={level + 1} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{:else if textelr.STRUCT.LIEN_ART !== undefined}
|
||||||
|
<ul class="inline">
|
||||||
|
{#each [...iterArrayOrSingleton(textelr.STRUCT.LIEN_ART)] as lienArt}
|
||||||
|
<li class="inline after:content-[',_'] after:last:content-['']">
|
||||||
|
Article {lienArt["@num"]}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#each [...iterArrayOrSingleton(textelr.STRUCT.LIEN_SECTION_TA)] as lienSectionTa}
|
||||||
|
{@const sectionTa = data.section_ta?.[lienSectionTa["@id"]]}
|
||||||
|
{#if sectionTa !== undefined}
|
||||||
|
<SectionTaView {data} level={level + 1} {sectionTa} {showArticles} />
|
||||||
|
{/if}
|
||||||
|
{/each}
|
|
@ -140,6 +140,17 @@ export interface LienArt {
|
||||||
"@origine": "LEGI"
|
"@origine": "LEGI"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LienSectionTa {
|
||||||
|
"@id": string
|
||||||
|
"@cid": string
|
||||||
|
"@fin": string
|
||||||
|
"@niv": string
|
||||||
|
"@url": string
|
||||||
|
"@etat": Etat
|
||||||
|
"@debut": string
|
||||||
|
"#text": string
|
||||||
|
}
|
||||||
|
|
||||||
export interface MetaCommun {
|
export interface MetaCommun {
|
||||||
ID: string
|
ID: string
|
||||||
}
|
}
|
||||||
|
@ -165,6 +176,7 @@ export interface SectionTa {
|
||||||
TITRE_TA: string
|
TITRE_TA: string
|
||||||
STRUCTURE_TA: {
|
STRUCTURE_TA: {
|
||||||
LIEN_ART?: LienArt | LienArt[]
|
LIEN_ART?: LienArt | LienArt[]
|
||||||
|
LIEN_SECTION_TA?: LienSectionTa | LienSectionTa[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,6 +198,7 @@ export interface Textelr {
|
||||||
}
|
}
|
||||||
STRUCT: {
|
STRUCT: {
|
||||||
LIEN_ART?: LienArt | LienArt[]
|
LIEN_ART?: LienArt | LienArt[]
|
||||||
|
LIEN_SECTION_TA?: LienSectionTa | LienSectionTa[]
|
||||||
}
|
}
|
||||||
VERSIONS: {
|
VERSIONS: {
|
||||||
VERSION: TextelrVersion | TextelrVersion[]
|
VERSION: TextelrVersion | TextelrVersion[]
|
||||||
|
@ -293,7 +306,7 @@ export const appMenu: MenuItem[] = [
|
||||||
{
|
{
|
||||||
items: [
|
items: [
|
||||||
{ href: "/idcc", label: "Accords de branche et conventions collectives" },
|
{ 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: "/dossier_legislatif", label: "Dossiers législatifs" },
|
||||||
{ href: "/jo", label: "Journal officiel" },
|
{ href: "/jo", label: "Journal officiel" },
|
||||||
],
|
],
|
||||||
|
@ -355,36 +368,34 @@ export function bestItemForDate<T extends { "@debut": string; "@fin": string }>(
|
||||||
return items[0]
|
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 {
|
export function pathnameFromLegalId(id: string): string | undefined {
|
||||||
if (id.match(/^[A-Z]{4}ARTI/) !== null) {
|
const rootType = rootTypeFromLegalId(id)
|
||||||
return `/article/${id}`
|
if (rootType === undefined) {
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
if (id.match(/^[A-Z]{4}DOLE/) !== null) {
|
return `/${rootType}/${id}`
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pathnameFromLegalObject(
|
export function pathnameFromLegalObject(
|
||||||
|
@ -450,3 +461,28 @@ export function pathnameFromLegalObjectId(
|
||||||
assertNeverLegalObjectType(type)
|
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}"`)
|
||||||
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
import { iterArrayOrSingleton } from "@tricoteuses/explorer-tools"
|
import { iterArrayOrSingleton } from "@tricoteuses/explorer-tools"
|
||||||
|
|
||||||
import type { Follow } from "$lib/aggregates"
|
import type { Aggregate, Follow } from "$lib/aggregates"
|
||||||
import type { Article, Lien } from "$lib/legal"
|
import {
|
||||||
|
rootTypeFromLegalId,
|
||||||
|
type Article,
|
||||||
|
type LegalObjectType,
|
||||||
|
type SectionTa,
|
||||||
|
type Textelr,
|
||||||
|
type TexteVersion,
|
||||||
|
} from "$lib/legal"
|
||||||
import { db } from "$lib/server/database"
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
export interface Aggregate {
|
|
||||||
article?: { [id: string]: Article }
|
|
||||||
id?: string
|
|
||||||
ids?: string[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Aggregator {
|
export class Aggregator {
|
||||||
article: { [id: string]: Article } = {}
|
article: { [id: string]: Article } = {}
|
||||||
follow: Set<Follow>
|
follow: Set<Follow>
|
||||||
requestedIds: Set<string> = new Set()
|
requestedTypeAndIds: Set<TypeAndId> = new Set()
|
||||||
visitedIds: Set<string> = new Set()
|
section_ta: { [id: string]: SectionTa } = {}
|
||||||
|
texte_version: { [id: string]: TexteVersion } = {}
|
||||||
|
textelr: { [id: string]: Textelr } = {}
|
||||||
|
visitedTypeAndIds: Set<TypeAndId> = new Set()
|
||||||
|
|
||||||
constructor(follow: Iterable<Follow>) {
|
constructor(follow: Iterable<Follow>) {
|
||||||
this.follow = new Set(follow)
|
this.follow = new Set(follow)
|
||||||
|
@ -33,46 +37,135 @@ export class Aggregator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addToVisitedIds(ids: string[]) {
|
addSectionTa(sectionTa: SectionTa): void {
|
||||||
for (const id of ids) {
|
const id = sectionTa.ID
|
||||||
this.visitedIds.add(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[]) {
|
addTextelr(textelr: Textelr): void {
|
||||||
for (const id of ids) {
|
const id = textelr.META.META_COMMUN.ID
|
||||||
this.requestedIds.delete(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<void> {
|
async getAll(): Promise<void> {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (this.requestedIds.size === 0) {
|
if (this.requestedTypeAndIds.size === 0) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
console.log("this.requestedIds.size", this.requestedIds.size)
|
console.log(
|
||||||
|
"this.requestedTypeAndIds.size",
|
||||||
|
this.requestedTypeAndIds.size,
|
||||||
|
)
|
||||||
|
|
||||||
{
|
{
|
||||||
const articleIds = [...this.requestedIds].filter(
|
const articleTypeAndIds = [...this.requestedTypeAndIds].filter(
|
||||||
(id) => id.match(/^[A-Z]{4}ARTI/) !== null,
|
([type]) => type === "article",
|
||||||
)
|
)
|
||||||
if (articleIds.length > 0) {
|
if (articleTypeAndIds.length > 0) {
|
||||||
this.deleteFromRequestedIds(articleIds)
|
this.deleteFromRequestedTypeAndIds(articleTypeAndIds)
|
||||||
for (const { data } of await db<{ id: string; data: Article }[]>`
|
for (const { data } of await db<{ id: string; data: Article }[]>`
|
||||||
SELECT id, data FROM article
|
SELECT id, data FROM article
|
||||||
WHERE id IN ${db(articleIds)}
|
WHERE id IN ${db(articleTypeAndIds.map(([, id]) => id))}
|
||||||
`) {
|
`) {
|
||||||
this.addArticle(data)
|
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 {
|
requestId(id: string): void {
|
||||||
if (!this.visitedIds.has(id)) {
|
const rootType = rootTypeFromLegalId(id)
|
||||||
this.requestedIds.add(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) {
|
if (Object.keys(this.article).length > 0) {
|
||||||
json.article = this.article
|
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
|
return json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TypeAndId = [LegalObjectType, string]
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { type Audit, auditSetNullish, cleanAudit } from "@auditors/core"
|
import { type Audit, auditSetNullish, cleanAudit } from "@auditors/core"
|
||||||
import { error } from "@sveltejs/kit"
|
import { error } from "@sveltejs/kit"
|
||||||
|
|
||||||
import type { Follow } from "$lib/aggregates"
|
import type { Aggregate, Follow } from "$lib/aggregates"
|
||||||
import {
|
import {
|
||||||
auditFollowSearchParams,
|
auditFollowSearchParams,
|
||||||
auditQSearchParam,
|
auditQSearchParam,
|
||||||
} from "$lib/auditors/search_params"
|
} from "$lib/auditors/search_params"
|
||||||
import type { Article } from "$lib/legal"
|
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"
|
import { db } from "$lib/server/database"
|
||||||
|
|
||||||
export function auditSearchParams(
|
export function auditSearchParams(
|
||||||
|
@ -41,15 +41,15 @@ export function auditSearchParams(
|
||||||
export const doGetRecherche = async (
|
export const doGetRecherche = async (
|
||||||
url: URL,
|
url: URL,
|
||||||
): Promise<
|
): Promise<
|
||||||
| (Aggregate & {
|
Aggregate & {
|
||||||
q: string
|
follow: Follow[]
|
||||||
})
|
q?: string
|
||||||
| null
|
}
|
||||||
> => {
|
> => {
|
||||||
const [query, queryError] = auditSearchParams(
|
const [query, queryError] = auditSearchParams(
|
||||||
cleanAudit,
|
cleanAudit,
|
||||||
url.searchParams,
|
url.searchParams,
|
||||||
) as [{ follow: Follow[]; q?: string }, unknown]
|
) as [{ follow: Set<Follow>; q?: string }, unknown]
|
||||||
if (queryError !== null) {
|
if (queryError !== null) {
|
||||||
console.error(
|
console.error(
|
||||||
`Error in ${url.pathname} query:\n${JSON.stringify(
|
`Error in ${url.pathname} query:\n${JSON.stringify(
|
||||||
|
@ -62,6 +62,8 @@ export const doGetRecherche = async (
|
||||||
}
|
}
|
||||||
const { follow, q } = query
|
const { follow, q } = query
|
||||||
|
|
||||||
|
const aggregator = new Aggregator(follow)
|
||||||
|
let id: string | undefined = undefined
|
||||||
if (q !== undefined) {
|
if (q !== undefined) {
|
||||||
// https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006308296/
|
// https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006308296/
|
||||||
// https://www.legifrance.gouv.fr/codes/article_lc/LEGIARTI000006308296/1983-12-30/
|
// 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
|
||||||
// https://www.legifrance.gouv.fr/loda/article_lc/LEGIARTI000036456533/2018-01-01
|
// https://www.legifrance.gouv.fr/loda/article_lc/LEGIARTI000036456533/2018-01-01
|
||||||
// https://www.legifrance.gouv.fr/loda/id/LEGIARTI000006317314/1983-12-30
|
// https://www.legifrance.gouv.fr/loda/id/LEGIARTI000006317314/1983-12-30
|
||||||
const articleId = q.match(/LEGIARTI\d+/)?.[0]
|
id = q.match(/LEGIARTI\d+/)?.[0]
|
||||||
if (articleId != null) {
|
if (id != null) {
|
||||||
const article = (
|
const article = (
|
||||||
await db<{ data: Article }[]>`
|
await db<{ data: Article }[]>`
|
||||||
SELECT data FROM article
|
SELECT data FROM article
|
||||||
WHERE id = ${articleId}
|
WHERE id = ${id}
|
||||||
LIMIT 1
|
|
||||||
`
|
`
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
||||||
if (article !== undefined) {
|
if (article !== undefined) {
|
||||||
const aggregator = new Aggregator(follow)
|
|
||||||
aggregator.addArticle(article)
|
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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
178
src/lib/server/doers/textes.ts
Normal file
178
src/lib/server/doers/textes.ts
Normal file
|
@ -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<Follow>
|
||||||
|
},
|
||||||
|
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<Follow>
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import {
|
||||||
type LegalObjectType,
|
type LegalObjectType,
|
||||||
type Lien,
|
type Lien,
|
||||||
type LienArt,
|
type LienArt,
|
||||||
|
type LienSectionTa,
|
||||||
pathnameFromLegalId,
|
pathnameFromLegalId,
|
||||||
pathnameFromLegalObject,
|
pathnameFromLegalObject,
|
||||||
pathnameFromLegalObjectId,
|
pathnameFromLegalObjectId,
|
||||||
|
@ -261,7 +262,7 @@ export function summarizeLegalObject(
|
||||||
]
|
]
|
||||||
return {
|
return {
|
||||||
items: [
|
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"
|
...(metaArticle.DATE_FIN === "2999-01-01"
|
||||||
? ([
|
? ([
|
||||||
" depuis le ",
|
" depuis le ",
|
||||||
|
@ -373,7 +374,7 @@ export const summarizeLienArt: Summarizer = (access, value) => {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
content: `Article n° ${lienArt["@num"]}`,
|
content: `Article ${lienArt["@num"]}`,
|
||||||
href: pathnameFromLegalObjectId("article", lienArt["@id"]),
|
href: pathnameFromLegalObjectId("article", lienArt["@id"]),
|
||||||
type: "link",
|
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) => {
|
export const summarizeSectionTaProperties: Summarizer = (access, value) => {
|
||||||
if (access?.key === "section_ta" && typeof value !== "number") {
|
if (access?.key === "section_ta" && typeof value !== "number") {
|
||||||
return summarizeLegalObject(access, "section_ta", value)
|
return summarizeLegalObject(access, "section_ta", value)
|
||||||
|
@ -434,6 +465,14 @@ export const summarizeSectionTaProperties: Summarizer = (access, value) => {
|
||||||
if (access?.key === "@cid" && access?.access?.key === "TEXTE") {
|
if (access?.key === "@cid" && access?.access?.key === "TEXTE") {
|
||||||
return summarizeLegalIdToLink(access, value)
|
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 (
|
if (
|
||||||
access?.key === "@id" &&
|
access?.key === "@id" &&
|
||||||
(access?.access?.key === "LIEN_ART" ||
|
(access?.access?.key === "LIEN_ART" ||
|
||||||
|
@ -442,12 +481,27 @@ export const summarizeSectionTaProperties: Summarizer = (access, value) => {
|
||||||
) {
|
) {
|
||||||
return summarizeLienArtId(access.access, access.parent)
|
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 (
|
if (
|
||||||
(access?.key === "LIEN_ART" && !Array.isArray(value)) ||
|
(access?.key === "LIEN_ART" && !Array.isArray(value)) ||
|
||||||
(typeof access?.key === "number" && access?.access?.key === "LIEN_ART")
|
(typeof access?.key === "number" && access?.access?.key === "LIEN_ART")
|
||||||
) {
|
) {
|
||||||
return summarizeLienArt(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)
|
||||||
|
}
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,6 +544,14 @@ export const summarizeTextelrProperties: Summarizer = (access, value) => {
|
||||||
return summarizeLegalObjectToLink(access, "textelr", 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 (
|
if (
|
||||||
access?.key === "@id" &&
|
access?.key === "@id" &&
|
||||||
(access?.access?.key === "LIEN_ART" ||
|
(access?.access?.key === "LIEN_ART" ||
|
||||||
|
@ -498,6 +560,14 @@ export const summarizeTextelrProperties: Summarizer = (access, value) => {
|
||||||
) {
|
) {
|
||||||
return summarizeLienArtId(access.access, access.parent)
|
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") {
|
if (access?.key === "CID") {
|
||||||
return summarizeLegalIdToLink(access, value)
|
return summarizeLegalIdToLink(access, value)
|
||||||
}
|
}
|
||||||
|
@ -507,6 +577,13 @@ export const summarizeTextelrProperties: Summarizer = (access, value) => {
|
||||||
) {
|
) {
|
||||||
return summarizeLienArt(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") {
|
if (access?.key === "LIEN_TXT") {
|
||||||
return summarizeTextelrVersionLienTxt(access, value)
|
return summarizeTextelrVersionLienTxt(access, value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,9 @@ import type { RequestHandler } from "./$types"
|
||||||
|
|
||||||
export const GET: RequestHandler = async ({ url }) => {
|
export const GET: RequestHandler = async ({ url }) => {
|
||||||
const result = await doGetRecherche(url)
|
const result = await doGetRecherche(url)
|
||||||
return result === null
|
return new Response(JSON.stringify(result, null, 2), {
|
||||||
? new Response(null, { status: 204 })
|
headers: {
|
||||||
: new Response(JSON.stringify(result, null, 2), {
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
headers: {
|
},
|
||||||
"Content-Type": "application/json; charset=utf-8",
|
})
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
12
src/routes/api/textes/+server.ts
Normal file
12
src/routes/api/textes/+server.ts
Normal file
|
@ -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",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
12
src/routes/api/textes/[id]/+server.ts
Normal file
12
src/routes/api/textes/[id]/+server.ts
Normal file
|
@ -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",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
||||||
|
|
||||||
if (sectionTa === undefined) {
|
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 }
|
return { section_ta: sectionTa }
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
||||||
|
|
||||||
if (texteVersion === undefined) {
|
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 }
|
return { texte_version: texteVersion }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { TreeView, SummaryView } from "augmented-data-viewer"
|
import { TreeView, SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
import IdPagesSwitcher from "$lib/components/IdPagesSwitcher.svelte"
|
||||||
import {
|
import {
|
||||||
summarizeTexteVersionProperties,
|
summarizeTexteVersionProperties,
|
||||||
summarizeLegalObject,
|
summarizeLegalObject,
|
||||||
|
@ -19,6 +20,8 @@
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<IdPagesSwitcher id={texteVersion.META.META_COMMUN.ID} />
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
<h2>TEXTE_VERSION</h2>
|
<h2>TEXTE_VERSION</h2>
|
||||||
{#if summary !== undefined}
|
{#if summary !== undefined}
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
||||||
|
|
||||||
if (textekali === undefined) {
|
if (textekali === undefined) {
|
||||||
throw error(404, `Texte KALI ${params.id} non trouvé`)
|
throw error(404, `TEXTEKALI ${params.id} non trouvé`)
|
||||||
}
|
}
|
||||||
return { textekali }
|
return { textekali }
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params }) => {
|
||||||
).map(({ data }) => data)[0]
|
).map(({ data }) => data)[0]
|
||||||
|
|
||||||
if (textelr === undefined) {
|
if (textelr === undefined) {
|
||||||
throw error(404, `Texte LR ${params.id} non trouvé`)
|
throw error(404, `TEXTELR ${params.id} non trouvé`)
|
||||||
}
|
}
|
||||||
return { textelr: textelr }
|
return { textelr: textelr }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { TreeView, SummaryView } from "augmented-data-viewer"
|
import { TreeView, SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
import IdPagesSwitcher from "$lib/components/IdPagesSwitcher.svelte"
|
||||||
import {
|
import {
|
||||||
summarizeTextelrProperties,
|
summarizeTextelrProperties,
|
||||||
summarizeLegalObject,
|
summarizeLegalObject,
|
||||||
|
@ -15,6 +16,8 @@
|
||||||
$: summary = summarizeLegalObject({ key: "textelr" }, "textelr", textelr)
|
$: summary = summarizeLegalObject({ key: "textelr" }, "textelr", textelr)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<IdPagesSwitcher id={textelr.META.META_COMMUN.ID} />
|
||||||
|
|
||||||
<header class="prose my-6 max-w-full">
|
<header class="prose my-6 max-w-full">
|
||||||
<h2>TEXTELR</h2>
|
<h2>TEXTELR</h2>
|
||||||
{#if summary !== undefined}
|
{#if summary !== undefined}
|
||||||
|
|
7
src/routes/textes/+page.server.ts
Normal file
7
src/routes/textes/+page.server.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { doListTextes } from "$lib/server/doers/textes"
|
||||||
|
|
||||||
|
import type { PageServerLoad } from "./$types"
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ url }) => {
|
||||||
|
return (await doListTextes(url)) ?? {}
|
||||||
|
}
|
69
src/routes/textes/+page.svelte
Normal file
69
src/routes/textes/+page.svelte
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<script lang="ts">
|
||||||
|
// import Icon from "@iconify/svelte"
|
||||||
|
// import searchIcon from "@iconify-icons/codicon/search"
|
||||||
|
import { TreeView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
// import { page } from "$app/stores"
|
||||||
|
import Pagination from "$lib/components/Pagination.svelte"
|
||||||
|
import type { Article, SectionTa, Textelr, TexteVersion } from "$lib/legal"
|
||||||
|
import { summarizeTexteVersionProperties } from "$lib/summaries"
|
||||||
|
|
||||||
|
import type { PageData } from "./$types"
|
||||||
|
|
||||||
|
export let data: PageData
|
||||||
|
|
||||||
|
const articleById = data.article as { [id: string]: Article }
|
||||||
|
const sectionTaById = data.sectionTa as { [id: string]: SectionTa }
|
||||||
|
const texteVersionById = data.texte_version as { [id: string]: TexteVersion }
|
||||||
|
const texteVersionArray = (data.ids as string[]).map(
|
||||||
|
(id) => texteVersionById[id],
|
||||||
|
)
|
||||||
|
const textelrById = data.textelr as { [id: string]: Textelr[] }
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<header class="prose my-6 max-w-full">
|
||||||
|
<h1>Codes, lois et règlements</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- <form action={$page.url.pathname} class="mx-auto max-w-sm" method="get">
|
||||||
|
<div class="form-control">
|
||||||
|
<div class="input-group">
|
||||||
|
<input
|
||||||
|
class="input input-bordered"
|
||||||
|
name="q"
|
||||||
|
type="search"
|
||||||
|
bind:value={q}
|
||||||
|
/>
|
||||||
|
<button class="btn btn-square" type="submit">
|
||||||
|
<Icon icon={searchIcon} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text">Législature</span>
|
||||||
|
<select
|
||||||
|
class="select select-bordered"
|
||||||
|
name="legislature"
|
||||||
|
bind:value={legislature}
|
||||||
|
>
|
||||||
|
<option value="">Toutes</option>
|
||||||
|
{#each Object.entries(Legislature) as [key, value]}
|
||||||
|
{#if value !== "*"}
|
||||||
|
<option {value}>{key}</option>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</form> -->
|
||||||
|
|
||||||
|
<TreeView
|
||||||
|
access={{ key: "texte_version" }}
|
||||||
|
frame={false}
|
||||||
|
open
|
||||||
|
summarize={summarizeTexteVersionProperties}
|
||||||
|
value={texteVersionArray}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Pagination currentPageCount={texteVersionArray.length} />
|
7
src/routes/textes/[id]/+page.server.ts
Normal file
7
src/routes/textes/[id]/+page.server.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { doGetTexte } from "$lib/server/doers/textes"
|
||||||
|
|
||||||
|
import type { PageServerLoad } from "./$types"
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async ({ params, url }) => {
|
||||||
|
return (await doGetTexte(params.id, url)) ?? {}
|
||||||
|
}
|
55
src/routes/textes/[id]/+page.svelte
Normal file
55
src/routes/textes/[id]/+page.svelte
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { TreeView, SummaryView } from "augmented-data-viewer"
|
||||||
|
|
||||||
|
import IdPagesSwitcher from "$lib/components/IdPagesSwitcher.svelte"
|
||||||
|
import TexteVersionView from "$lib/components/TexteVersionView.svelte"
|
||||||
|
import { summarizeLegalObject } from "$lib/summaries"
|
||||||
|
|
||||||
|
import type { PageData } from "./$types"
|
||||||
|
|
||||||
|
export let data: PageData
|
||||||
|
|
||||||
|
const id = data.id!
|
||||||
|
const texteVersion = data.texte_version![id]
|
||||||
|
|
||||||
|
let showArticles = false
|
||||||
|
let showRawData = false
|
||||||
|
|
||||||
|
$: summary = summarizeLegalObject(
|
||||||
|
{ key: "texte_version" },
|
||||||
|
"texte_version",
|
||||||
|
texteVersion,
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<IdPagesSwitcher {id} />
|
||||||
|
|
||||||
|
<header class="prose my-6 max-w-full">
|
||||||
|
<h2>Codes, lois et règlements</h2>
|
||||||
|
{#if summary !== undefined}
|
||||||
|
<h1>
|
||||||
|
<SummaryView {summary} />
|
||||||
|
</h1>
|
||||||
|
{/if}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<form class="max-w-xs" on:submit|preventDefault>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label cursor-pointer">
|
||||||
|
<span class="label-text">Données brutes</span>
|
||||||
|
<input class="toggle" type="checkbox" bind:checked={showRawData} />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="label cursor-pointer">
|
||||||
|
<span class="label-text">Montrer les articles</span>
|
||||||
|
<input class="toggle" type="checkbox" bind:checked={showArticles} />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{#if showRawData}
|
||||||
|
<TreeView frame={false} open value={data} />
|
||||||
|
{:else}
|
||||||
|
<TexteVersionView {data} {showArticles} {texteVersion} />
|
||||||
|
{/if}
|
Loading…
Reference in a new issue