Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 15 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"devDependencies": {
"@commitlint/cli": "^18.2.0",
"@commitlint/config-conventional": "^18.1.0",
"@koumoul/vjsf-compiler": "^1.0.0",
"@koumoul/vjsf-compiler": "^1.5.0",
"@types/cookie": "^0.6.0",
"@types/debug": "^4.1.10",
"@types/eslint": "^9.6.1",
Expand Down
56 changes: 34 additions & 22 deletions packages/types-builder/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ const main = async (dir: string, options: TypesBuilderOptions) => {
let importsCode = '/* eslint-disable */\n\n'
let code = ''
let dtsCode = ''
// serialized compiled layouts produced by the vjsf export (keyed by locale), so the
// compiledLayout export can reuse them instead of compiling+serializing a second time
const builtVjsfLayoutCodes: Record<string, string> = {}
if (existsSync(path.join(dir, '.type'))) rmSync(path.join(dir, '.type'), { recursive: true })
mkdirSync(path.join(dir, '.type'))

Expand Down Expand Up @@ -282,7 +285,7 @@ export declare function returnValid(data: any, options?: import('${validationImp
let compName = key

const vjsfDir = path.resolve(options.vjsfDir)
const compileVjsf = (await import('@koumoul/vjsf-compiler')).compile
const { compileParts } = await import('@koumoul/vjsf-compiler')
const { resolveXI18n } = await import('@json-layout/core')

for (const locale of vjsfLocales) {
Expand All @@ -301,7 +304,8 @@ export declare function returnValid(data: any, options?: import('${validationImp
if (schema.$id) delete otherSchemas[schema.$id]
schemaVjsfOpts.ajvOptions = { schemas: otherSchemas }

const vjsfCode = await compileVjsf(schema, { locale, ...schemaVjsfOpts })
const { code: vjsfCode, compiledLayoutCode } = await compileParts(schema, { locale, ...schemaVjsfOpts })
builtVjsfLayoutCodes[locale] = compiledLayoutCode
const vjsfFilePath = path.join(vjsfDir, vjsfLocales.length > 1 ? `vjsf-${compName}-${locale}.vue` : `vjsf-${compName}.vue`)
console.log(` vjsf ${locale} component path : ${vjsfFilePath}`)
writeFileSync(vjsfFilePath, vjsfCode)
Expand Down Expand Up @@ -359,27 +363,35 @@ const emit = defineEmits(emits)
const { resolveXI18n } = await import('@json-layout/core')

for (const locale of vjsfLocales) {
const schemaVjsfOpts = { ...schema['x-vjsf'] }
delete schemaVjsfOpts.compName
console.log(` compiledLayout ${locale} options: ${JSON.stringify(schemaVjsfOpts)}`)
const otherSchemas = { ...schemas }
for (const [key, otherSchema] of Object.entries(schemas)) {
if (key === schema.$id) continue
otherSchemas[key] = clone(otherSchema)
resolveXI18n(otherSchemas[key], locale)
}
if (schema.$id) delete otherSchemas[schema.$id]
schemaVjsfOpts.ajvOptions = { schemas: otherSchemas }

const fullOptions = { pluginsImports: [] as string[], webmcp: false, locale, ...schemaVjsfOpts }
for (const pluginImport of fullOptions.pluginsImports) {
const componentInfo = (await import(pluginImport + '/info.js')).default
fullOptions.components = fullOptions.components ?? {}
fullOptions.components[componentInfo.name] = componentInfo
}
// reuse the layout already compiled+serialized by the vjsf export when present
// (the vjsf compiler embeds the very same serialized compiled layout), otherwise
// compile it now
let compiledLayoutCode = builtVjsfLayoutCodes[locale]
if (compiledLayoutCode) {
console.log(` compiledLayout ${locale}: reusing the layout compiled for the vjsf export`)
} else {
const schemaVjsfOpts = { ...schema['x-vjsf'] }
delete schemaVjsfOpts.compName
console.log(` compiledLayout ${locale} options: ${JSON.stringify(schemaVjsfOpts)}`)
const otherSchemas = { ...schemas }
for (const [key, otherSchema] of Object.entries(schemas)) {
if (key === schema.$id) continue
otherSchemas[key] = clone(otherSchema)
resolveXI18n(otherSchemas[key], locale)
}
if (schema.$id) delete otherSchemas[schema.$id]
schemaVjsfOpts.ajvOptions = { schemas: otherSchemas }

const compiledLayout = compileLayout(schema, fullOptions)
let compiledLayoutCode = await serializeCompiledLayout(compiledLayout)
const fullOptions = { pluginsImports: [] as string[], webmcp: false, locale, ...schemaVjsfOpts }
for (const pluginImport of fullOptions.pluginsImports) {
const componentInfo = (await import(pluginImport + '/info.js')).default
fullOptions.components = fullOptions.components ?? {}
fullOptions.components[componentInfo.name] = componentInfo
}

const compiledLayout = compileLayout(schema, fullOptions)
compiledLayoutCode = await serializeCompiledLayout(compiledLayout)
}
// The serialized code declares `const compiledLayout = {...}`.
// Make it an export.
compiledLayoutCode = compiledLayoutCode.replace('const compiledLayout =', 'export const compiledLayout =')
Expand Down
2 changes: 1 addition & 1 deletion packages/types-builder/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"build": "cd .. && npm run build"
},
"peerDependencies": {
"@koumoul/vjsf-compiler": "1"
"@koumoul/vjsf-compiler": "^1.5.0"
},
"peerDependenciesMeta": {
"@koumoul/vjsf-compiler": {
Expand Down
13 changes: 13 additions & 0 deletions packages/types-builder/test/build.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, it } from 'node:test'
import { strict as assert } from 'assert'
import { readFileSync } from 'node:fs'
import * as simpleObject from './types/simple-object/index.js'
import * as objectWithReference from './types/object-with-reference/index.js'

Expand Down Expand Up @@ -34,4 +35,16 @@ describe('build.js script', () => {
}
})
})

it('should reuse the vjsf layout for the compiledLayout export', async () => {
// site-patch exports both vjsf and compiledLayout: the compiledLayout export reuses the
// layout already compiled+serialized for the vjsf component, so both must stay in sync
const compiledLayoutCode = readFileSync(import.meta.dirname + '/types/site-patch/.type/compiled-layout-fr.js', 'utf8')
.replace('/* eslint-disable */\n// @ts-nocheck\n\n', '')
.replace('export const compiledLayout =', 'const compiledLayout =')
const vjsfCode = readFileSync(import.meta.dirname + '/vjsf/vjsf-site-patch.vue', 'utf8')

assert.ok(compiledLayoutCode.includes('const compiledLayout ='))
assert.ok(vjsfCode.includes(compiledLayoutCode), 'the compiledLayout export should be the very layout embedded in the vjsf component')
})
})
2 changes: 1 addition & 1 deletion packages/types-builder/test/types/site-patch/schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$id": "https://github.com/data-fair/simple-directory/site-patch",
"x-exports": ["types", "validate", "resolvedSchema", "vjsf"],
"x-exports": ["types", "validate", "resolvedSchema", "vjsf", "compiledLayout"],
"title": "site-patch",
"type":"object",
"additionalProperties":false,
Expand Down
33 changes: 12 additions & 21 deletions packages/types-builder/test/vjsf/vjsf-site-patch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ return errors === 0;
validate27.evaluated = {"dynamicProps":true,"dynamicItems":false};

const schema40 = {"$id":"export2","$ref":"https://github.com/data-fair/simple-directory/site-patch#"};
const schema41 = {"$id":"https://github.com/data-fair/simple-directory/site-patch","x-exports":["types","validate","resolvedSchema","vjsf"],"title":"site-patch","type":"object","additionalProperties":false,"required":["_id","authMode"],"properties":{"_id":{"readOnly":true,"$ref":"https://github.com/data-fair/simple-directory/site#/properties/_id","__pointer":"https://github.com/data-fair/simple-directory/site-patch#/properties/_id","errorMessage":{}},"authMode":{"$ref":"https://github.com/data-fair/simple-directory/site#/properties/authMode","__pointer":"https://github.com/data-fair/simple-directory/site-patch#/properties/authMode","errorMessage":{"oneOf":"choisissez une valeur"}},"authProviders":{"$ref":"https://github.com/data-fair/simple-directory/site#/properties/authProviders","__pointer":"https://github.com/data-fair/simple-directory/site-patch#/properties/authProviders","errorMessage":{}}},"__pointer":"https://github.com/data-fair/simple-directory/site-patch#","errorMessage":{"required":{"_id":"information obligatoire","authMode":"information obligatoire"}}};
const schema41 = {"$id":"https://github.com/data-fair/simple-directory/site-patch","x-exports":["types","validate","resolvedSchema","vjsf","compiledLayout"],"title":"site-patch","type":"object","additionalProperties":false,"required":["_id","authMode"],"properties":{"_id":{"readOnly":true,"$ref":"https://github.com/data-fair/simple-directory/site#/properties/_id","__pointer":"https://github.com/data-fair/simple-directory/site-patch#/properties/_id","errorMessage":{}},"authMode":{"$ref":"https://github.com/data-fair/simple-directory/site#/properties/authMode","__pointer":"https://github.com/data-fair/simple-directory/site-patch#/properties/authMode","errorMessage":{"oneOf":"choisissez une valeur"}},"authProviders":{"$ref":"https://github.com/data-fair/simple-directory/site#/properties/authProviders","__pointer":"https://github.com/data-fair/simple-directory/site-patch#/properties/authProviders","errorMessage":{}}},"__pointer":"https://github.com/data-fair/simple-directory/site-patch#","errorMessage":{"required":{"_id":"information obligatoire","authMode":"information obligatoire"}}};
const schema42 = {"type":"string","__pointer":"https://github.com/data-fair/simple-directory/site#/properties/_id","errorMessage":{}};
const schema43 = {"default":"onlyBackOffice","title":"Mode d'authentification","type":"string","oneOf":[{"const":"onlyLocal","title":"uniquement sur le site lui même"},{"const":"onlyBackOffice","title":"uniquement sur le back-office"},{"const":"ssoBackOffice","title":"sur le site et sur le back-office par SSO"}],"__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authMode","errorMessage":{"oneOf":"choisissez une valeur"}};
const schema44 = {"type":"array","title":"Fournisseurs d'identité (SSO)","items":{"type":"object","required":["title","type"],"properties":{"title":{"type":"string","title":"Nom","__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/properties/title","errorMessage":{}},"color":{"type":"string","title":"Couleur","x-display":"color-picket","__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/properties/color","errorMessage":{}},"img":{"type":"string","title":"Lien vers logo (petite taille)","__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/properties/img","errorMessage":{}}},"oneOf":[{"type":"object","title":"OpenID Connect","required":["discovery","client"],"properties":{"type":{"type":"string","title":"Type de founisseur","const":"oidc","__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/oneOf/0/properties/type","errorMessage":{}},"discovery":{"type":"string","title":"URL de découverte OICD","description":"probablement de la forme http://mon-fournisseur/.well-known/openid-configuration","__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/oneOf/0/properties/discovery","errorMessage":{}},"client":{"type":"object","required":["id","secret"],"properties":{"id":{"type":"string","title":"Identifiant du client","__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/oneOf/0/properties/client/properties/id","errorMessage":{}},"secret":{"type":"string","title":"Secret","x-display":"textarea","writeOnly":true,"__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/oneOf/0/properties/client/properties/secret","errorMessage":{}}},"__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/oneOf/0/properties/client","errorMessage":{"required":{"id":"information obligatoire","secret":"information obligatoire"}}}},"__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items/oneOf/0","errorMessage":{"required":{"discovery":"information obligatoire","client":"information obligatoire"}}}],"__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders/items","errorMessage":{"oneOf":"choisissez une valeur","required":{"title":"information obligatoire"}}},"__pointer":"https://github.com/data-fair/simple-directory/site#/properties/authProviders","errorMessage":{}};
Expand Down Expand Up @@ -2018,31 +2018,13 @@ const compiledLayout = {
confirm: "Confirmer",
close: "Fermer",
duplicate: "Dupliquer",
insertAfter: "Insérer après",
copy: "Copier",
paste: "Coller",
sort: "Trier",
up: "Décaler vers le haut",
down: "Décaler vers le bas",
showHelp: "Afficher un message d'aide",
mdeLink1: "[titre du lien",
mdeLink2: "](adresse du lien)",
mdeImg1: "![](",
mdeImg2: "adresse de l'image)",
mdeTable1: "",
mdeTable2: "\n\n| Colonne 1 | Colonne 2 | Colonne 3 |\n| -------- | -------- | -------- |\n| Texte | Texte | Texte |\n\n",
bold: "Gras",
italic: "Italique",
heading: "Titre",
quote: "Citation",
unorderedList: "Liste à puce",
orderedList: "Liste numérotée",
createLink: "Créer un lien",
insertImage: "Insérer une image",
createTable: "Créer un tableau",
preview: "Preview",
mdeGuide: "Syntax documentation",
undo: "Défaire",
redo: "Refaire",
default: "défaut : ",
name: "nom : ",
examples: "Exemples : ",
Expand Down Expand Up @@ -2117,7 +2099,7 @@ const compiledLayout = {

items: {
type: "string",
enum: ["add", "edit", "delete", "sort", "duplicate", "copy", "paste"]
enum: ["add", "edit", "delete", "sort", "duplicate", "insertAfter", "copy", "paste"]
}
},

Expand Down Expand Up @@ -2166,6 +2148,10 @@ const compiledLayout = {
type: "string"
},

insertAfter: {
type: "string"
},

sort: {
type: "string"
}
Expand Down Expand Up @@ -2452,6 +2438,10 @@ const compiledLayout = {
type: "boolean"
},

autocomplete: {
type: "boolean"
},

oneOfItems: {
type: "array",

Expand Down Expand Up @@ -2505,6 +2495,7 @@ const { el, statefulLayout, stateTree } = useVjsf(
null,
computed(() => compiledLayout)
)

</script>

<template>
Expand Down