first commit
This commit is contained in:
Vendored
Executable
+37
@@ -0,0 +1,37 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* contract `test` to be non-empty string.
|
||||
* @param {string} test test string
|
||||
* @param {string} msg message on exception
|
||||
*/
|
||||
toNonEmptyString: function (test, msg) {
|
||||
if (typeof test !== 'string') throw new Error(msg);
|
||||
if (test === ''
|
||||
|| test === null
|
||||
|| test === undefined) throw new Error(msg);
|
||||
},
|
||||
/**
|
||||
* contract `test` to be true.
|
||||
* @param {boolean} test test boolean.
|
||||
* @param {sting} msg massage on excetion.
|
||||
*/
|
||||
toTrue: function (test, msg) {
|
||||
if (typeof test !== 'boolean') throw new Error(msg);
|
||||
if (!test) throw new Error(msg);
|
||||
},
|
||||
toBeUrlString: function (test, msg) {
|
||||
this.toNonEmptyString(test, msg);
|
||||
try {
|
||||
new URL(test);
|
||||
} catch {
|
||||
throw new Error(msg);
|
||||
}
|
||||
},
|
||||
toBeClassName: function (test, msg) {
|
||||
if (!/^[A-Za-z0-9]+(-?[A-Za-z0-9]+)*$/.exec(test)) {
|
||||
throw new Error(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
.obsidian/plugins/marp-slides/lib3/markdown-it/@kazumatu981/markdown-it-kroki/lib/diagram-encoder.js
Vendored
Executable
+27
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const { deflateSync } = require('zlib');
|
||||
const contract = require('./contract');
|
||||
const support = require('./support');
|
||||
|
||||
function encode(diagram) {
|
||||
return deflateSync(diagram, { level: 9 }).toString('base64url');
|
||||
}
|
||||
function generateUrl(entrypoint, lang, imgType, diagram) {
|
||||
|
||||
contract.toNonEmptyString(entrypoint, '\'entrypoint\' must be non-empty string.');
|
||||
contract.toNonEmptyString(lang, '\'lang\' must be non-empty string.');
|
||||
contract.toNonEmptyString(imgType, '\'imgType\' must be non-empty string.');
|
||||
contract.toNonEmptyString(diagram, '\'diagram\' must be non-empty string.');
|
||||
contract.toTrue(support.languageSupports(lang), 'Not Supported Diagram Language.');
|
||||
contract.toTrue(support.imageFormatSupports(imgType), 'Not Supported Image Type.');
|
||||
|
||||
const api = `${lang}/${imgType}/${encode(diagram)}`;
|
||||
|
||||
return entrypoint.endsWith('/') ?
|
||||
`${entrypoint}${api}` : `${entrypoint}/${api}`;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
encode, generateUrl
|
||||
};
|
||||
Vendored
Executable
+52
@@ -0,0 +1,52 @@
|
||||
const { deflateSync } = require('zlib')
|
||||
|
||||
const krokiLangs = [
|
||||
'actdiag',
|
||||
'blockdiag',
|
||||
'bpmn',
|
||||
'bytefield',
|
||||
'c4plantuml',
|
||||
'ditaa',
|
||||
'dot',
|
||||
'erd',
|
||||
'excalidraw',
|
||||
'graphviz',
|
||||
'mermaid',
|
||||
'nomnoml',
|
||||
'nwdiag',
|
||||
'packetdiag',
|
||||
'pikchr',
|
||||
'plantuml',
|
||||
'rackdiag',
|
||||
'seqdiag',
|
||||
'svgbob',
|
||||
'umlet',
|
||||
'vega',
|
||||
'vegalite',
|
||||
'wavedrom',
|
||||
]
|
||||
|
||||
const entrypoint = 'https://kroki.io/'
|
||||
|
||||
const marpKrokiPlugin = (md) => {
|
||||
const { fence } = md.renderer.rules
|
||||
|
||||
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
|
||||
const info = md.utils.unescapeAll(tokens[idx].info).trim()
|
||||
|
||||
if (info) {
|
||||
const [lang] = info.split(/(\s+)/g)
|
||||
|
||||
if (krokiLangs.includes(lang)) {
|
||||
const data = deflateSync(tokens[idx].content).toString('base64url')
|
||||
|
||||
// <marp-auto-scaling> is working only with Marp Core v3
|
||||
return `<p><marp-auto-scaling data-downscale-only><img src="${entrypoint}${lang}/svg/${data}"/></marp-auto-scaling></p>`
|
||||
}
|
||||
}
|
||||
|
||||
return fence.call(self, tokens, idx, options, env, self)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = marpKrokiPlugin
|
||||
Vendored
Executable
+85
@@ -0,0 +1,85 @@
|
||||
'use strict';
|
||||
|
||||
const support = require('./support');
|
||||
const contract = require('./contract');
|
||||
const { safeProperty, safeChoice } = require('./safe-property');
|
||||
const diagramEncoder = require('./diagram-encoder');
|
||||
|
||||
class MarkdownItKrokiCore {
|
||||
constructor(md) {
|
||||
this._md = md;
|
||||
}
|
||||
setOptions(opt) {
|
||||
this._entrypoint = safeProperty(opt, "entrypoint", "string", 'https://kroki.io');
|
||||
this._containerClass = safeProperty(opt, "containerClass", "string", "kroki-image-container");
|
||||
this._imageFormat = safeProperty(opt, "imageFormat", "string", "svg");
|
||||
this._useImg = safeProperty(opt, "useImg", "boolean", false);
|
||||
this._render = safeProperty(opt, "render", "function", undefined);
|
||||
|
||||
this._imageFormat = safeChoice(this._imageFormat, support.imageFormats, "svg");
|
||||
|
||||
contract.toBeUrlString(this._entrypoint, "entrypoint must be url string.");
|
||||
contract.toBeClassName(this._containerClass, "containerClass must be className.");
|
||||
|
||||
return this;
|
||||
}
|
||||
use() {
|
||||
// if _md has `marpit` property then use <marp-auto-scaling> tag
|
||||
this._marpAutoScaling = this._md['marpit'] !== undefined;
|
||||
|
||||
this._defaultFence = this._md.renderer.rules.fence;
|
||||
this._md.renderer.rules.fence
|
||||
= (tokens, idx, options, env, self) => this.krokiFencePlugin(tokens, idx, options, env, self);
|
||||
}
|
||||
static readLanguageAndAltText(info) {
|
||||
if (!info) return { language: '', alt: '' };
|
||||
|
||||
const trimed = info.trim();
|
||||
const langFound = /[\s|\[]/.exec(trimed);
|
||||
const altFound = /\[.*?\]/.exec(trimed);
|
||||
|
||||
return {
|
||||
language: langFound ?
|
||||
trimed.substring(0, langFound.index) : trimed,
|
||||
alt: altFound ?
|
||||
altFound[0].replace('[', '').replace(']', '') : ''
|
||||
};
|
||||
}
|
||||
buildEmbedHTML(langAndAlt, diagramCode) {
|
||||
// alt build url
|
||||
const url = diagramEncoder.generateUrl(
|
||||
this._entrypoint, langAndAlt.language, this._imageFormat, diagramCode);
|
||||
|
||||
// sanitize alt
|
||||
const alt = langAndAlt.alt ?
|
||||
this._md.utils.escapeHtml(langAndAlt.alt) : undefined;
|
||||
// build img tag
|
||||
let imgTag;
|
||||
if(this._render) {
|
||||
imgTag = this._render(url, alt);
|
||||
} else if (this._useImg) {
|
||||
imgTag = langAndAlt.alt ?
|
||||
`<img alt="${alt}" src="${url}" />` : `<img src="${url}" />`;
|
||||
} else {
|
||||
imgTag = langAndAlt.alt ?
|
||||
`<embed title="${alt}" src="${url}" />` : `<embed src="${url}" />`;
|
||||
}
|
||||
|
||||
// build container contents
|
||||
const containerContents = this._marpAutoScaling ?
|
||||
`<marp-auto-scaling data-downscale-only>${imgTag}</marp-auto-scaling>` : imgTag;
|
||||
// build embed HTML
|
||||
return `<p class="${this._containerClass}">${containerContents}</p>`;
|
||||
}
|
||||
krokiFencePlugin(tokens, idx, options, env, self) {
|
||||
const info = this._md.utils.unescapeAll(tokens[idx].info)
|
||||
const langAndAlt = MarkdownItKrokiCore.readLanguageAndAltText(info);
|
||||
|
||||
return support.languageSupports(langAndAlt.language) ?
|
||||
this.buildEmbedHTML(langAndAlt, tokens[idx].content) :
|
||||
this._defaultFence.call(self, tokens, idx, options, env, self);
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
MarkdownItKrokiCore
|
||||
}
|
||||
Vendored
Executable
+15
@@ -0,0 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
function safeProperty(test, name, type, defaultValue) {
|
||||
if (test == null || test == undefined) return defaultValue;
|
||||
if (typeof test[name] !== type) return defaultValue;
|
||||
if (typeof test[name] === "string" && test[name] === '') return defaultValue;
|
||||
return test[name];
|
||||
}
|
||||
|
||||
function safeChoice(test, candidates, defaultValue) {
|
||||
return candidates.includes(test) ?
|
||||
test : defaultValue;
|
||||
}
|
||||
|
||||
module.exports = { safeProperty, safeChoice };
|
||||
Vendored
Executable
+56
@@ -0,0 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Diagram Languages are supported by kroki.io
|
||||
*/
|
||||
const LANGUAGES = [
|
||||
'actdiag',
|
||||
'blockdiag',
|
||||
'bpmn',
|
||||
'bytefield',
|
||||
'c4plantuml',
|
||||
'dbml',
|
||||
'ditaa',
|
||||
'dot',
|
||||
'd2',
|
||||
'erd',
|
||||
'excalidraw',
|
||||
'graphviz',
|
||||
'mermaid',
|
||||
'nomnoml',
|
||||
'nwdiag',
|
||||
'packetdiag',
|
||||
'pikchr',
|
||||
'plantuml',
|
||||
'rackdiag',
|
||||
'seqdiag',
|
||||
'svgbob',
|
||||
'umlet',
|
||||
'vega',
|
||||
'vegalite',
|
||||
'wavedrom',
|
||||
];
|
||||
|
||||
/**
|
||||
* Image formats are supported by kroki.io
|
||||
*/
|
||||
const IMG_FORMATS = [
|
||||
'png', 'svg', 'jpeg', 'pdf', 'base64'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
lnaguages: LANGUAGES,
|
||||
imageFormats: IMG_FORMATS,
|
||||
/**
|
||||
* test whether `lang` is supported diagram language by kroki.io
|
||||
* @param {string} lang target language
|
||||
* @returns is supported
|
||||
*/
|
||||
languageSupports: (lang) => LANGUAGES.includes(lang),
|
||||
/**
|
||||
* test whether `format` is supported image format by kroki.io
|
||||
* @param {string} format name of image format like 'png', 'svg', ... etc
|
||||
* @returns is supported
|
||||
*/
|
||||
imageFormatSupports: (format) => IMG_FORMATS.includes(format)
|
||||
};
|
||||
Reference in New Issue
Block a user