Skip to content

Commit

Permalink
Pickup missing elements from the default template
Browse files Browse the repository at this point in the history
  • Loading branch information
tai2 committed Nov 4, 2023
1 parent db1e6b1 commit b483a87
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 23 deletions.
60 changes: 39 additions & 21 deletions src/decor.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,12 @@
import { parse } from './deps/std/flags.ts'
import { debounce } from './deps/std/async.ts'
import { DOMParser } from './deps/deno-dom.ts'
import { extractTemplate } from './extract_template.ts'
import { HTMLDocument } from './deps/deno-dom.ts'
import { PartialTemplate, Template } from './template.ts'
import { parsePartialTemplate, parseTemplate } from './extract_template.ts'
import { templateRenderer } from './template_renderer.ts'
import { renderHtml } from './render_html.ts'
import assets from './assets.json' assert { type: 'json' }

function render(contentString: string, templateString: string): string {
const templateDocument = new DOMParser().parseFromString(
templateString,
'text/html',
)
if (!templateDocument) {
throw new Error('Failed to parse template')
}

const template = extractTemplate(templateDocument)
const renderer = templateRenderer(template)

return renderHtml(contentString, renderer, templateDocument)
}

async function renderDefaultTemplate(options: { output?: string }) {
let file, writableStream
if (options.output) {
Expand All @@ -43,17 +29,43 @@ async function runOneshot(options: {
template?: string
input?: string
output?: string
defaultTemplate: [HTMLDocument, Template]
}) {
const templateString = options.template
? Deno.readTextFileSync(options.template)
: assets.defaultTemplate
// Prepare the template
const [defaultHtmlDocument, defaultTemplate] = options.defaultTemplate

let template: Template, document: HTMLDocument
if (options.template) {
// Fill the missing elements with the default template.
const templateString = Deno.readTextFileSync(options.template)
const [templateDocument, partialTemplate] = parsePartialTemplate(
templateString,
)
for (
const key of Object.keys(partialTemplate) as Array<keyof PartialTemplate>
) {
if (!partialTemplate[key]) {
partialTemplate[key] = defaultTemplate[key]
}
}
template = partialTemplate as Template
document = templateDocument
} else {
// Use the default template but clone the document so that we can reuse the original data.
template = defaultTemplate
document = defaultHtmlDocument.cloneNode(true) as HTMLDocument
}

// Execute rendering
const renderer = templateRenderer(template)

const contentString = options.input
? Deno.readTextFileSync(options.input)
: assets.defaultContent

const outputString = render(contentString, templateString)
const outputString = renderHtml(contentString, renderer, document)

// Write the output
let file, writableStream
if (options.output) {
file = Deno.openSync(options.output, {
Expand All @@ -79,6 +91,7 @@ async function runWatch(options: {
template?: string
input?: string
output: string
defaultTemplate: [HTMLDocument, Template]
}) {
const watchTargets: string[] = []
if (options.template) {
Expand Down Expand Up @@ -133,6 +146,9 @@ async function main() {
Deno.exit(1)
}

const defaultTemplate = parseTemplate(
assets.defaultTemplate,
)
if (options.watch) {
if (options.output === undefined) {
console.error('--output is required when --watch is specified')
Expand All @@ -143,12 +159,14 @@ async function main() {
template: options.template,
input: input?.toString(),
output: options.output,
defaultTemplate,
})
} else {
await runOneshot({
template: options.template,
input: input?.toString(),
output: options.output,
defaultTemplate,
})
}
} catch (e) {
Expand Down
40 changes: 39 additions & 1 deletion src/extract_template.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HTMLDocument } from './deps/deno-dom.ts'
import { DOMParser, HTMLDocument } from './deps/deno-dom.ts'
import { PartialTemplate, Template } from './template.ts'

export function extractPartialTemplate(
Expand Down Expand Up @@ -45,6 +45,25 @@ export function extractPartialTemplate(
return template
}

export function parsePartialTemplate(
templateString: string,
): [HTMLDocument, PartialTemplate] {
const templateDocument = new DOMParser().parseFromString(
templateString,
'text/html',
)
if (!templateDocument) {
throw new Error('Failed to parse template')
}

const template = extractPartialTemplate(templateDocument)

// Discard the content of the body since we are no longer interested in it.
templateDocument.body.innerHTML = ''

return [templateDocument, template]
}

export function extractTemplate(
templateDocument: HTMLDocument,
): Template {
Expand All @@ -63,3 +82,22 @@ export function extractTemplate(

return template as Template
}

export function parseTemplate(
templateString: string,
): [HTMLDocument, Template] {
const templateDocument = new DOMParser().parseFromString(
templateString,
'text/html',
)
if (!templateDocument) {
throw new Error('Failed to parse template')
}

const template = extractTemplate(templateDocument)

// Discard the content of the body since we are no longer interested in it.
templateDocument.body.innerHTML = ''

return [templateDocument, template]
}
4 changes: 3 additions & 1 deletion src/render_html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export function renderHtml(
): string {
const tokens = marked.lexer(markdown)
const output = Parser.parse(renderer, tokens)
templateDocument.body.innerHTML = output
// Due to a bug of deno-dom, tempalteDocument.body becomes null when the document is cloned with
// `cloneNode(true)`. So we instead use `querySelector`. Let's fix this when the bug is fixed.
templateDocument.querySelector('body')!.innerHTML = output
return '<!DOCTYPE html>\n' + templateDocument.documentElement?.outerHTML
}

0 comments on commit b483a87

Please sign in to comment.