diff --git a/CHANGELOG.md b/CHANGELOG.md index d3d07a1..d766712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,3 +16,4 @@ - support for `mdconf.json`config file - MathJax script to html - `mdconfig.json` extensions with `extends: "name"` +- variables prefixed with `$` and system variables prefixed with `$$` diff --git a/README.md b/README.md index 7c7f987..889854b 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,32 @@ You can include your own stylesheet. It is applied after the default style. The [!stylesheet]: path/to/style.css ``` +## Variables + +Variables are prefixed with `$`. +You can define and use variables like this: + +Defining: +``` +$varname = value +$fruit = apple +``` + +Using: +``` +I'm eating an $fruit. +``` + +There are system variables that are prefixed with `$$`. +Currently you can use + +variable | value | example value +---------|-----------------|-------------- +$now | current datetime| 31.07.2019 21:03:47 +$date | current date | 31.07.2019 +$time | current time | 21:03:47 + + ## Configuration file You can also define plugins, stylesheets and other stuff by using a `mdconf.json` file in the same directory as the main markdown file. Example config: diff --git a/package-lock.json b/package-lock.json index 4c59a3c..cbbc577 100644 --- a/package-lock.json +++ b/package-lock.json @@ -954,6 +954,11 @@ "whatwg-url": "^7.0.0" } }, + "date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==" + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3448,6 +3453,11 @@ "resolved": "https://registry.npmjs.org/markdown-it-imsize/-/markdown-it-imsize-2.0.1.tgz", "integrity": "sha1-zKBCeQXQUziiR8ucqdloxc3dUXA=" }, + "markdown-it-inline-comments": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/markdown-it-inline-comments/-/markdown-it-inline-comments-1.0.1.tgz", + "integrity": "sha1-F26r5jGj4IElvXOVAPQ8UfUliW0=" + }, "markdown-it-ins": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-2.0.0.tgz", @@ -3476,6 +3486,11 @@ "resolved": "https://registry.npmjs.org/markdown-it-mathjax/-/markdown-it-mathjax-2.0.0.tgz", "integrity": "sha1-ritPTFxxmgP55HXGZPeyaFIx2ek=" }, + "markdown-it-modify-token": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/markdown-it-modify-token/-/markdown-it-modify-token-1.0.2.tgz", + "integrity": "sha1-VCRxoyMnClwQKmNbB/47R8J47qA=" + }, "markdown-it-multimd-table": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-3.2.2.tgz", diff --git a/package.json b/package.json index 2cd3478..243bdce 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@types/puppeteer": "^1.19.0", "argparse": "^1.0.10", "chokidar": "^3.0.2", + "date-format": "^2.1.0", "fs-extra": "^8.1.0", "jsdom": "^15.1.1", "line-by-line": "^0.1.6", @@ -46,11 +47,13 @@ "markdown-it-highlightjs": "^3.0.0", "markdown-it-implicit-figures": "^0.9.0", "markdown-it-imsize": "^2.0.1", + "markdown-it-inline-comments": "^1.0.1", "markdown-it-ins": "^2.0.0", "markdown-it-kbd": "^2.0.0", "markdown-it-mark": "^2.0.0", "markdown-it-math": "^4.1.1", "markdown-it-mathjax": "^2.0.0", + "markdown-it-modify-token": "^1.0.2", "markdown-it-multimd-table": "^3.2.2", "markdown-it-plantuml": "^1.4.1", "markdown-it-smartarrows": "^1.0.1", diff --git a/src/configs/full-mdconfig.json b/src/configs/full-mdconfig.json index 1102ab7..a7d4976 100644 --- a/src/configs/full-mdconfig.json +++ b/src/configs/full-mdconfig.json @@ -22,6 +22,7 @@ "header-sections", "task-checkbox", "underline", - "implicit-figures" + "implicit-figures", + "inline-comments" ] } diff --git a/src/lib/CommandParser.ts b/src/lib/PreFormatter.ts similarity index 72% rename from src/lib/CommandParser.ts rename to src/lib/PreFormatter.ts index 2f6c1d8..e9a341b 100644 --- a/src/lib/CommandParser.ts +++ b/src/lib/PreFormatter.ts @@ -6,11 +6,13 @@ import {pageFormats} from "./formats"; import {PDFFormat} from "puppeteer"; import {getMarkdownPlugin} from "./utils"; import {logger} from "./logger"; +import {globalVariables} from "./globvars"; -export class CommandParser { +export class PreFormatter { public projectFiles: string[]; public pageFormat: PDFFormat; public stylesheets: string[]; + public variables: any; private readonly resolvePath: {path: string, lines: number}[]; @@ -18,6 +20,7 @@ export class CommandParser { this.projectFiles = []; this.resolvePath = []; this.stylesheets = []; + this.variables = Object.assign({}, globalVariables); } async processCommands(doc: string, docpath: string, renderer: Renderer) { @@ -44,25 +47,26 @@ export class CommandParser { currentFile = this.resolvePath[this.resolvePath.length - 1]; } } - let match: RegExpExecArray = /\[ *!(\w+) *\]:? *(.*)/gu.exec(inputLine.replace(/\s/, '')); + let commandMatch: RegExpExecArray = /\[ *!(\w+) *\]:? *(.*)/g.exec(inputLine); + let variableMatch: RegExpExecArray = /\$(\w+) *= *(.*?) *$/g.exec(inputLine); - if (match && match[0]) { // TODO: stylesheets - switch(match[1]) { + if (commandMatch && commandMatch[0]) { + switch(commandMatch[1]) { case 'use': - let plugins = match[2].split(','); - logger.verbose(`Adding plugins: ${match[2]}`); + let plugins = commandMatch[2].split(','); + logger.verbose(`Adding plugins: ${commandMatch[2]}`); for (let mdPlugin of plugins) { renderer.addPlugin(getMarkdownPlugin(mdPlugin.replace(/^ *| *$/g, ''))); } break; case 'include': try { - if (!this.resolvePath.find(x => x.path === match[2])) { // if the include is in the path, it is a circular reference - let included = await this.getInclude(match[2], mainDir); + if (!this.resolvePath.find(x => x.path === commandMatch[2])) { // if the include is in the path, it is a circular reference + let included = await this.getInclude(commandMatch[2], mainDir); inputLines.unshift(...included); - this.resolvePath.push({path: match[2], lines: included.length}); + this.resolvePath.push({path: commandMatch[2], lines: included.length}); } else { - logger.warning(`Circular reference detected. Skipping include ${match[2]}`); + logger.warning(`Circular reference detected. Skipping include ${commandMatch[2]}`); } } catch (err) { logger.error(err.message); @@ -70,28 +74,40 @@ export class CommandParser { } break; case 'format': - if (!this.pageFormat && Object.values(pageFormats).includes(match[2])) + if (!this.pageFormat && Object.values(pageFormats).includes(commandMatch[2])) // @ts-ignore - this.pageFormat = match[2]; + this.pageFormat = commandMatch[2]; else - logger.warning('Invalid page format or format already set: ' + match[2]); + logger.warning('Invalid page format or format already set: ' + commandMatch[2]); break; case 'newpage': renderer.addPlugin(getMarkdownPlugin(markdownPlugins.div)); outputLines.push('::: .newpage \n:::'); break; case 'stylesheet': - await this.addStylesheet(match[2], mainDir); + await this.addStylesheet(commandMatch[2], mainDir); break; default: outputLines.push(inputLine); } + } else if (variableMatch) { + this.variables[variableMatch[1]] = variableMatch[2]; + logger.debug(`Added variable: "${variableMatch[1]}": "${variableMatch[2]}"`); } else { outputLines.push(inputLine); } } - return outputLines.join('\n'); + let documentContent = outputLines.join('\n'); + // replacing all variables with their values. + for (let [key, value] of Object.entries(this.variables)) { + let varReplacer: RegExp = new RegExp(`\\$${key}`, "gi"); + if (typeof value === "function") + value = await value(); + // @ts-ignore + documentContent = documentContent.replace(varReplacer, value); + } + return documentContent; } /** diff --git a/src/lib/Renderer.ts b/src/lib/Renderer.ts index 6ec5863..b71e2a6 100644 --- a/src/lib/Renderer.ts +++ b/src/lib/Renderer.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import * as chokidar from 'chokidar'; import * as puppeteer from 'puppeteer'; import {JSDOM} from 'jsdom'; -import {CommandParser} from "./CommandParser"; +import {PreFormatter} from "./PreFormatter"; import {EventEmitter} from "events"; import {PDFFormat} from "puppeteer"; import {MarkdownConfig} from "./MarkdownConfig"; @@ -15,7 +15,7 @@ export class Renderer extends EventEmitter { private md: MarkdownIt; private readonly beforeRendering: Function[]; private readonly afterRendering: Function[]; - private commandParser: CommandParser; + private commandParser: PreFormatter; private config: MarkdownConfig; constructor(config?: MarkdownConfig) { @@ -24,7 +24,7 @@ export class Renderer extends EventEmitter { this.md = new MarkdownIt(); this.beforeRendering = []; this.afterRendering = []; - this.commandParser = new CommandParser(); + this.commandParser = new PreFormatter(); this.configure(); } diff --git a/src/lib/globvars.ts b/src/lib/globvars.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/plugins.ts b/src/lib/plugins.ts index 9eb584f..db374a7 100644 --- a/src/lib/plugins.ts +++ b/src/lib/plugins.ts @@ -70,5 +70,8 @@ export const markdownPlugins: any = { options: { figcaption: true } + }, + 'inline-comments': { + module: 'markdown-it-inline-comments' } }; diff --git a/src/styles/default.sass b/src/styles/default.sass index f549476..259f541 100644 --- a/src/styles/default.sass +++ b/src/styles/default.sass @@ -36,6 +36,9 @@ figcaption margin: 0.5em font-style: italic +.footnote-backref + display: none + .page page-break-before: always page-break-after: always