diff --git a/package-lock.json b/package-lock.json index 257fe4e746..658b6dcf46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2255,11 +2255,6 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, - "ejs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.0.1.tgz", - "integrity": "sha512-cuIMtJwxvzumSAkqaaoGY/L6Fc/t6YvoP9/VIaK0V/CyqKLEQ8sqODmYfy/cjXEdZ9+OOL8TecbJu+1RsofGDw==" - }, "electron-to-chromium": { "version": "1.3.322", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", diff --git a/package.json b/package.json index f5e7b2adab..1a7855ff34 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "cheerio": "^0.22.0", "chokidar": "^3.3.0", "commander": "^3.0.2", - "ejs": "^3.0.1", "fastmatter": "^2.1.1", "figlet": "^1.2.4", "find-up": "^4.1.0", diff --git a/src/Page.js b/src/Page.js index 8ee0af33f3..31a3a704c0 100644 --- a/src/Page.js +++ b/src/Page.js @@ -827,7 +827,7 @@ Page.prototype.generate = function (builtFiles) { this.buildPageNav(); return fs.outputFileAsync(this.resultPath, htmlBeautify( - this.template(this.prepareTemplateData()), + this.template.render(this.prepareTemplateData()), { indent_size: 2 }, )); }) diff --git a/src/Site.js b/src/Site.js index 4e2c22e718..2334f9c7c0 100644 --- a/src/Site.js +++ b/src/Site.js @@ -1,5 +1,4 @@ const cheerio = require('cheerio'); -const ejs = require('ejs'); const fs = require('fs-extra-promise'); const ghpages = require('gh-pages'); const ignore = require('ignore'); @@ -112,7 +111,8 @@ function Site(rootPath, outputPath, onePagePath, forceReload = false, siteConfig // Page template path this.pageTemplatePath = path.join(__dirname, PAGE_TEMPLATE_NAME); - this.pageTemplate = ejs.compile(fs.readFileSync(this.pageTemplatePath, 'utf8')); + const env = nunjucks.configure({ autoescape: false }); + this.pageTemplate = nunjucks.compile(fs.readFileSync(this.pageTemplatePath, 'utf8'), env); this.pages = []; // Other properties diff --git a/src/constants.js b/src/constants.js index 58872e2e2e..903e603ff0 100644 --- a/src/constants.js +++ b/src/constants.js @@ -46,7 +46,7 @@ module.exports = { FOOTER_PATH: '_markbind/footers/footer.md', INDEX_MARKDOWN_FILE: 'index.md', MARKBIND_PLUGIN_PREFIX: 'markbind-plugin-', - PAGE_TEMPLATE_NAME: 'page.ejs', + PAGE_TEMPLATE_NAME: 'page.njk', PROJECT_PLUGIN_FOLDER_NAME: '_markbind/plugins', SITE_CONFIG_NAME: 'site.json', SITE_DATA_NAME: 'siteData.json', diff --git a/src/page.ejs b/src/page.ejs deleted file mode 100644 index d85e19e29b..0000000000 --- a/src/page.ejs +++ /dev/null @@ -1,59 +0,0 @@ - - - - <%- headFileTopContent %> - - - - - <%= title %> - - - - - - -<% if (asset.pluginLinks) { -%> -<% for (const link of asset.pluginLinks) { -%> - <%- link %> -<% } -%> -<% } -%> - - <% if (siteNav) { %><% } %> - <% if (pageNav) { %><% } %> - <%- headFileBottomContent %> - <% if (faviconUrl) { %><% } %> - - data-spy="scroll" data-target="#page-nav" data-offset="100" <%_ } %>> -
- <%- headerHtml _%> -
- <%- siteNavHtml _%> - <%- content %> - <%- pageNavHtml _%> -
- <%- footerHtml _%> -
- - - - - - - - -<% if (asset.externalScripts) { -%> -<% for (const script of asset.externalScripts) { -%> - -<% } -%> -<% } -%> -<% if (asset.pluginScripts) { -%> -<% for (const script of asset.pluginScripts) { -%> -<%- script %> -<% } -%> -<% } -%> - - diff --git a/src/page.njk b/src/page.njk new file mode 100644 index 0000000000..c0a8860e6e --- /dev/null +++ b/src/page.njk @@ -0,0 +1,68 @@ + + + + {{ headFileTopContent }} + + + + + {{ title }} + + + + + + + {%- if asset.pluginLinks %} + {%- for link in asset.pluginLinks %} + {{ link }} + {%- endfor %} + {%- endif %} + + {%- if siteNav %} + + {%- endif %} + {%- if pageNav %} + + {%- endif %} + {{ headFileBottomContent }} + {%- if faviconUrl %} + + {%- endif %} + + +
+ {{ headerHtml }} +
+ {{ siteNavHtml }} + {{ content }} + {{ pageNavHtml }} +
+ {{ footerHtml }} +
+ + + + + + + + + +{%- if asset.externalScripts %} +{%- for script in asset.externalScripts %} + +{%- endfor %} +{%- endif %} + +{%- if asset.pluginScripts %} +{%- for script in asset.pluginScripts %} + {{ script }} +{%- endfor %} +{%- endif %} + + + diff --git a/test/unit/Site.test.js b/test/unit/Site.test.js index 4dbf6f8c85..43b6f390f0 100644 --- a/test/unit/Site.test.js +++ b/test/unit/Site.test.js @@ -8,7 +8,7 @@ const { FOOTER_MD_DEFAULT, HEADER_MD_DEFAULT, INDEX_MD_DEFAULT, - PAGE_EJS, + PAGE_NJK, SITE_JSON_DEFAULT, SITE_NAV_MD_DEFAULT, TOP_NAV_DEFAULT, @@ -29,7 +29,7 @@ afterEach(() => fs.vol.reset()); test('Site Generate builds the correct amount of assets', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'inner/site.json': SITE_JSON_DEFAULT, 'asset/css/bootstrap.min.css': '', @@ -102,7 +102,7 @@ test('Site Generate builds the correct amount of assets', async () => { test('Site Init with invalid template fails', async () => { // Mock default template in MemFS without site config const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'src/template/default/index.md': INDEX_MD_DEFAULT, }; @@ -121,7 +121,7 @@ test('Site Init does not overwrite existing files', async () => { // Mock default template in MemFS const json = { 'index.md': EXISTING_INDEX_MD, - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'src/template/default/index.md': INDEX_MD_DEFAULT, 'src/template/default/site.json': SITE_JSON_DEFAULT, }; @@ -135,7 +135,7 @@ test('Site Init does not overwrite existing files', async () => { test('Site Init in existing directory generates correct assets', async () => { // Mock default template in MemFS const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'src/template/default/index.md': INDEX_MD_DEFAULT, 'src/template/default/site.json': SITE_JSON_DEFAULT, 'src/template/default/_markbind/boilerplates/': '', @@ -199,7 +199,7 @@ test('Site Init in existing directory generates correct assets', async () => { test('Site Init in directory which does not exist generates correct assets', async () => { // Mock default template in MemFS const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'src/template/default/index.md': INDEX_MD_DEFAULT, 'src/template/default/site.json': SITE_JSON_DEFAULT, 'src/template/default/_markbind/boilerplates/': '', @@ -265,7 +265,7 @@ test('Site Init in directory which does not exist generates correct assets', asy test('Site baseurls are correct for sub nested subsites', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, 'sub/site.json': SITE_JSON_DEFAULT, 'sub/sub/site.json': SITE_JSON_DEFAULT, @@ -282,7 +282,7 @@ test('Site baseurls are correct for sub nested subsites', async () => { test('Site removeAsync removes the correct asset', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, '_site/toRemove.jpg': '', '_site/dontRemove.png': '', 'toRemove.html': '', @@ -297,7 +297,7 @@ test('Site removeAsync removes the correct asset', async () => { test('Site read site config for default', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, }; fs.vol.fromJSON(json, ''); @@ -329,7 +329,7 @@ test('Site read site config for custom site config', async () => { enableSearch: true, }; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': JSON.stringify(customSiteJson), }; fs.vol.fromJSON(json, ''); @@ -341,7 +341,7 @@ test('Site read site config for custom site config', async () => { test('Site resolves variables referencing other variables', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, '_markbind/variables.md': 'variable' @@ -361,17 +361,13 @@ test('Site resolves variables referencing other variables', async () => { expect(root.level1).toEqual('variable'); expect(root.level2).toEqual('variable'); const expectedTextSpan = 'Blue text'; - const expectedTextSpanEscaped = expectedTextSpan - .replace(/"/g, '"') - .replace(//g, '>'); expect(root.level3).toEqual(expectedTextSpan); - expect(root.level4).toEqual(expectedTextSpanEscaped); + expect(root.level4).toEqual(expectedTextSpan); }); test('Site read correct user defined variables', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, 'sub/site.json': SITE_JSON_DEFAULT, 'sub/sub/site.json': SITE_JSON_DEFAULT, @@ -414,7 +410,7 @@ test('Site read correct user defined variables', async () => { test('Site convert generates correct assets', async () => { // Mock default template in MemFS const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'src/template/default/index.md': INDEX_MD_DEFAULT, 'src/template/default/site.json': SITE_JSON_DEFAULT, 'src/template/default/_markbind/boilerplates/': '', @@ -467,7 +463,7 @@ test('Site convert generates correct assets', async () => { test('Site convert with custom _Footer.md, no _Sidebar.md, README.md generates correct assets', async () => { // Mock default template in MemFS const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'src/template/default/index.md': INDEX_MD_DEFAULT, 'src/template/default/site.json': SITE_JSON_DEFAULT, 'src/template/default/_markbind/boilerplates/': '', @@ -523,7 +519,7 @@ test('Site convert with custom _Footer.md, no _Sidebar.md, README.md generates c test('Site deploys with default settings', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, _site: {}, }; @@ -543,7 +539,7 @@ test('Site deploys with custom settings', async () => { branch: 'master', }; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': JSON.stringify(customConfig), _site: {}, }; @@ -557,7 +553,7 @@ test('Site deploys with custom settings', async () => { test('Site should not deploy without a built site', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, }; fs.vol.fromJSON(json, ''); @@ -591,7 +587,7 @@ describe('Site deploy with Travis', () => { process.env.TRAVIS_REPO_SLUG = 'TRAVIS_USER/TRAVIS_REPO'; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, _site: {}, }; @@ -611,7 +607,7 @@ describe('Site deploy with Travis', () => { const customRepoConfig = JSON.parse(SITE_JSON_DEFAULT); customRepoConfig.deploy.repo = 'https://github.com/USER/REPO.git'; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': JSON.stringify(customRepoConfig), _site: {}, }; @@ -628,7 +624,7 @@ describe('Site deploy with Travis', () => { process.env.TRAVIS_REPO_SLUG = 'TRAVIS_USER/TRAVIS_REPO.github.io'; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, _site: {}, }; @@ -641,7 +637,7 @@ describe('Site deploy with Travis', () => { test('Site deploy -t/--travis should not deploy if not in Travis', async () => { const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, _site: {}, }; @@ -656,7 +652,7 @@ describe('Site deploy with Travis', () => { process.env.TRAVIS = true; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': SITE_JSON_DEFAULT, _site: {}, }; @@ -674,7 +670,7 @@ describe('Site deploy with Travis', () => { const invalidRepoConfig = JSON.parse(SITE_JSON_DEFAULT); invalidRepoConfig.deploy.repo = 'INVALID_GITHUB_REPO'; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'site.json': JSON.stringify(invalidRepoConfig), _site: {}, }; @@ -792,7 +788,7 @@ siteJsonResolvePropertiesTestCases.forEach((testCase) => { }, }; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'index.md': '', }; fs.vol.fromJSON(json, ''); @@ -828,7 +824,7 @@ test('Site config throws error on duplicate page src', async () => { }, }; const json = { - 'src/page.ejs': PAGE_EJS, + 'src/page.njk': PAGE_NJK, 'index.md': '', }; fs.vol.fromJSON(json, ''); diff --git a/test/unit/utils/data.js b/test/unit/utils/data.js index 8fa0a88abb..60852febb2 100644 --- a/test/unit/utils/data.js +++ b/test/unit/utils/data.js @@ -7,44 +7,52 @@ module.exports.LAYOUT_FILES_DEFAULT = [ ]; module.exports.LAYOUT_SCRIPTS_DEFAULT = '// eslint-disable-next-line no-undef\n' -+ 'MarkBind.afterSetup(() => {\n' -+ ' // Include code to be called after MarkBind setup here.\n' -+ '});\n'; + + 'MarkBind.afterSetup(() => {\n' + + ' // Include code to be called after MarkBind setup here.\n' + + '});\n'; -module.exports.PAGE_EJS = '\n' - + '\n' - + '\n' - + ' <%- headFileTopContent %>\n' - + ' \n' - + ' \n' - + ' \n' - + ' <%= title %>\n' - + ' \n' - + ' \n' - + ' \n' - + ' \n' - + ' \n' - + ' \n' - + ' \n' - + ' <% if (siteNav) { %><% } %>\n' - + ' <%- headFileBottomContent %>\n' - + ' <% if (faviconUrl) { %><% } %>\n' - + '\n' - + '\n' - + '
\n' - + ' <%- content %>\n' - + '
\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n' - + '\n'; +module.exports.PAGE_NJK = ` + + + + {{ headFileTopContent }} + + + + + {{ title }} + + + + + + + + {% if siteNav %} + + {% endif %} + {{ headFileBottomContent }} + {% if faviconUrl %} + + {% endif %} + + +
+ {{ content }} +
+ + + + + + + + + + +`; module.exports.SITE_JSON_DEFAULT = '{\n' + ' "baseUrl": "",\n'