UNPKG

node-red-contrib-knx-ultimate

Version:

Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control and ETS group address importer. Easy to use and highly configurable.

262 lines (244 loc) 7.53 kB
#!/usr/bin/env node /* Injects/updates a compact navigation header below the language bar on every wiki page. The header is localized based on filename prefix: it- / de- / zh-CN- / (default EN). It is wrapped between markers so it can be updated idempotently: <!-- NAV START --> ... one-line header ... <!-- NAV END --> Insertion point: right after the language bar and before the first '---' separator when present. */ const fs = require('fs') const path = require('path') const ROOT = process.cwd() const WIKI_DIR = path.resolve(ROOT, '..', 'node-red-contrib-knx-ultimate.wiki') const ABS = 'https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/' const MENU_CFG = path.join(__dirname, 'wiki-menu.json') function listMarkdown (dir) { const out = [] for (const e of fs.readdirSync(dir, { withFileTypes: true })) { const p = path.join(dir, e.name) if (e.isDirectory()) out.push(...listMarkdown(p)) else if (e.isFile() && e.name.endsWith('.md')) out.push(p) } return out } function detectLang (fileBase) { if (fileBase.startsWith('it-')) return 'it' if (fileBase.startsWith('de-')) return 'de' if (fileBase.startsWith('zh-CN-')) return 'zh' return 'en' } function slugify (title) { return title.replace(/ /g, '+') } function pageUrl (lang, title) { const slug = slugify(title) const pref = lang === 'en' ? '' : (lang === 'zh' ? 'zh-CN-' : lang + '-') return ABS + pref + slug } const LABELS = { en: { nav: 'Navigation', home: 'Home', overview: 'Overview', changelog: 'Changelog', faq: 'FAQ', security: 'Security', docsLang: 'Docs: Language bar', knxMain: 'KNX Device', gateway: 'Gateway', device: 'Device', protections: 'Protections', knxOther: 'Other KNX Nodes', scene: 'Scene Controller', watchdog: 'WatchDog', logger: 'Logger', global: 'Global Context', alerter: 'Alerter', load: 'Load Control', viewer: 'Viewer', autoresp: 'Auto Responder', ha: 'HA Translator', hue: 'HUE', bridge: 'Bridge', light: 'Light', battery: 'Battery', button: 'Button', contact: 'Contact', devsw: 'Device SW update', lightsensor: 'Light sensor', motion: 'Motion', sceneH: 'Scene', tapdial: 'Tap Dial', temperature: 'Temperature', zigbee: 'Zigbee connectivity', samples: 'Samples' }, it: { nav: 'Navigazione', home: 'Home', overview: 'Panoramica', changelog: 'Changelog', faq: 'FAQ', security: 'Sicurezza', docsLang: 'Docs: Barra lingue', knxMain: 'Nodo KNX Dispositivo', gateway: 'Gateway', device: 'Dispositivo', protections: 'Protezioni', knxOther: 'Altri Nodi KNX', scene: 'Scene Controller', watchdog: 'WatchDog', logger: 'Logger', global: 'Global Context', alerter: 'Alerter', load: 'Controllo Carico', viewer: 'Viewer', autoresp: 'Auto Responder', ha: 'Traduttore HA', hue: 'HUE', bridge: 'Bridge', light: 'Luce', battery: 'Batteria', button: 'Pulsante', contact: 'Contatto', devsw: 'Aggiornamento SW', lightsensor: 'Sensore Luce', motion: 'Movimento', sceneH: 'Scena', tapdial: 'Tap Dial', temperature: 'Temperatura', zigbee: 'Connettività Zigbee', samples: 'Esempi' }, de: { nav: 'Navigation', home: 'Startseite', overview: 'Übersicht', changelog: 'Changelog', faq: 'FAQ', security: 'Sicherheit', docsLang: 'Doku: Sprachleiste', knxMain: 'KNX Geräteknoten', gateway: 'Gateway', device: 'Gerät', protections: 'Knotenschutz', knxOther: 'Weitere KNX‑Knoten', scene: 'Szenencontroller', watchdog: 'WatchDog', logger: 'Logger', global: 'Global Context', alerter: 'Alerter', load: 'Laststeuerung', viewer: 'Viewer', autoresp: 'Auto‑Responder', ha: 'HA‑Übersetzer', hue: 'HUE', bridge: 'Bridge', light: 'Licht', battery: 'Batterie', button: 'Taster', contact: 'Kontaktsensor', devsw: 'Geräte‑SW‑Update', lightsensor: 'Lichtsensor', motion: 'Bewegung', sceneH: 'Szene', tapdial: 'Tap Dial', temperature: 'Temperatur', zigbee: 'Zigbee‑Konnektivität', samples: 'Beispiele' }, zh: { nav: '导航', home: '首页', overview: '概览', changelog: '更新日志', faq: '常见问题', security: '安全', docsLang: '文档:语言栏', knxMain: 'KNX 设备', gateway: '网关', device: '设备', protections: '节点保护', knxOther: '其他 KNX 节点', scene: '场景控制器', watchdog: '看门狗', logger: '日志节点', global: '全局上下文', alerter: '告警器', load: '负载控制', viewer: '查看器', autoresp: '自动响应', ha: 'HA 翻译器', hue: 'HUE', bridge: 'Bridge', light: '灯', battery: '电池', button: '按钮', contact: '接触', devsw: '设备软件更新', lightsensor: '光照传感器', motion: '运动', sceneH: '场景', tapdial: 'Tap Dial', temperature: '温度', zigbee: 'Zigbee 连接', samples: '示例' } } function buildHeader (lang) { const L = LABELS[lang] const mk = (t) => pageUrl(lang, t) const cfg = JSON.parse(fs.readFileSync(MENU_CFG, 'utf8')) const lines = [] lines.push(`${L.nav}: [${L.home}](${mk('Home')})`) for (const section of cfg.sections) { const sLabel = section.labels[lang] || section.labels.en const parts = [] for (const it of section.items) { const label = (it.labels && (it.labels[lang] || it.labels.en)) || 'Link' const href = it.type === 'url' ? it.url : mk(it.page) parts.push(`[${label}](${href})`) } lines.push(`${sLabel}: ${parts.join(' • ')}`) } return lines.join('\n') } function updateFile (file) { const base = path.basename(file) if (base === '_Sidebar.md' || base === '_Footer.md') return false const lang = detectLang(base) const header = buildHeader(lang) const NAV_START = '<!-- NAV START -->' const NAV_END = '<!-- NAV END -->' const content = fs.readFileSync(file, 'utf8') const lines = content.split(/\r?\n/) if (!lines.length) return false if (!lines[0].startsWith('🌐 Language:')) return false // enforce language bar presence // If header exists, replace block const startIdx = lines.findIndex(l => l.trim() === NAV_START) const endIdx = lines.findIndex(l => l.trim() === NAV_END) if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) { const prev = lines.slice(startIdx + 1, endIdx).join('\n') if (prev.trim() === header.trim()) return false // no change lines.splice(startIdx, endIdx - startIdx + 1, NAV_START, header, NAV_END) fs.writeFileSync(file, lines.join('\n'), 'utf8') return true } // Insert below language bar and before first '---' separator when present let insertAt = 1 const sepIdx = lines.slice(1, 6).findIndex(l => l.trim() === '---') if (sepIdx !== -1) insertAt = 1 + sepIdx // place right before the '---' lines.splice(insertAt, 0, NAV_START, header, NAV_END) fs.writeFileSync(file, lines.join('\n'), 'utf8') return true } const files = listMarkdown(WIKI_DIR) let changed = 0; let skipped = 0 for (const f of files) { try { if (updateFile(f)) changed++; else skipped++ } catch (e) { console.error('Error processing', f, e.message) } } console.log(`Header injected/updated in ${changed} pages. Unchanged/skipped: ${skipped}.`)