Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow mermaid to be configured via some query params #1413

Merged
merged 8 commits into from
Jan 7, 2023
1 change: 1 addition & 0 deletions mermaid/package-lock.json

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

3 changes: 2 additions & 1 deletion mermaid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@
"url": "https://github.com/yuzutech/kroki.git"
},
"dependencies": {
"lodash": "^4.17.21",
"micro": "9.4.1",
"pino": "8.8.0",
"pino-debug": "2.0.0",
"puppeteer": "14.4.1"
},
"devDependencies": {
"mermaid": "9.3.0",
"chai": "4.3.7",
"dirty-chai": "^2.0.1",
"mermaid": "9.3.0",
"mocha": "10.2.0",
"pngjs": "^6.0.0",
"standard": "17.0.0"
Expand Down
5 changes: 3 additions & 2 deletions mermaid/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ const instance = require('./browser-instance')
const server = micro(async (req, res) => {
// TODO: add a /_status route (return mermaid version)
// TODO: read the diagram source as plain text
const outputType = req.url.match(/\/(png|svg)$/)?.[1]
const url = new URL(req.url, 'http://localhost') // create a URL object. The base is not important here
const outputType = url.pathname.match(/\/(png|svg)$/)?.[1]
if (outputType) {
const diagramSource = await micro.text(req, { limit: '1mb', encoding: 'utf8' })
if (diagramSource) {
try {
const isPng = outputType === 'png'
const output = await worker.convert(new Task(diagramSource, isPng))
const output = await worker.convert(new Task(diagramSource, isPng), url.searchParams)
res.setHeader('Content-Type', isPng ? 'image/png' : 'image/svg+xml')
return micro.send(res, 200, output)
} catch (err) {
Expand Down
40 changes: 39 additions & 1 deletion mermaid/src/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const { logger } = require('./logger')
const path = require('path')
const puppeteer = require('puppeteer')
const set = require('lodash/set')

class SyntaxError extends Error {
constructor () {
Expand All @@ -15,12 +16,13 @@ class Worker {
this.pageUrl = process.env.KROKI_MERMAID_PAGE_URL || `file://${path.join(__dirname, '..', 'assets', 'index.html')}`
}

async convert (task) {
async convert (task, config) {
const browser = await puppeteer.connect({
browserWSEndpoint: this.browserWSEndpoint,
ignoreHTTPSErrors: true
})
const page = await browser.newPage()
this.updateConfig(task, config)
try {
page.setViewport({ height: 800, width: 600 })
await page.goto(this.pageUrl)
Expand Down Expand Up @@ -65,6 +67,42 @@ class Worker {
}
}
}

updateConfig (task, config) {
for (const property in Object.fromEntries(config)) {
const propertyCamelCase = this.convertPropertyToCamelCase(property)
const value = this.getTypedValue(config.get(property))
set(task.mermaidConfig, propertyCamelCase, value)
}
}

convertPropertyToCamelCase (property) {
const propertySplit = property.split('_')
for (let i = 0; i < propertySplit.length; i++) {
const split = propertySplit[i]
const subSplit = split.split('-')
if (subSplit.length > 1) {
for (let j = 1; j < subSplit.length; j++) {
subSplit[j] = subSplit[j].charAt(0).toUpperCase() + subSplit[j].substring(1)
}
propertySplit[i] = subSplit.join('')
}
}
return propertySplit.join('.')
}

getTypedValue (value) {
if (value.toLowerCase() === 'true' || value.toLocaleString() === 'false') {
return value === 'true'
}
if (value.startsWith('[') && value.endsWith(']')) {
return value.substring(1, value.length - 1).split(',').map(item => this.getTypedValue(item))
}
if (!isNaN(value)) {
return Number(value)
}
return value
}
}

module.exports = {
Expand Down