refactor(form-schema): inline validators to remove @core transitive dep

Resolves TECH-07. Copies the four validators actually used
(requiredValidator, emailValidator, urlValidator, regexValidator) from
@core/utils/validators into packages/form-schema/src/utils/validators.ts
as pure boolean functions. Vuexy template copies in apps/*/src/@core/
remain for non-form UI use. Package is now genuinely standalone —
grep -rn "@core/" packages/form-schema/ returns zero matches.

Also corrects two documentation inconsistencies from commit 42dd626e:
dev-guide heading translated to Dutch for style consistency, and the
BACKLOG entry renumbered from TECH-DEBT-01 to TECH-07 to match the
flat numbering in the Technische schuld section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 00:20:15 +02:00
parent 42dd626e37
commit 214a2debee
4 changed files with 60 additions and 18 deletions

View File

@@ -489,22 +489,6 @@ apps/portal om drift te voorkomen.
--- ---
### TECH-DEBT-01 — @form-schema transitive dep op @core/utils/validators
**Aanleiding:** `packages/form-schema/src/utils/formValidation.ts`
importeert uit `@core/utils/validators`, dat per-app resolvt naar
`apps/*/src/@core/utils/validators.ts`. Beide app-kopieën zijn op dit
moment identiek (Vuexy template-code), maar drift tussen de twee
zou `@form-schema` per consumer verschillend laten werken.
**Wat:** Kopieer de specifieke validators die `formValidation.ts`
gebruikt naar `packages/form-schema/src/utils/` zodra het package
een tweede echte consumer krijgt (PR-c of later). Ontdekt tijdens
PR-a (commit dda60ed5).
**Prioriteit:** Laag — latent; triggert pas bij consumer-drift of
wanneer het package buiten de huidige Vuexy-twin apps wordt geladen.
---
### ~~TECH-02 — scopeForFestival helper op Event model~~ ✅ OPGELOST ### ~~TECH-02 — scopeForFestival helper op Event model~~ ✅ OPGELOST
--- ---
@@ -517,6 +501,10 @@ wanneer het package buiten de huidige Vuexy-twin apps wordt geladen.
--- ---
### ~~TECH-07 — @form-schema transitive dep op @core/utils/validators~~ ✅ OPGELOST — resolved in PR-a1
---
## Opgeloste items (april 2026) ## Opgeloste items (april 2026)
De volgende items zijn geïmplementeerd en afgerond (673+ tests): De volgende items zijn geïmplementeerd en afgerond (673+ tests):

View File

@@ -381,7 +381,7 @@ Altijd in deze volgorde. Nooit stappen overslaan — later toevoegen kost meer t
| Fase 3 — Advancing & Show Day | Artist advancing + portaal, Timetable, Mission Control, Formulierbouwer, Post-festival evaluatie, PDF allocatiesheet, Campagnes (email + WhatsApp via Zender) | | Fase 3 — Advancing & Show Day | Artist advancing + portaal, Timetable, Mission Control, Formulierbouwer, Post-festival evaluatie, PDF allocatiesheet, Campagnes (email + WhatsApp via Zender) |
| Fase 4 — Differentiators | Real-time WebSockets, Show Day Mode, Vrijwilligersprofiel + festival-paspoort, Shift swap & wachtlijst, Retrospectief rapport, Leveranciersportaal uitgebreid | | Fase 4 — Differentiators | Real-time WebSockets, Show Day Mode, Vrijwilligersprofiel + festival-paspoort, Shift swap & wachtlijst, Retrospectief rapport, Leveranciersportaal uitgebreid |
## Shared frontend packages ## Gedeelde frontend packages
`apps/portal/` en `apps/app/` delen een klein aantal schema-gedreven modules. Deze sectie legt vast wat wel en niet in die gedeelde laag hoort, en hoe je de aliases opzet. `apps/portal/` en `apps/app/` delen een klein aantal schema-gedreven modules. Deze sectie legt vast wat wel en niet in die gedeelde laag hoort, en hoe je de aliases opzet.

View File

@@ -1,4 +1,4 @@
import { emailValidator, regexValidator, requiredValidator, urlValidator } from '@core/utils/validators' import { emailValidator, regexValidator, requiredValidator, urlValidator } from './validators'
import { FormFieldType } from '../types/formBuilder' import { FormFieldType } from '../types/formBuilder'
import type { PublicFormField } from '../types/formBuilder' import type { PublicFormField } from '../types/formBuilder'

View File

@@ -0,0 +1,54 @@
// Pure boolean validators used as gates by formValidation.ts. Error
// messages (in Dutch) are produced by the caller, not by these validators.
// This file deliberately has no external imports — the package must be
// standalone and free of cross-app coupling.
function isNullOrUndefined(value: unknown): boolean {
return value === null || value === undefined
}
function isEmptyArray(value: unknown): boolean {
return Array.isArray(value) && value.length === 0
}
function isEmpty(value: unknown): boolean {
if (isNullOrUndefined(value)) return true
if (typeof value === 'string') return value.trim() === ''
if (Array.isArray(value)) return value.length === 0
return false
}
export function requiredValidator(value: unknown): boolean {
if (isNullOrUndefined(value) || isEmptyArray(value) || value === false) return false
return String(value).trim().length > 0
}
export function emailValidator(value: unknown): boolean {
if (isEmpty(value)) return true
const re = /^(?:[^<>()[\]\\.,;:\s@"]+(?:\.[^<>()[\]\\.,;:\s@"]+)*|".+")@(?:\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\]|(?:[a-z\-\d]+\.)+[a-z]{2,})$/i
if (Array.isArray(value)) return value.every(val => re.test(String(val)))
return re.test(String(value))
}
export function urlValidator(value: unknown): boolean {
if (isEmpty(value)) return true
const re = /^https?:\/\/[^\s$.?#].\S*$/
return re.test(String(value))
}
export function regexValidator(value: unknown, regex: RegExp | string): boolean {
if (isEmpty(value)) return true
const regEx = typeof regex === 'string' ? new RegExp(regex) : regex
if (Array.isArray(value)) return value.every(val => regexValidator(val, regEx))
return regEx.test(String(value))
}