diff --git a/down-the-stack-book/README.md b/down-the-stack-book/README.md new file mode 100644 index 0000000..d156996 --- /dev/null +++ b/down-the-stack-book/README.md @@ -0,0 +1,11 @@ +# Down the Stack Slides + +To read as an mdbook: + +1. `cargo install mdbook` +2. `mdbook serve` + +To read as a slide-show: + +1. Download [marp-cli](https://github.com/marp-team/marp-cli/releases) and unpack into your `$PATH` +2. `marp -c marp.config.js -I . -s` diff --git a/down-the-stack-book/marp.config.js b/down-the-stack-book/marp.config.js new file mode 100644 index 0000000..6fd55d6 --- /dev/null +++ b/down-the-stack-book/marp.config.js @@ -0,0 +1,6 @@ +module.exports = { + inputDir: './slides', + engine: ({ marp }) => marp.use(require('@kazumatu981/markdown-it-kroki'), { + entrypoint: "https://kroki.io", + }) +} diff --git a/down-the-stack-book/node_modules/.package-lock.json b/down-the-stack-book/node_modules/.package-lock.json new file mode 100644 index 0000000..6503422 --- /dev/null +++ b/down-the-stack-book/node_modules/.package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "down-the-stack-book", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/@kazumatu981/markdown-it-kroki": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kazumatu981/markdown-it-kroki/-/markdown-it-kroki-1.1.1.tgz", + "integrity": "sha512-LDYl+mV2WogLQ5r4olxovm+gphL/MNGfWZ1M1woBO/YhFnfwdn5EAUu9zF/KoVZzytJPq0RNfyeDtMkv+GJihg==", + "dev": true + } + } +} diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/CHANGELOG.md b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/CHANGELOG.md new file mode 100644 index 0000000..ca902a6 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/CHANGELOG.md @@ -0,0 +1,17 @@ +# CHANGELOG + +## v1.1.1 + +* fix readme, see [this issue](https://github.com/kazumatu981/markdown-it-kroki/issues/1) + +## v1.1.0 + +* Obsolated Option `marpAutoScaling` and detect automatically wether it is nessesury or not. + +## v1.0.1 + +release on npm + +## v1.0.0 + +create new diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/LICENSE b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/LICENSE new file mode 100644 index 0000000..9cf3147 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Kazuyoshi Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/README.md b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/README.md new file mode 100644 index 0000000..ec7ffe7 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/README.md @@ -0,0 +1,157 @@ +# markdown-it-kroki + +> This library was designed to embed [Kori.io](https://kroki.io/) diagram into [Marp](https://marp.app/) Slide-deks!! + + +This library is a pugin for markdown-it to embed figure is created by textual syntax. +To use this package, You can embed **Software Diagram** (like uml) is written by **code** in Marp Slides-deck. + +See marp sample code. + +## Sample + + --- + marp: true + --- + + + ## plantuml + + ```plantuml[platuml image] + @startuml + left to right direction + actor Guest as g + package Professional { + actor Chef as c + actor "Food Critic" as fc + } + package Restaurant { + usecase "Eat Food" as UC1 + usecase "Pay for Food" as UC2 + usecase "Drink" as UC3 + usecase "Review" as UC4 + } + fc --> UC4 + g --> UC1 + g --> UC2 + g --> UC3 + @enduml + ``` + +![plantuml-sample](img/plantuml-sample.png) + +If you want to write daigram, you write Diagram Language (like [plantuml](https://plantuml.com/), [mermaid.js](https://mermaid-js.github.io/mermaid/#/)) with in fenced code block. + +## How to install + +You can install `npm install` command like bellow. + +```bash +npm install -D @kazumatu981/markdown-it-kroki +``` + +## How to use + +Here is the how to use `markdow-it-kroki`. +This section introduce how to create Marp slides-deck project, +and introduce how to create Marp slides-deck server. + +You can find deltail info in [here](https://marp.app/), +and you can learn about marp plugin eco-system, [here](https://marpit.marp.app/usage?id=extend-marpit-by-plugins). + +### **[1st step]** Create Slides-deck project + +First, for create slides-deck, you have to prepair to **Marp Project** directory. +So First, Create slides-deck project, and init npm package. + +```bash +mkdir myslides +cd myslides + +npm init -y +``` + +Secondary, Build Marp Environment. +Install [@marp-team/marp-cli](https://github.com/marp-team/marp-cli). + +```bash +npm install -D @marp-team/marp-cli +``` + +> Off-course you can install as **global package** (like `npm install -g @marp-team/marp-cli`), or **run at-once** (like `npx`). + +### **[2nd step]** Download this project and install + +```bash +git clone https://github.com/kazumatu981/markdown-it-kroki.git + +cd myslides +npm install -D path/to/markdown-it-kroki +``` + + +### **[3rd step]** Create `marp.config.js`. + +Here is the configuration file for **Marp**. + +```javascript +module.exports = { + inputDir: './slides', + engine: ({ marp }) => marp.use(require('@kazumatu981/markdown-it-kroki'), { + entrypoint: "https://kroki.io", + }) +} +``` + +### **[4th step]** Create your slides + +On `slies` directory. you create slides-deck. like this. + + --- + marp: true + --- + + + ## mermaid + + ```mermaid[mermaid image] + flowchart TD + Start --> Stop + ``` + +### **[5th step]** run server + +Run marp server. + +```bash +marp -s -c marp.config.js +``` + +## Detail + +### Syntax of Markdown + +#### Diagram Language + +You have to write diagram language by [fenced code block](https://spec.commonmark.org/0.30/#fenced-code-blocks) syntax, start with **triple back quot** and after that the language. + + ```plantuml + +This package depends on kroki.io. +If you want to know which is **supported diagram language**, +you will see in [Kroki.io official web site (https://kroki.io/)](https://kroki.io/). + +#### Alt Text + +You can write Alt-text attribute to IMG tag in HTML. +Write in `square blacket` after **Diagram Language**. + + ```mermaid [check your network config..] + +### Options of `constructor` + +| property-name | type | mean | defaul value | +| ---------------- | -------- | ------------------------------------------------------ | ------------------------- | +| `entrypoint` | `string` | The entry point for Kroki server. | `'https://kroki.io'` | +| `containerClass` | `string` | class name of container (`DIV`-tag `class` attribute). | `'kroki-image-container'` | +| `imageFormat` | `string` | image format of diagram. see [here](https://kroki.io/) | `'svg'` | diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/demo/marp.config.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/demo/marp.config.js new file mode 100644 index 0000000..12e5fa9 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/demo/marp.config.js @@ -0,0 +1,8 @@ + +module.exports = { + inputDir: './', + engine: ({ marp }) => marp.use(require('../index'), { + entrypoint: "https://kroki.io", + marpAutoScaling: true + }) +} \ No newline at end of file diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/demo/test.md b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/demo/test.md new file mode 100644 index 0000000..9dca75a --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/demo/test.md @@ -0,0 +1,59 @@ +--- +marp: true +--- + +# @kazumatu981/markdown-it-kroki + +## Marp Sample + +--- + +## plantuml + +```plantuml[platuml image] +@startuml +left to right direction +actor Guest as g +package Professional { + actor Chef as c + actor "Food Critic" as fc +} +package Restaurant { + usecase "Eat Food" as UC1 + usecase "Pay for Food" as UC2 + usecase "Drink" as UC3 + usecase "Review" as UC4 +} +fc --> UC4 +g --> UC1 +g --> UC2 +g --> UC3 +@enduml +``` + +--- + +## mermaid + +```mermaid[mermaid image] +graph TD + A[ Anyone ] -->|Can help | B( Go to github.com/yuzutech/kroki ) + B --> C{ How to contribute? } + C --> D[ Reporting bugs ] + C --> E[ Sharing ideas ] + C --> F[ Advocating ] +``` + +--- + +## normal code + +```JavaScript +function testFunc(test) { + let sum = 0; + for(let x = 1; x<=test; x++) { + sum += x; + } + return sum; +} +``` \ No newline at end of file diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/img/plantuml-sample.png b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/img/plantuml-sample.png new file mode 100644 index 0000000..6db8131 Binary files /dev/null and b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/img/plantuml-sample.png differ diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/index.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/index.js new file mode 100644 index 0000000..92ecdd1 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/index.js @@ -0,0 +1,6 @@ +const { MarkdownItKrokiCore } = require('./lib/plugin-core'); + +module.exports = (md, opt) => { + const plugin = new MarkdownItKrokiCore(md); + plugin.setOptions(opt).use(); +}; diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/contract.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/contract.js new file mode 100644 index 0000000..690c13a --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/contract.js @@ -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 { + require('url').parse(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); + } + } +}; diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/diagram-encoder.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/diagram-encoder.js new file mode 100644 index 0000000..e18b918 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/diagram-encoder.js @@ -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 +}; diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/obs/marp-it-kroki.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/obs/marp-it-kroki.js new file mode 100644 index 0000000..5c34e28 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/obs/marp-it-kroki.js @@ -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') + + // is working only with Marp Core v3 + return `

