diff --git a/docs/userGuide/syntax/variables.mbdf b/docs/userGuide/syntax/variables.mbdf index 168ba3b47f..4b712f4bc9 100644 --- a/docs/userGuide/syntax/variables.mbdf +++ b/docs/userGuide/syntax/variables.mbdf @@ -172,6 +172,26 @@ However, this is a combination of *both* syntaxes above, and thus this will allo +### Defining variables with JSON + +You could also have your variables defined in a JSON file to define multiple variables in a more concise manner. + +{{ icon_example }} +`variables.md`: +```html + +``` + +`variables.json`: +```json +{ + "variable1": "This is the first variable", + "variable2": "This is the second variable" +} +``` + +Variables defined in JSON file will be scoped according to where it is being referenced. + ### Variables: Tips and Tricks **Variables can refer to other variables** that are declared earlier, including built-in variables. @@ -218,6 +238,25 @@ You must use the `safe` filter when using such variables: {{ const_note }} :fas-arrow-right: Note: This is a constant. +When defining variables with incomplete HTML fragments, we can define variables as a separate JSON file. + +{{ icon_example }} variables containing HTML fragments:
+ +`index.md`: +```html + +``` + +`variableFileName.json`: +```json +{ + "back_fragment": "Back", + "front_fragment": "
Front" +} +``` + +{{ front_fragment }} and {{ back_fragment }} :fas-arrow-right: Front and Back + Global variables: diff --git a/src/Site.js b/src/Site.js index d8fc4eb3ed..92fc785280 100644 --- a/src/Site.js +++ b/src/Site.js @@ -503,10 +503,10 @@ class Site { this.baseUrlMap.forEach((base) => { const userDefinedVariables = {}; Object.assign(userDefinedVariables, markbindVariable); - + const userDefinedVariablesPath = path.resolve(base, USER_VARIABLES_PATH); + const userDefinedVariablesDir = path.dirname(userDefinedVariablesPath); let content; try { - const userDefinedVariablesPath = path.resolve(base, USER_VARIABLES_PATH); content = fs.readFileSync(userDefinedVariablesPath, 'utf8'); } catch (e) { content = ''; @@ -521,9 +521,27 @@ class Site { const $ = cheerio.load(content); $('variable,span').each(function () { const name = $(this).attr('name') || $(this).attr('id'); - // Process the content of the variable with nunjucks, in case it refers to other variables. - const html = nunjuckUtils.renderEscaped(nunjucks, $(this).html(), userDefinedVariables); - userDefinedVariables[name] = html; + const variableSource = $(this).attr('from'); + + if (variableSource !== undefined) { + try { + const variableFilePath = path.resolve(userDefinedVariablesDir, variableSource); + const jsonData = fs.readFileSync(variableFilePath); + const varData = JSON.parse(jsonData); + Object.entries(varData).forEach(([varName, varValue]) => { + // Process the content of the variable with nunjucks, in case it refers to other variables. + const variableValue = nunjuckUtils.renderEscaped(nunjucks, varValue, userDefinedVariables); + + userDefinedVariables[varName] = variableValue; + }); + } catch (err) { + logger.warn(`Error ${err.message}`); + } + } else { + // Process the content of the variable with nunjucks, in case it refers to other variables. + const html = nunjuckUtils.renderEscaped(nunjucks, $(this).html(), userDefinedVariables); + userDefinedVariables[name] = html; + } }); }); } diff --git a/src/lib/markbind/src/parser.js b/src/lib/markbind/src/parser.js index 97ec8811c3..32a1dec330 100644 --- a/src/lib/markbind/src/parser.js +++ b/src/lib/markbind/src/parser.js @@ -8,6 +8,7 @@ const slugify = require('@sindresorhus/slugify'); const componentParser = require('./parsers/componentParser'); const componentPreprocessor = require('./preprocessors/componentPreprocessor'); const nunjuckUtils = require('./utils/nunjuckUtils'); +const logger = require('../../../util/logger'); const _ = {}; _.clone = require('lodash/clone'); @@ -67,6 +68,7 @@ class Parser { */ // eslint-disable-next-line class-methods-use-this extractPageVariables(fileName, data, userDefinedVariables, includedVariables) { + const fileDir = path.dirname(fileName); const $ = cheerio.load(data); const pageVariables = {}; Parser.VARIABLE_LOOKUP.set(fileName, new Map()); @@ -92,21 +94,42 @@ class Parser { importedVariables[name] = `{{${alias}.${name}}}`; }); }); - $('variable').each(function () { - const variableElement = $(this); - const variableName = variableElement.attr('name'); - if (!variableName) { - // eslint-disable-next-line no-console - console.warn(`Missing 'name' for variable in ${fileName}\n`); - return; - } + const setPageVariable = (variableName, rawVariableValue) => { + const otherVariables = { + ...importedVariables, + ...pageVariables, + ...userDefinedVariables, + ...includedVariables, + }; + const variableValue = nunjuckUtils.renderEscaped(nunjucks, rawVariableValue, otherVariables); if (!pageVariables[variableName]) { - const variableValue = nunjuckUtils.renderEscaped(nunjucks, md.renderInline(variableElement.html()), { - ...importedVariables, ...pageVariables, ...userDefinedVariables, ...includedVariables, - }); pageVariables[variableName] = variableValue; Parser.VARIABLE_LOOKUP.get(fileName).set(variableName, variableValue); } + }; + $('variable').each(function () { + const variableElement = $(this); + const variableName = variableElement.attr('name'); + const variableSource = $(this).attr('from'); + if (variableSource !== undefined) { + try { + const variableFilePath = path.resolve(fileDir, variableSource); + const jsonData = fs.readFileSync(variableFilePath); + const varData = JSON.parse(jsonData); + Object.entries(varData).forEach(([varName, varValue]) => { + setPageVariable(varName, varValue); + }); + } catch (err) { + logger.warn(`Error ${err.message}`); + } + } else { + if (!variableName) { + // eslint-disable-next-line no-console + console.warn(`Missing 'name' for variable in ${fileName}\n`); + return; + } + setPageVariable(variableName, md.renderInline(variableElement.html())); + } }); return { ...importedVariables, ...pageVariables }; } diff --git a/src/template/default/_markbind/variables.json b/src/template/default/_markbind/variables.json new file mode 100644 index 0000000000..04d0b977d3 --- /dev/null +++ b/src/template/default/_markbind/variables.json @@ -0,0 +1,3 @@ +{ + "jsonVariableExample": "Your variables can be defined here as well" +} \ No newline at end of file diff --git a/src/template/default/_markbind/variables.md b/src/template/default/_markbind/variables.md index d1f129e068..aab37f29a9 100644 --- a/src/template/default/_markbind/variables.md +++ b/src/template/default/_markbind/variables.md @@ -1,4 +1,6 @@ To inject this HTML segment in your markbind files, use {{ example }} where you want to place it. More generally, surround the segment's id with double curly braces. - \ No newline at end of file + + + \ No newline at end of file diff --git a/src/template/minimal/_markbind/variables.json b/src/template/minimal/_markbind/variables.json new file mode 100644 index 0000000000..04d0b977d3 --- /dev/null +++ b/src/template/minimal/_markbind/variables.json @@ -0,0 +1,3 @@ +{ + "jsonVariableExample": "Your variables can be defined here as well" +} \ No newline at end of file diff --git a/src/template/minimal/_markbind/variables.md b/src/template/minimal/_markbind/variables.md index d1f129e068..aab37f29a9 100644 --- a/src/template/minimal/_markbind/variables.md +++ b/src/template/minimal/_markbind/variables.md @@ -1,4 +1,6 @@ To inject this HTML segment in your markbind files, use {{ example }} where you want to place it. More generally, surround the segment's id with double curly braces. - \ No newline at end of file + + + \ No newline at end of file diff --git a/test/functional/test_site/_markbind/variable.json b/test/functional/test_site/_markbind/variable.json new file mode 100644 index 0000000000..c067e2283c --- /dev/null +++ b/test/functional/test_site/_markbind/variable.json @@ -0,0 +1,6 @@ +{ + "back": "back
", + "front": "
front", + "jsonVar1": "Json Variable can be referenced", + "jsonVar2": "Referencing jsonVar1: {{ jsonVar1 }}" +} \ No newline at end of file diff --git a/test/functional/test_site/_markbind/variables.md b/test/functional/test_site/_markbind/variables.md index 657b47c1f5..d4d6518125 100644 --- a/test/functional/test_site/_markbind/variables.md +++ b/test/functional/test_site/_markbind/variables.md @@ -9,3 +9,4 @@ Global Variable Overriding Included Variable Global Variable Global Variable Overriding Page Variable + \ No newline at end of file diff --git a/test/functional/test_site/expected/_markbind/variable.json b/test/functional/test_site/expected/_markbind/variable.json new file mode 100644 index 0000000000..79f0b587ab --- /dev/null +++ b/test/functional/test_site/expected/_markbind/variable.json @@ -0,0 +1,6 @@ +{ + "front": "
front", + "back": "back
", + "jsonVar1": "Json Variable can be referenced", + "jsonVar2": "Referencing jsonVar1: {{ jsonVar1 }}" +} \ No newline at end of file diff --git a/test/functional/test_site/expected/index.html b/test/functional/test_site/expected/index.html index 11dd6e2145..c2bbb61994 100644 --- a/test/functional/test_site/expected/index.html +++ b/test/functional/test_site/expected/index.html @@ -150,12 +150,16 @@

Testing Site-Nav[1]

Inline footnotes: Here is an inline note.[3]

+

Json Variable

+
front back
+

Json Variable can be referenced Referencing jsonVar1: Json Variable can be referenced

Variables that reference another variable

This variable can be referenced.

References can be several levels deep.

Page Variable

- Page Variable +
+

Page Variable Json Variable

Page Variable with HTML and MD

Page Variable with HTML and Markdown diff --git a/test/functional/test_site/expected/jsonPageVariable.json b/test/functional/test_site/expected/jsonPageVariable.json new file mode 100644 index 0000000000..28d96f5cd7 --- /dev/null +++ b/test/functional/test_site/expected/jsonPageVariable.json @@ -0,0 +1,3 @@ +{ + "json_page_variable": "Json Variable" +} \ No newline at end of file diff --git a/test/functional/test_site/index.md b/test/functional/test_site/index.md index d36f7f8261..06c35acb8d 100644 --- a/test/functional/test_site/index.md +++ b/test/functional/test_site/index.md @@ -18,6 +18,12 @@ tags: ["tag-frontmatter-shown", "tag-included-file", "+tag-exp*", "-tag-exp-hidd +**Json Variable** + +{{ front }} {{ back }} + +{{ jsonVar1 }} {{ jsonVar2 }} + **Variables that reference another variable** {{finalized_value}} @@ -27,7 +33,9 @@ tags: ["tag-frontmatter-shown", "tag-included-file", "+tag-exp*", "-tag-exp-hidd **Page Variable** Page Variable -{{ page_variable }} + + +{{ page_variable }} {{ json_page_variable }} **Page Variable with HTML and MD** diff --git a/test/functional/test_site/jsonPageVariable.json b/test/functional/test_site/jsonPageVariable.json new file mode 100644 index 0000000000..28d96f5cd7 --- /dev/null +++ b/test/functional/test_site/jsonPageVariable.json @@ -0,0 +1,3 @@ +{ + "json_page_variable": "Json Variable" +} \ No newline at end of file diff --git a/test/functional/test_site_convert/expected/_markbind/variables.json b/test/functional/test_site_convert/expected/_markbind/variables.json new file mode 100644 index 0000000000..04d0b977d3 --- /dev/null +++ b/test/functional/test_site_convert/expected/_markbind/variables.json @@ -0,0 +1,3 @@ +{ + "jsonVariableExample": "Your variables can be defined here as well" +} \ No newline at end of file diff --git a/test/functional/test_site_templates/test_default/expected/_markbind/variables.json b/test/functional/test_site_templates/test_default/expected/_markbind/variables.json new file mode 100644 index 0000000000..04d0b977d3 --- /dev/null +++ b/test/functional/test_site_templates/test_default/expected/_markbind/variables.json @@ -0,0 +1,3 @@ +{ + "jsonVariableExample": "Your variables can be defined here as well" +} \ No newline at end of file diff --git a/test/functional/test_site_templates/test_minimal/expected/_markbind/variables.json b/test/functional/test_site_templates/test_minimal/expected/_markbind/variables.json new file mode 100644 index 0000000000..04d0b977d3 --- /dev/null +++ b/test/functional/test_site_templates/test_minimal/expected/_markbind/variables.json @@ -0,0 +1,3 @@ +{ + "jsonVariableExample": "Your variables can be defined here as well" +} \ No newline at end of file diff --git a/test/unit/parser.test.js b/test/unit/parser.test.js index c8e16b8640..b67f86cd4d 100644 --- a/test/unit/parser.test.js +++ b/test/unit/parser.test.js @@ -4,6 +4,7 @@ const MarkBind = require('../../src/lib/markbind/src/parser.js'); const { USER_VARIABLES_DEFAULT } = require('./utils/data'); jest.mock('fs'); +jest.mock('../../src/util/logger'); afterEach(() => fs.vol.reset());