Skip to content

Commit

Permalink
Test collectPartials(), ignore @partial-block
Browse files Browse the repository at this point in the history
While adding tests for PartialCollector, it became apparent that
wrapping it in collectPartials() made both the tests and the production
code more concise.

As expected, the code already handled block partials and ignored dynamic
and inline partials. But while reading the partials documentation, I
discovered that the code didn't yet handle `@partial-block`:

- https://handlebarsjs.com/guide/partials.html

It proved easy enough to test and fix.
  • Loading branch information
mbland committed Jan 6, 2024
1 parent 894afc4 commit 83316c3
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 7 deletions.
6 changes: 2 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
* obtain one at https://mozilla.org/MPL/2.0/.
*/

import PartialCollector from './partial-collector.js'
import collectPartials from './partials.js'
import { createFilter } from '@rollup/pluginutils'
import Handlebars from 'handlebars'

Expand Down Expand Up @@ -125,13 +125,11 @@ export default class PluginImpl {
const ast = Handlebars.parse(code, opts)
const compiled = Handlebars.precompile(ast, opts)
const { code: tmpl = compiled, map: srcMap } = compiled
const collector = new PartialCollector()
collector.accept(ast)

const beforeTmpl = [
IMPORT_HANDLEBARS,
IMPORT_HELPERS,
...collector.partials.map(p => `import '${this.#partialPath(p, id)}'`),
...collectPartials(ast).map(p => `import '${this.#partialPath(p, id)}'`),
'export const RawTemplate = Handlebars.template('
]
const afterTmpl = [
Expand Down
22 changes: 20 additions & 2 deletions lib/partial-collector.js → lib/partials.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import Handlebars from 'handlebars'
* Collects the names of partial templates from a Handlebars template
* @see https://github.com/handlebars-lang/handlebars.js/blob/master/docs/compiler-api.md
*/
export default class PartialCollector extends Handlebars.Visitor {
class PartialCollector extends Handlebars.Visitor {
partials = []

PartialStatement(partial) {
Expand All @@ -55,5 +55,23 @@ export default class PartialCollector extends Handlebars.Visitor {
return super.PartialBlockStatement(partial)
}

collect(n) { if (n.type === 'PathExpression') this.partials.push(n.original) }
collect(n) {
if (n.type === 'PathExpression' && n.original !== '@partial-block') {
this.partials.push(n.original)
}
}
}

/**
* Returns the partial names parsed from a Handlebars template
* @see https://handlebarsjs.com/guide/partials.html
* @see https://github.com/handlebars-lang/handlebars.js/blob/master/docs/compiler-api.md
* @param {object} ast - abstract syntax tree for a Handlebars template returned
* by Handlebars.parse()
* @returns {string[]} - a list of partial names parsed from the template
*/
export default function collectPartials(ast) {
const collector = new PartialCollector()
collector.accept(ast)
return collector.partials
}
2 changes: 1 addition & 1 deletion test/main.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import { describe, expect, test } from 'vitest'
import HandlebarsPrecompiler from '../index.js'
import { PLUGIN_NAME } from '../lib/index.js'
import { describe, expect, test } from 'vitest'

const PLUGIN_ID = `\0${PLUGIN_NAME}`

Expand Down
74 changes: 74 additions & 0 deletions test/partials.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/

import collectPartials from '../lib/partials.js'
import Handlebars from 'handlebars'
import { describe, expect, test } from 'vitest'

describe('collectPartials', () => {
/**
* Returns the partial names parsed from a Handlebars template
* @param {string} s - Handlebars template strin to parse
* @returns {string[]} - a list of partial names parsed from the template
*/
const partials = (s) => collectPartials(Handlebars.parse(s, {}))

describe('parses', () => {
test('regular partials', () => {
const s = '{{ foo }}{{> bar }}{{ baz }}{{> quux }}{{ xyzzy }}{{> plugh }}'

expect(partials(s))
.toEqual(['bar', 'quux', 'plugh'])
})

test('partials with contexts or parameters', () => {
expect(partials('{{> foo bar}}{{> baz quux=xyzzy }}'))
.toEqual(['foo', 'baz'])
})

test('block partials', () => {
expect(partials('{{#> foo }}bar{{>baz}}quux{{/foo}}'))
.toEqual(['foo', 'baz'])
})
})

describe('ignores', () => {
test('dynamic partials', () => {
expect(partials('{{> foo }}{{> (lookup . ignored) }}{{> bar }}'))
.toEqual(['foo', 'bar'])
})

test('@partial-block', () => {
expect(partials('Some text {{> @partial-block }}'))
.toEqual([])
})

test('inline partials', () => {
// Examples from:
// - https://handlebarsjs.com/guide/partials.html#inline-partials
const s = [
'{{#*inline "myPartial"}}',
' My Content',
'{{/inline}}',
'{{#each people}}',
' {{> myPartial}}',
'{{/each}}',
'',
'{{#> layout}}',
' {{#*inline "nav"}}',
' My Nav',
' {{/inline}}',
' {{#*inline "content"}}',
' My Content',
' {{/inline}}',
'{{/layout}}'
].join('\n')

expect(partials(s))
.toEqual(['myPartial', 'layout'])
})
})
})

0 comments on commit 83316c3

Please sign in to comment.