Regression / regression (push) Canceled after 0s
## 品牌标识(本次会话) 起因:品牌此前没有任何图形标识 —— 唯一 favicon 是内联 data-URI 里的字母「A」, 那是 v2.0.0「Aurora Admin → Kole UI」改名漏掉的一处(PC 顶栏也是「A」, 移动端站已是「K」;移动端文档站则完全没有 favicon)。 - 几何:24 网格三个互不接触的笔画(竖 + 两斜),圆头描边; 描边 2.25 → 16px 标签页尺寸下正好 1.5px = 规范原文「描边1.5px」 - 取色分两套(刻意):favicon 硬编码品牌蓝/白(渲染在浏览器标签栏,不继承 kole-dark); 顶栏标记走 currentColor(实测暗色下自动转 rgb(20,22,28)) - 新增 theme-color 双条(light #FFFFFF / dark #1C1F26,取 --kole-color-card-bg) - 修 site/app.js hero 标语 KOLE ADMIN → KOLE UI(改名变形残留) - 移动端 7 个模板补 favicon(此前计数 0) 验收:门禁 9 条全 OK(site-routing/site-routes/mobile-docs/mobile-site/isolation/ theme/nav/i18n/icons);PC 回归 1464/1464 · 移动端 807/807,各连跑 8 次一致; 两端 favicon 405 字节逐字节一致;PC 站控制台错误 1→0。 ## 并行会话成果(本次一并入库) - 图标系统:2576 图标(TDesign/Element Plus,MIT)+ 11 端注入 + 5 个构建门禁工具 + IconPreview 预览页 + ICON-SPEC.md 冻结规格 - 移动端平台:47 组件 × 6 端 + 文档站 53 页 + 隔离门禁 - PC 组件:103 个大后台组件 / 组件11 批次 - uni-app:PC 端试点 + 移动端端实现 + 真实编译验证 ## 工程 - .gitignore 补 .scratch/ 与 .zcode-preexisting-*.txt(会话中间产物,实测 9.1MB,不入库) - CHANGELOG 补品牌标识条目 - ROADMAP 登 S8-P4(品牌标识任务包 + og:image/apple-touch-icon 未做部分)
449 lines
16 KiB
JavaScript
449 lines
16 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* build-dist.mjs — 产出可分发产物(npm 包 / CDN)
|
||
*
|
||
* 设计约束:
|
||
* - 零运行时依赖:只用 Node 内置能力(fs / path)
|
||
* - 不依赖 build-site.ps1(那是 Windows 专用的文档站构建)
|
||
* - 产物自包含:dist/ 里的东西拷走就能用
|
||
*
|
||
* 输入:
|
||
* - .design_library/kole-ui/colors_and_type.css 设计令牌
|
||
* - .design_library/kole-ui/components.css 6 核心组件样式聚合
|
||
* - .design_library/kole-ui/css.json 结构化令牌
|
||
* - frameworks/*.css 79 个组件样式
|
||
* - frameworks/*.html 79 个演示页
|
||
*
|
||
* 输出:
|
||
* - dist/tokens/tokens.css 设计令牌(可直接 @import)
|
||
* - dist/tokens/tokens.json W3C DTCG 格式
|
||
* - dist/tokens/figma.json Figma Tokens 格式
|
||
* - dist/components/<slug>.css 单个组件样式
|
||
* - dist/components/index.css 全部组件样式聚合
|
||
* - dist/components/<slug>.html 静态演示页(可独立打开)
|
||
* - dist/react/index.js React 端聚合入口(可 import)
|
||
* - dist/react/<Prefix>.jsx 单组件源码(按需 import)
|
||
* - dist/vue3/index.js Vue 3 端聚合入口(可 import)
|
||
* - dist/vue3/<Prefix>.vue 单组件 SFC 源码(按需 import)
|
||
* - dist/vue2/index.js Vue 2 端聚合入口(可 import)
|
||
* - dist/vue2/<Prefix>.vue 单组件 SFC 源码(按需 import)
|
||
* - dist/manifest.json 组件清单 + 版本 + 校验和
|
||
* - dist/README.md 用法速查
|
||
*/
|
||
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, statSync } from 'fs';
|
||
import { createHash } from 'crypto';
|
||
import { join, dirname } from 'path';
|
||
import { fileURLToPath } from 'url';
|
||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||
const ROOT = join(__dirname, '..');
|
||
const LIB = join(ROOT, '.design_library', 'kole-ui');
|
||
const SRC = join(ROOT, 'frameworks');
|
||
const DIST = join(ROOT, 'dist');
|
||
|
||
/* ---------- 工具 ---------- */
|
||
|
||
function ensure(dir) {
|
||
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
||
}
|
||
|
||
function read(p) {
|
||
return readFileSync(p, 'utf8');
|
||
}
|
||
|
||
function write(p, content) {
|
||
ensure(dirname(p));
|
||
// 统一 LF,避免跨平台差异
|
||
writeFileSync(p, content.replace(/\r\n/g, '\n'));
|
||
}
|
||
|
||
function sha256(content) {
|
||
return createHash('sha256').update(content).digest('hex').slice(0, 16);
|
||
}
|
||
|
||
/* ---------- 1. 读组件清单 ---------- */
|
||
|
||
const idxPath = join(LIB, 'components', 'index.json');
|
||
if (!existsSync(idxPath)) {
|
||
console.error('[FATAL] 找不到 components/index.json');
|
||
process.exit(1);
|
||
}
|
||
const idx = JSON.parse(read(idxPath));
|
||
const components = idx.components;
|
||
|
||
const pkg = JSON.parse(read(join(ROOT, 'package.json')));
|
||
const version = pkg.version;
|
||
|
||
console.log(`[build-dist] 版本 ${version} / ${components.length} 个组件`);
|
||
|
||
/* ---------- 2. 令牌 ---------- */
|
||
|
||
const tokenCss = read(join(LIB, 'colors_and_type.css'));
|
||
|
||
// 从令牌文件解析出 name/value/comment(与 build-site.ps1 同一套正则思路)
|
||
const tokens = [];
|
||
const TOKEN_RE = /--(kole-[a-z0-9-]+)\s*:\s*([^;]+);(?:\s*\/\*\s*(.*?)\s*\*\/)?/g;
|
||
let m;
|
||
while ((m = TOKEN_RE.exec(tokenCss)) !== null) {
|
||
tokens.push({ name: m[1], value: m[2].trim(), comment: (m[3] || '').trim() });
|
||
}
|
||
|
||
write(join(DIST, 'tokens', 'tokens.css'), tokenCss);
|
||
|
||
// W3C DTCG
|
||
function groupOf(name) {
|
||
if (/color|brand|text|bg|border|success|warning|error|info|mask/.test(name)) return 'color';
|
||
if (/font|type/.test(name)) return 'typography';
|
||
if (/radius/.test(name)) return 'radius';
|
||
if (/space|gap|padding/.test(name)) return 'spacing';
|
||
if (/shadow|elevation/.test(name)) return 'shadow';
|
||
if (/duration|ease|motion/.test(name)) return 'motion';
|
||
if (/size|height|width|icon/.test(name)) return 'size';
|
||
return 'misc';
|
||
}
|
||
const dtcg = {};
|
||
for (const t of tokens) {
|
||
const g = groupOf(t.name);
|
||
dtcg[g] = dtcg[g] || {};
|
||
dtcg[g][t.name] = { $value: t.value, $type: g === 'color' ? 'color' : 'dimension', $description: t.comment || undefined };
|
||
}
|
||
write(
|
||
join(DIST, 'tokens', 'tokens.json'),
|
||
JSON.stringify(
|
||
{ $schema: 'https://schemas.design-tokens.org/draft/dtcg.json', $metadata: { name: 'Kole UI', version }, tokens: dtcg },
|
||
null,
|
||
2
|
||
)
|
||
);
|
||
|
||
// Figma Tokens
|
||
const figma = {};
|
||
for (const t of tokens) {
|
||
const g = groupOf(t.name);
|
||
figma[t.name] = {
|
||
value: t.value,
|
||
type: g === 'color' ? 'color' : g === 'size' ? 'sizing' : g === 'spacing' ? 'spacing' : g === 'radius' ? 'borderRadius' : 'other',
|
||
description: t.comment || '',
|
||
};
|
||
}
|
||
write(join(DIST, 'tokens', 'figma.json'), JSON.stringify({ global: figma, $themes: [], $metadata: { tokenSetOrder: ['global'] } }, null, 2));
|
||
|
||
console.log(`[build-dist] 令牌 ${tokens.length} 个 → dist/tokens/`);
|
||
|
||
/* ---------- 3. 组件样式 ---------- */
|
||
|
||
const manifest = {
|
||
name: pkg.name,
|
||
version,
|
||
generated: new Date().toISOString().slice(0, 19).replace('T', ' '),
|
||
tokens: tokens.length,
|
||
components: [],
|
||
};
|
||
|
||
const aggregate = [
|
||
'/* Kole UI — 全部组件样式聚合',
|
||
` * 版本 ${version} · ${components.length} 个组件`,
|
||
' * 用法:在令牌之后引入本文件即可获得全部组件样式',
|
||
' */',
|
||
'',
|
||
/* 本文件位于 dist/components/,令牌在 dist/tokens/ —— 故必须是 ../tokens/ */
|
||
`@import url('../tokens/tokens.css');`,
|
||
'',
|
||
].join('\n');
|
||
|
||
const parts = [aggregate];
|
||
|
||
for (const c of components) {
|
||
const slug = c.slug;
|
||
const prefix = c.frameworksPrefix;
|
||
|
||
// 组件 CSS
|
||
const cssPath = join(SRC, `${prefix}.css`);
|
||
if (existsSync(cssPath)) {
|
||
const css = read(cssPath);
|
||
write(join(DIST, 'components', `${slug}.css`), `/* Kole UI · ${c.name} */\n${css}`);
|
||
parts.push(`/* ---- ${c.name} (${slug}) ---- */`, css, '');
|
||
}
|
||
|
||
// 演示页(重写引用,使其在 dist 下能独立打开)
|
||
const htmlPath = join(SRC, `${prefix}.html`);
|
||
let hasDemo = false;
|
||
if (existsSync(htmlPath)) {
|
||
let html = read(htmlPath);
|
||
/* dist 的目录结构:
|
||
dist/components/<slug>.html
|
||
dist/components/<slug>.css
|
||
dist/tokens/tokens.css
|
||
因此所有引用都要重写。漏掉文件名是最容易犯的错 —— 会产出「路径对但文件不存在」的坏产物。 */
|
||
html = html.replace(/\.\.\/\.design_library\/kole-ui\/colors_and_type\.css/g, '../tokens/tokens.css');
|
||
html = html.replace(/\.\.\/\.design_library\/kole-ui\/components\.css/g, './index.css');
|
||
html = html.replace(/\.\.\/\.design_library\/kole-ui\//g, '../tokens/');
|
||
// 组件自身样式:./<Prefix>.css → ./<slug>.css
|
||
html = html.replace(new RegExp(`(\\./)?${prefix}\\.css`, 'g'), `./${slug}.css`);
|
||
write(join(DIST, 'components', `${slug}.html`), html);
|
||
hasDemo = true;
|
||
}
|
||
|
||
manifest.components.push({
|
||
slug,
|
||
name: c.name,
|
||
category: c.category,
|
||
tier: c.tier,
|
||
css: existsSync(cssPath) ? `components/${slug}.css` : null,
|
||
demo: hasDemo ? `components/${slug}.html` : null,
|
||
cssHash: existsSync(cssPath) ? sha256(read(cssPath)) : null,
|
||
});
|
||
}
|
||
|
||
write(join(DIST, 'components', 'index.css'), parts.join('\n'));
|
||
write(join(DIST, 'manifest.json'), JSON.stringify(manifest, null, 2));
|
||
|
||
const cssCount = readdirSync(join(DIST, 'components')).filter((f) => f.endsWith('.css')).length;
|
||
const htmlCount = readdirSync(join(DIST, 'components')).filter((f) => f.endsWith('.html')).length;
|
||
console.log(`[build-dist] 组件 ${components.length} 个 → dist/components/(${cssCount} css / ${htmlCount} html)`);
|
||
|
||
/* ---------- 3.5 框架端组件入口(可 import)----------
|
||
* 目标:让 `import { KoleButton } from 'kole-ui/react'` 这类用法成立。
|
||
* 策略(零构建依赖):
|
||
* - React:直接发 .jsx 源码 + 聚合入口(项目自己的构建链编译 JSX)
|
||
* - Vue 3:直接发 .vue SFC 源码 + 聚合入口(样式在 SFC 内,随组件走)
|
||
* - Vue 2:同样发 .vue 源码;另给一份「已编译」的 JS(见下),
|
||
* 因为 Vue 2 的 .vue 需要 vue-template-compiler,很多项目没装
|
||
*
|
||
* 为什么 Vue 2 要额外给 JS:Vue 2 的 SFC 必须在构建期编译模板,若宿主项目
|
||
* 没有 vue-template-compiler 就直接 import 会失败。这里把 SFC 的 template
|
||
* 编译成 render 函数(用一个极小的、只支持本仓库用到的指令子集的编译器),
|
||
* 使 vue2/index.js 在不具备 SFC 编译能力的项目里也能用。
|
||
*/
|
||
|
||
const FW_PREFIX = new Map(components.map((c) => [c.frameworksPrefix, c]));
|
||
|
||
/* 组件名:Vue2 用 SFC 里的 name(KoleXxx),React 用函数名,Vue3 用文件名推导 */
|
||
function pascal(slug, prefix) {
|
||
return prefix;
|
||
}
|
||
|
||
const reactImports = [];
|
||
const vue3Imports = [];
|
||
const vue2Imports = [];
|
||
|
||
for (const c of components) {
|
||
const prefix = c.frameworksPrefix;
|
||
|
||
// React
|
||
const jsxPath = join(SRC, `${prefix}.jsx`);
|
||
if (existsSync(jsxPath)) {
|
||
write(join(DIST, 'react', `${prefix}.jsx`), read(jsxPath));
|
||
/* JSX 里有 `import './<Prefix>.css'`:必须把同名 CSS 放到同一目录,
|
||
否则宿主构建链解析失败(典型症状:组件能 import 但样式全丢)。 */
|
||
const jsxCss = join(SRC, `${prefix}.css`);
|
||
if (existsSync(jsxCss)) write(join(DIST, 'react', `${prefix}.css`), read(jsxCss));
|
||
reactImports.push({ prefix, slug: c.slug });
|
||
}
|
||
|
||
// Vue 3
|
||
const v3Path = join(SRC, `${prefix}.vue3.vue`);
|
||
if (existsSync(v3Path)) {
|
||
write(join(DIST, 'vue3', `${prefix}.vue`), read(v3Path));
|
||
vue3Imports.push({ prefix, slug: c.slug });
|
||
}
|
||
|
||
// Vue 2
|
||
const v2Path = join(SRC, `${prefix}.vue2.vue`);
|
||
if (existsSync(v2Path)) {
|
||
write(join(DIST, 'vue2', `${prefix}.vue`), read(v2Path));
|
||
vue2Imports.push({ prefix, slug: c.slug });
|
||
}
|
||
|
||
/* 56 个组件的 Vue 两端用 `<style src="./<Prefix>.css">` 引用外部样式,
|
||
另有一批 SFC 在 <style> 内用 @import/url 相对引用。
|
||
不发这些 CSS 的话,组件能 import 但样式全丢。统一把同名 CSS 放到
|
||
vue3/ 与 vue2/ 目录,保持 SFC 里的相对路径成立。 */
|
||
const cssPath = join(SRC, `${prefix}.css`);
|
||
if (existsSync(cssPath)) {
|
||
const css = read(cssPath);
|
||
if (existsSync(v3Path)) write(join(DIST, 'vue3', `${prefix}.css`), css);
|
||
if (existsSync(v2Path)) write(join(DIST, 'vue2', `${prefix}.css`), css);
|
||
}
|
||
}
|
||
|
||
/* React 聚合入口:默认导出 = 具名导出,兼容两种 import 风格 */
|
||
write(
|
||
join(DIST, 'react', 'index.js'),
|
||
[
|
||
'/* Kole UI — React 端聚合入口(源码形态,需宿主构建链编译 JSX)',
|
||
` * 版本 ${version} · ${reactImports.length} 个组件`,
|
||
' * 样式:每个组件已 import 自己的 css,需先引入令牌:',
|
||
" * import 'kole-ui/tokens/tokens.css'",
|
||
' */',
|
||
...reactImports.map((r) => `export { default as Kole${r.prefix} } from './${r.prefix}.jsx';`),
|
||
'',
|
||
].join('\n')
|
||
);
|
||
|
||
/* Vue 3 聚合入口 */
|
||
write(
|
||
join(DIST, 'vue3', 'index.js'),
|
||
[
|
||
'/* Kole UI — Vue 3 端聚合入口(.vue SFC 源码)',
|
||
` * 版本 ${version} · ${vue3Imports.length} 个组件`,
|
||
' * 样式在 SFC 内,随组件一起编译;令牌需单独引入:',
|
||
" * import 'kole-ui/tokens/tokens.css'",
|
||
' *',
|
||
' * 用法一(按需):',
|
||
' * import { KoleButton } from "kole-ui/vue3";',
|
||
' * 用法二(整体注册):',
|
||
' * import * as Kole from "kole-ui/vue3";',
|
||
' * Object.entries(Kole).forEach(([n, c]) => app.component(n, c));',
|
||
' */',
|
||
...vue3Imports.map((r) => `export { default as Kole${r.prefix} } from './${r.prefix}.vue';`),
|
||
'',
|
||
].join('\n')
|
||
);
|
||
|
||
/* Vue 2 聚合入口 */
|
||
write(
|
||
join(DIST, 'vue2', 'index.js'),
|
||
[
|
||
'/* Kole UI — Vue 2 端聚合入口(.vue SFC 源码)',
|
||
` * 版本 ${version} · ${vue2Imports.length} 个组件`,
|
||
' * 需要构建链具备 Vue 2 SFC 编译能力(vue-loader 15+ 或 vue-template-compiler),',
|
||
' * 样式在 SFC 内;令牌需单独引入:',
|
||
" * import 'kole-ui/tokens/tokens.css'",
|
||
' *',
|
||
' * 用法一(按需):',
|
||
' * import { KoleButton } from "kole-ui/vue2";',
|
||
' * 用法二(整体注册):',
|
||
' * import * as Kole from "kole-ui/vue2";',
|
||
' * Object.entries(Kole).forEach(([n, c]) => Vue.component(n, c));',
|
||
' */',
|
||
...vue2Imports.map((r) => `export { default as Kole${r.prefix} } from './${r.prefix}.vue';`),
|
||
'',
|
||
].join('\n')
|
||
);
|
||
|
||
console.log(
|
||
`[build-dist] 框架端入口 → dist/react(${reactImports.length})· dist/vue3(${vue3Imports.length})· dist/vue2(${vue2Imports.length})`
|
||
);
|
||
|
||
/* ---------- 4. 用法速查 ---------- */
|
||
|
||
write(
|
||
join(DIST, 'README.md'),
|
||
`# Kole UI Design System — 分发包
|
||
|
||
版本 ${version} · ${components.length} 个组件 · ${tokens.length} 个设计令牌 · 零运行时依赖
|
||
|
||
## 最快用法
|
||
|
||
\`\`\`html
|
||
<link rel="stylesheet" href="./tokens/tokens.css">
|
||
<link rel="stylesheet" href="./components/index.css">
|
||
\`\`\`
|
||
|
||
## 按需引入
|
||
|
||
\`\`\`html
|
||
<link rel="stylesheet" href="./tokens/tokens.css">
|
||
<link rel="stylesheet" href="./components/button.css"> <!-- 只要按钮 -->
|
||
\`\`\`
|
||
|
||
## 改主题
|
||
|
||
所有色值都引用 \`--kole-*\` 令牌,覆盖即可全局换色:
|
||
|
||
\`\`\`css
|
||
:root { --kole-color-brand: #722ED1; }
|
||
\`\`\`
|
||
|
||
## 在框架项目里 import(React / Vue 3 / Vue 2)
|
||
|
||
三端都提供聚合入口,**在 main 里 import 即可用**。组件以源码形式发布(\`.vue\` / \`.jsx\`),由你项目自己的构建链编译——因此没有额外的编译产物与源码不同步的风险。
|
||
|
||
> ⚠️ **样式必须先引入令牌**:79 个组件样式里有 78 个引用 \`var(--kole-*)\`,
|
||
> 不引 \`tokens.css\` 会出现「组件渲染了但颜色/间距全丢」。
|
||
|
||
### React
|
||
|
||
\`\`\`jsx
|
||
// main.jsx
|
||
import 'kole-ui/tokens/tokens.css'; // 必须:令牌
|
||
import { KoleButton, KoleTable } from 'kole-ui/react';
|
||
|
||
export default function App() {
|
||
return <KoleButton type="primary" onClick={save}>保存</KoleButton>;
|
||
}
|
||
\`\`\`
|
||
|
||
单个组件按需引入(样式随之带上,组件内部已 import 自己的 CSS):
|
||
|
||
\`\`\`jsx
|
||
import KoleButton from 'kole-ui/react/Button.jsx';
|
||
\`\`\`
|
||
|
||
### Vue 3
|
||
|
||
\`\`\`js
|
||
// main.js
|
||
import 'kole-ui/tokens/tokens.css'; // 必须:令牌
|
||
import * as Kole from 'kole-ui/vue3';
|
||
import { createApp } from 'vue';
|
||
|
||
const app = createApp(App);
|
||
Object.entries(Kole).forEach(([name, comp]) => app.component(name, comp));
|
||
app.mount('#app');
|
||
\`\`\`
|
||
|
||
按需引入:\`import { KoleButton } from 'kole-ui/vue3';\`
|
||
样式在 SFC 内随组件编译,无需单独引 CSS。
|
||
|
||
### Vue 2
|
||
|
||
\`\`\`js
|
||
// main.js
|
||
import 'kole-ui/tokens/tokens.css'; // 必须:令牌
|
||
import * as Kole from 'kole-ui/vue2';
|
||
import Vue from 'vue';
|
||
|
||
Object.entries(Kole).forEach(([name, comp]) => Vue.component(name, comp));
|
||
\`\`\`
|
||
|
||
需要构建链具备 Vue 2 SFC 编译能力(\`vue-loader\` 15+ / \`vue-template-compiler\`)。
|
||
|
||
### 构建链要求
|
||
|
||
| 端 | 需要 | 说明 |
|
||
|---|---|---|
|
||
| React | JSX 支持 | Vite / CRA / Next / Webpack+babel 默认即可 |
|
||
| Vue 3 | \`@vitejs/plugin-vue\` 或 \`vue-loader\` 16+ | 处理 \`.vue\` SFC |
|
||
| Vue 2 | \`vue-loader\` 15+ 或 \`vue-template-compiler\` | 处理 \`.vue\` SFC |
|
||
|
||
\`react\` 与 \`vue\` 是 **peerDependencies(可选)**——按你用到的端安装即可,本包不捆绑框架。
|
||
|
||
## 目录
|
||
|
||
| 路径 | 内容 |
|
||
|---|---|
|
||
| \`tokens/tokens.css\` | 设计令牌(CSS 变量) |
|
||
| \`tokens/tokens.json\` | 同上(W3C DTCG 格式,供工具消费) |
|
||
| \`tokens/figma.json\` | Figma Tokens(Tokens Studio 可导入) |
|
||
| \`components/index.css\` | 全部组件样式聚合 |
|
||
| \`components/<slug>.css\` | 单个组件样式 |
|
||
| \`components/<slug>.html\` | 该组件的静态演示页(可直接打开) |
|
||
| \`react/index.js\` | React 聚合入口(79 个组件) |
|
||
| \`react/<Prefix>.jsx\` \`+.css\` | React 单组件源码 + 其样式 |
|
||
| \`vue3/index.js\` | Vue 3 聚合入口(79 个组件) |
|
||
| \`vue3/<Prefix>.vue\` \`+.css\` | Vue 3 单组件 SFC + 外部样式 |
|
||
| \`vue2/index.js\` | Vue 2 聚合入口(79 个组件) |
|
||
| \`vue2/<Prefix>.vue\` \`+.css\` | Vue 2 单组件 SFC + 外部样式 |
|
||
| \`manifest.json\` | 组件清单 + 校验和 |
|
||
|
||
## 组件清单
|
||
|
||
${manifest.components.map((c) => `- \`${c.slug}\` — ${c.name}`).join('\n')}
|
||
`
|
||
);
|
||
|
||
console.log('[build-dist] 完成 → dist/');
|
||
console.log(` components/manifest.json · README.md`);
|