@antora/page-composer
Advanced tools
Comparing version 2.3.0-beta.2 to 2.3.0-rc.1
@@ -9,4 +9,25 @@ 'use strict' | ||
function buildBaseUiModel (playbook, contentCatalog, env) { | ||
const contentCatalogModel = contentCatalog.exportToModel() | ||
return { | ||
antoraVersion: VERSION, | ||
contentCatalog: contentCatalogModel, | ||
env, | ||
site: buildSiteUiModel(playbook, contentCatalogModel), | ||
} | ||
} | ||
function buildUiModel (baseUiModel, file, contentCatalog, navigationCatalog) { | ||
const siteUiModel = baseUiModel.site | ||
const siteRootPath = file.pub.rootPath || siteUiModel.path || '' | ||
const uiRootPath = siteRootPath + siteUiModel.ui.url | ||
return Object.assign({}, baseUiModel, { | ||
page: buildPageUiModel(siteUiModel, file, contentCatalog, navigationCatalog), | ||
siteRootPath, | ||
uiRootPath, | ||
}) | ||
} | ||
function buildSiteUiModel (playbook, contentCatalog) { | ||
const model = { title: playbook.site.title, contentCatalog: contentCatalog.exportToModel() } | ||
const model = { title: playbook.site.title } | ||
@@ -32,10 +53,5 @@ let siteUrl = playbook.site.url | ||
// QUESTION should components be pre-sorted? should we make this configurable? | ||
model.components = contentCatalog.getComponentMapSortedBy('title') | ||
model.components = contentCatalog.getComponentsSortedBy('title').reduce((map, it) => (map[it.name] = it) && map, {}) | ||
model.keys = Object.assign({}, playbook.site.keys) | ||
model.keys = Object.entries(playbook.site.keys || {}).reduce((accum, [key, value]) => { | ||
if (value) accum[key] = value | ||
return accum | ||
}, {}) | ||
const uiConfig = playbook.ui | ||
@@ -50,19 +66,7 @@ model.ui = { | ||
function buildUiModel (siteModel, file, contentCatalog, navigationCatalog, env) { | ||
const siteRootPath = file.pub.rootPath || siteModel.path || '' | ||
return { | ||
antoraVersion: VERSION, | ||
env, | ||
page: buildPageUiModel(siteModel, file, contentCatalog, navigationCatalog), | ||
site: siteModel, | ||
siteRootPath, | ||
uiRootPath: siteRootPath + siteModel.ui.url, | ||
} | ||
} | ||
function buildPageUiModel (siteUiModel, file, contentCatalog, navigationCatalog) { | ||
const fileSrc = file.src | ||
if (fileSrc.stem === '404' && !fileSrc.component) return { layout: '404', title: file.title } | ||
const { component: componentName, version, module: module_, relative: srcPath, origin, editUrl, fileUri } = fileSrc | ||
function buildPageUiModel (siteModel, file, contentCatalog, navigationCatalog) { | ||
const { component: componentName, version, stem } = file.src | ||
if (!componentName && stem === '404') return { layout: stem, title: file.title } | ||
// QUESTION should attributes be scoped to AsciiDoc, or should this work regardless of markup language? file.data? | ||
@@ -80,8 +84,8 @@ const asciidoc = file.asciidoc || {} | ||
// QUESTION can we cache versions on file.rel so only computed once per page version lineage? | ||
const versions = component.versions.length > 1 ? getPageVersions(file.src, component, contentCatalog) : undefined | ||
const title = asciidoc.doctitle | ||
const versions = component.versions.length > 1 ? getPageVersions(fileSrc, component, contentCatalog) : undefined | ||
const title = file.title || asciidoc.doctitle | ||
const model = { | ||
contents: file.contents, | ||
layout: pageAttributes.layout || siteModel.ui.defaultLayout, | ||
layout: pageAttributes.layout || siteUiModel.ui.defaultLayout, | ||
title, | ||
@@ -96,9 +100,9 @@ url, | ||
componentVersion, | ||
module: file.src.module, | ||
srcPath: file.src.relative, | ||
origin: file.src.origin, | ||
module: module_, | ||
srcPath, | ||
origin, | ||
versions, | ||
editUrl: file.src.editUrl, | ||
fileUri: file.src.fileUri, | ||
home: url === siteModel.homeUrl, | ||
editUrl, | ||
fileUri, | ||
home: url === siteUiModel.homeUrl, | ||
} | ||
@@ -119,3 +123,3 @@ | ||
// NOTE site URL has already been normalized at this point | ||
const siteUrl = siteModel.url | ||
const siteUrl = siteUiModel.url | ||
if (siteUrl && siteUrl.charAt() !== '/') { | ||
@@ -217,2 +221,2 @@ if (versions) { | ||
module.exports = { buildSiteUiModel, buildPageUiModel, buildUiModel } | ||
module.exports = { buildBaseUiModel, buildSiteUiModel, buildPageUiModel, buildUiModel } |
@@ -5,3 +5,2 @@ 'use strict' | ||
DEFAULT_LAYOUT_NAME: 'default', | ||
HANDLEBARS_COMPILE_OPTIONS: Object.freeze({ preventIndent: true }), | ||
}) |
'use strict' | ||
const { buildSiteUiModel, buildUiModel } = require('./build-ui-model') | ||
const { buildBaseUiModel, buildUiModel } = require('./build-ui-model') | ||
const handlebars = require('handlebars') | ||
const relativizeHelper = require('./helpers/relativize') | ||
const resolvePageHelper = require('./helpers/resolve-page') | ||
const resolvePageURLHelper = require('./helpers/resolve-page-url') | ||
const relativize = require('./helpers/relativize') | ||
const resolvePage = require('./helpers/resolve-page') | ||
const resolvePageURL = require('./helpers/resolve-page-url') | ||
const requireFromString = require('require-from-string') | ||
const { HANDLEBARS_COMPILE_OPTIONS } = require('./constants') | ||
/** | ||
@@ -31,23 +29,22 @@ * Generates a function to wrap the page contents in a page layout. | ||
function createPageComposer (playbook, contentCatalog, uiCatalog, env = process.env) { | ||
handlebars.registerHelper('relativize', relativizeHelper) | ||
handlebars.registerHelper('resolvePage', resolvePageHelper) | ||
handlebars.registerHelper('resolvePageURL', resolvePageURLHelper) | ||
handlebars.registerHelper('relativize', relativize) | ||
handlebars.registerHelper('resolvePage', resolvePage) | ||
handlebars.registerHelper('resolvePageURL', resolvePageURL) | ||
uiCatalog | ||
.findByType('helper') | ||
.forEach((file) => handlebars.registerHelper(file.stem, requireFromString(file.contents.toString(), file.path))) | ||
uiCatalog.findByType('partial').forEach((file) => handlebars.registerPartial(file.stem, file.contents.toString())) | ||
.forEach(({ path, stem, contents }) => | ||
handlebars.registerHelper(stem, requireFromString(contents.toString(), path)) | ||
) | ||
uiCatalog.findByType('partial').forEach(({ stem, contents }) => handlebars.registerPartial(stem, contents.toString())) | ||
const layouts = uiCatalog | ||
.findByType('layout') | ||
.reduce( | ||
(accum, file) => accum.set(file.stem, handlebars.compile(file.contents.toString(), HANDLEBARS_COMPILE_OPTIONS)), | ||
(accum, { path: srcName, stem, contents }) => | ||
accum.set(stem, handlebars.compile(contents.toString(), { preventIndent: true, srcName })), | ||
new Map() | ||
) | ||
return createPageComposerInternal(buildSiteUiModel(playbook, contentCatalog), env, layouts) | ||
return createPageComposerInternal(buildBaseUiModel(playbook, contentCatalog, env), layouts) | ||
} | ||
function createPageComposerInternal (siteModel, env, layouts) { | ||
function createPageComposerInternal (baseUiModel, layouts) { | ||
/** | ||
@@ -66,3 +63,3 @@ * Wraps the embeddable HTML contents of the specified file in a page layout. | ||
* @param {ContentCatalog} contentCatalog - The content catalog | ||
* that provides access to the virtual files in the site. | ||
* that provides access to the virtual files in the site (ignored). | ||
* @param {NavigationCatalog} navigationCatalog - The navigation catalog | ||
@@ -72,10 +69,9 @@ * that provides access to the navigation for each component version. | ||
*/ | ||
return function composePage (file, contentCatalog, navigationCatalog) { | ||
return function composePage (file, _contentCatalog, navigationCatalog) { | ||
// QUESTION should we pass the playbook to the uiModel? | ||
const uiModel = buildUiModel(siteModel, file, contentCatalog, navigationCatalog, env) | ||
const uiModel = buildUiModel(baseUiModel, file, baseUiModel.contentCatalog, navigationCatalog) | ||
let layout = uiModel.page.layout | ||
if (!layouts.has(layout)) { | ||
if (layout === '404') throw new Error('404 layout not found') | ||
const defaultLayout = siteModel.ui.defaultLayout | ||
const defaultLayout = uiModel.site.ui.defaultLayout | ||
if (defaultLayout === layout) { | ||
@@ -89,5 +85,8 @@ throw new Error(`${layout} layout not found`) | ||
} | ||
// QUESTION should we call trim() on result? | ||
file.contents = Buffer.from(layouts.get(layout)(uiModel)) | ||
try { | ||
file.contents = Buffer.from(layouts.get(layout)(uiModel)) | ||
} catch (e) { | ||
throw transformHandlebarsError(e, layout) | ||
} | ||
return file | ||
@@ -97,2 +96,10 @@ } | ||
function transformHandlebarsError (err, layout) { | ||
const stack = err.stack | ||
const m = stack.match(/^ *at Object\.ret \[as (.+?)\]/m) | ||
err = new Error(`${err.message} in UI template ${m ? 'partials/' + m[1] : 'layouts/' + layout}.hbs`) | ||
if (stack) err.stack += `\nCaused by: ${stack}` | ||
return err | ||
} | ||
module.exports = createPageComposer |
'use strict' | ||
module.exports = (spec, { data, hash: context }) => { | ||
const page = spec && data.root.site.contentCatalog.resolvePage(spec, context) | ||
const page = spec && data.root.contentCatalog.resolvePage(spec, context) | ||
if (page) return page.pub.url | ||
} |
@@ -7,4 +7,3 @@ 'use strict' | ||
if (!spec) return | ||
const site = data.root.site | ||
const contentCatalog = site.contentCatalog | ||
const { contentCatalog, site } = data.root | ||
const page = contentCatalog.resolvePage(spec, context) | ||
@@ -11,0 +10,0 @@ if (page) { |
{ | ||
"name": "@antora/page-composer", | ||
"version": "2.3.0-beta.2", | ||
"version": "2.3.0-rc.1", | ||
"description": "Wraps the embeddable HTML contents of each page file from the content catalog in a page layout to yield standalone pages in an Antora documentation pipeline.", | ||
@@ -5,0 +5,0 @@ "license": "MPL-2.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15405
338