` + } + } + + return fence.call(self, tokens, idx, options, env, self) + } +} + +module.exports = marpKrokiPlugin diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/plugin-core.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/plugin-core.js new file mode 100644 index 0000000..60fcc65 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/plugin-core.js @@ -0,0 +1,74 @@ +'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._imageFormat = safeChoice(this._imageFormat, support.imageFormats, "svg"); + this._entrypoint = require('url').parse(this._entrypoint).href; + + contract.toBeClassName(this._containerClass, "containerClass must be className."); + + return this; + } + use() { + // if _md has `marpit` property then use 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 + const imgTag = langAndAlt.alt ? + `${alt}` : ``; + // build container contents + const containerContents = this._marpAutoScaling ? + `${imgTag}` : imgTag; + // build embed HTML + return `

${containerContents}

`; + } + 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 +} \ No newline at end of file diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/safe-property.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/safe-property.js new file mode 100644 index 0000000..953e305 --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/safe-property.js @@ -0,0 +1,18 @@ +'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; +} +function safeUrl(test) { + +} + +module.exports = { safeProperty, safeChoice }; diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/support.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/support.js new file mode 100644 index 0000000..e8144ae --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/lib/support.js @@ -0,0 +1,54 @@ +'use strict'; + +/** + * Diagram Languages are supported by kroki.io + */ +const LANGUAGES = [ + 'actdiag', + 'blockdiag', + 'bpmn', + 'bytefield', + 'c4plantuml', + 'ditaa', + 'dot', + '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) +}; \ No newline at end of file diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/package.json b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/package.json new file mode 100644 index 0000000..2ae5ecd --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/package.json @@ -0,0 +1,35 @@ +{ + "name": "@kazumatu981/markdown-it-kroki", + "version": "1.1.1", + "description": "markdown-it kroki plugin.", + "main": "index.js", + "scripts": { + "test": "mocha tests/**/*.test.js", + "demo": "marp -s -c demo/marp.config.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/kazumatu981/markdown-it-kroki.git" + }, + "keywords": [ + "markdown-it", + "markdown-it-plugin", + "kroki", + "marp", + "markdown" + ], + "author": "kazumatu981", + "license": "MIT", + "bugs": { + "url": "https://github.com/kazumatu981/markdown-it-kroki/issues" + }, + "homepage": "https://github.com/kazumatu981/markdown-it-kroki#readme", + "devDependencies": { + "@marp-team/marp-cli": "^2.2.0", + "chai": "^4.3.6", + "jsdom": "^20.0.1", + "markdown-it": "^13.0.1", + "mocha": "^10.1.0", + "nyc": "^15.1.0" + } +} \ No newline at end of file diff --git a/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/tests/securitytest/security.test.js b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/tests/securitytest/security.test.js new file mode 100644 index 0000000..eb8f20a --- /dev/null +++ b/down-the-stack-book/node_modules/@kazumatu981/markdown-it-kroki/tests/securitytest/security.test.js @@ -0,0 +1,94 @@ +const MarkdownIt = require('markdown-it'); +const { expect } = require('chai'); +const { JSDOM } = require('jsdom'); +const MarkdownItKroki = require('../../index'); + +describe('# [Security-test] anti-injecttion for syntax.', () => { + describe("## for alt", () => { + it('* escape double quote', () => { + const expected = 'this is a "test comment" test'; + + const md = new MarkdownIt(); + md.use(MarkdownItKroki, { + entrypoint: "https://kroki.io", + marpAutoScaling: true, + containerClass: "the-container" + }); + + const result = md.render( + '```graphviz [this is a "test comment" test]\r\n' + + 'digraph G {Hello->World}\r\n' + + '```\r\n' + ); + const dom = new JSDOM(result); + const imgTag = dom.window.document.getElementsByTagName("img")[0]; + const actual = imgTag.getAttribute('alt'); + + expect(actual).to.be.equal(expected); + }) + }) +}); +describe('# [Security-test] anti-injecttion for option.', () => { + describe("## for entrypoint", () => { + it('* deny invalid URL', () => { + const md = new MarkdownIt(); + md.use(MarkdownItKroki, { + entrypoint: "https://kroki.io\">