diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fbb1483ab0..e4ff252f64 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,6 +8,7 @@ java/ @smahati # Infra .github/ @chgeo @swaldmann .vitepress/ @chgeo @swaldmann +public/ @chgeo @swaldmann # allow dependencies updates through renovate w/o code owners package.json diff --git a/.github/renovate.json b/.github/renovate.json index 141f5b2876..64415f15dd 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -54,5 +54,16 @@ "depNameTemplate": "com.sap.cds:cds4j-api", "datasourceTemplate": "maven", "versioningTemplate": "maven" + }, + { + "customType": "regex", + "fileMatch": [ ".vitepress/config.*" ], + "matchStrings": [ + "cloud_sec_ams\\s*:\\s*'(?.*?)'" + ], + "depNameTemplate": "com.sap.cloud.security.ams.client:cap-ams-support", + "datasourceTemplate": "maven", + "versioningTemplate": "maven" } + ]} diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 9a2a0e219c..0000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -v20 diff --git a/.vitepress/config.js b/.vitepress/config.js index 0bfab873f3..0a548364a8 100644 --- a/.vitepress/config.js +++ b/.vitepress/config.js @@ -4,6 +4,7 @@ const base = process.env.GH_BASE || '/docs/' // Construct vitepress config object... import path from 'node:path' import { defineConfig } from 'vitepress' +import playground from './lib/cds-playground/index.js' import languages from './languages' import { Menu } from './menu.js' @@ -75,10 +76,17 @@ const config = defineConfig({ ['link', { rel: 'icon', href: base+'favicon.ico' }], ['link', { rel: 'shortcut icon', href: base+'favicon.ico' }], ['link', { rel: 'apple-touch-icon', sizes: '180x180', href: base+'logos/cap.png' }], - ['script', { src: base+'script.js' } ] + // Inline script to restore impl-variant selection immediately (before first paint) + ['script', { id: 'check-impl-variant' }, `{const p=new URLSearchParams(location.search),v=p.get('impl-variant')||localStorage.getItem('impl-variant');if(v)document.documentElement.classList.add(v)}`] ], vite: { + plugins: [...playground.plugins()], + esbuild: { + supported: { + 'top-level-await': true //browsers can handle top-level-await features in special cases + }, + }, build: { chunkSizeWarningLimit: 6000, // chunk for local search index dominates }, @@ -116,8 +124,9 @@ const siteURL = new URL(process.env.SITE_HOSTNAME || 'http://localhost:4173/docs if (!siteURL.pathname.endsWith('/')) siteURL.pathname += '/' config.themeConfig.capire = { versions: { - java_services: '4.7.0', - java_cds4j: '4.7.0' + java_services: '4.8.0', + java_cds4j: '4.8.0', + cloud_sec_ams: '3.8.0' }, gotoLinks: [], siteURL @@ -194,10 +203,14 @@ if (process.env.VITE_CAPIRE_EXTRA_ASSETS) { import { dl } from '@mdit/plugin-dl' import * as MdAttrsPropagate from './lib/md-attrs-propagate' import * as MdTypedModels from './lib/md-typed-models' +import * as MdLiveCode from './lib/cds-playground/md-live-code' +import * as MdDiagramSvg from './lib/md-diagram-svg' config.markdown.config = md => { MdAttrsPropagate.install(md) MdTypedModels.install(md) + MdLiveCode.install(md) + MdDiagramSvg.install(md) md.use(dl) } diff --git a/.vitepress/languages/index.ts b/.vitepress/languages/index.ts index b929ab26ee..c6ce02bffb 100644 --- a/.vitepress/languages/index.ts +++ b/.vitepress/languages/index.ts @@ -5,7 +5,7 @@ import scsv from './scsv.tmLanguage.json' with {type:'json'} import type { LanguageInput } from 'shiki' export default [ - { ...cds, aliases:['cds','dcl'] }, + { ...cds, aliases:['cds','dcl', 'cql'] }, { ...csv, aliases:['csv','csvc'] }, { ...scsv, aliases:['csvs'] }, { ...log, aliases:['log','logs'] }, diff --git a/.vitepress/lib/cds-playground/index.js b/.vitepress/lib/cds-playground/index.js new file mode 100644 index 0000000000..54ce2ff6d3 --- /dev/null +++ b/.vitepress/lib/cds-playground/index.js @@ -0,0 +1,23 @@ +import templates from './vite-plugin-templates' +import path from 'path' + +let enabled = false +let plugins = () => [] + +try { + const { node, cap } = await import('vite-plugin-cds') + plugins = () => { + return [node(), cap(), templates([path.join(__dirname, 'templates')])] + } + enabled = true +} +catch { + // eslint-disable-next-line no-console + console.error('live code not available - run `npm i` to update your modules') +} + +export { + enabled, + plugins, +} +export default { enabled, plugins } diff --git a/.vitepress/lib/cds-playground/md-live-code.ts b/.vitepress/lib/cds-playground/md-live-code.ts new file mode 100644 index 0000000000..69c06fe31e --- /dev/null +++ b/.vitepress/lib/cds-playground/md-live-code.ts @@ -0,0 +1,73 @@ +import { MarkdownRenderer, MarkdownEnv } from 'vitepress' +import { dirname, join, relative } from 'path' +import { enabled } from '.' + +/** + * Makes code blocks with "live" in the info string interactive by rendering a component. + * + * ```cds live + * select from Books { title } + * ``` + * + * ```js live + * await INSERT.into('Books').entries( + * { ID: 2, author_ID: 150, title: 'Eldorado' } + * ) + * ``` + * + * Additional options: + * - as : specify the language to execute the code block as (defaults to the language specified before "live") + * example: ```cds live as cql + * - readonly: make the code block readonly + * example: ```cds live readonly + */ +export function install(md: MarkdownRenderer) { + if (!enabled) return + const fence = md.renderer.rules.fence + md.renderer.rules.fence = (tokens, idx, options, env: MarkdownEnv, ...args) => { + + const { info } = tokens[idx] + const [language, live, ...rest] = info.split(' ') + if (live === 'live') { + const mdDir = dirname(env.realPath ?? env.path) + const filePath = './' + relative(mdDir, join(__dirname, '../../theme/components/cds-playground/LiveCode.vue')) + const imp = `import LiveCode from "${filePath}";` + insertScriptSetup(env, imp) + + const opts = Object.fromEntries(['as'].map(key => { + const idx = rest.findIndex(k => k === key) + return idx > -1 ? [key, rest.splice(idx+1, 1)[0]] : []; + })) + const props = { + language: opts.as ?? language, + } + const flags = ['readonly'].filter(k => rest.includes(k)) + + const content = tokens[idx].content.trim() + return ` `${k}="${v}"`)} ${flags.join(' ')}>` + } + return fence!(tokens, idx, options, env, ...args) + } +} + +function insertScriptSetup(env: MarkdownEnv, imp: string) { + const sfcBlocks = env.sfcBlocks! + if (!sfcBlocks.scriptSetup) { + sfcBlocks.scriptSetup = { + content: '', + contentStripped: '\n', + tagClose: '', + tagOpen: '', + contentStripped: '\n', + tagClose: '', + tagOpen: '