From 04530c7219fbf1bbe7e0ae4a136e54e652576192 Mon Sep 17 00:00:00 2001 From: Joseph Finlayson Date: Fri, 6 Apr 2018 15:44:07 +0200 Subject: [PATCH 1/3] support for recursive extends --- lib/index.js | 42 ++++++++++++++++++++------------ package.json | 5 ++-- test/fixtures/card.html | 4 +++ test/fixtures/nested_extend.html | 10 ++++++++ test/index.js | 36 +++++++++++++++++++++++---- 5 files changed, 74 insertions(+), 23 deletions(-) create mode 100644 test/fixtures/card.html create mode 100644 test/fixtures/nested_extend.html diff --git a/lib/index.js b/lib/index.js index 25883cb..ac357f2 100644 --- a/lib/index.js +++ b/lib/index.js @@ -23,14 +23,23 @@ module.exports = function reshapeLayouts (options = {}) { } function handleExtendsNodes (tree, options, ctx) { - return tree.reduce((m, node) => { + return tree.reduce((p, node) => { // if it's not an "extends" tag, move on - if (node.name !== 'extends') { m.push(node); return m } + if (node.name !== 'extends') { + + if (Array.isArray(node.content)) { + node.content = handleExtendsNodes(node.content, options, ctx) + p.push(node) + } else { + p.push(node) + } + return p + } // if the extends tag has no "src", throw an error if (!node.attrs || !node.attrs.src) { throw new ctx.PluginError({ - message: "Extends tag has no 'src' attribute", + message: 'Extends tag has no \'src\' attribute', plugin: 'reshape-extend', location: node.location }) @@ -39,7 +48,7 @@ function handleExtendsNodes (tree, options, ctx) { // Get the layout file contents and parse it const layoutPath = path.resolve(options.root, node.attrs.src[0].content) const layoutHtml = fs.readFileSync(layoutPath, options.encoding) - const parsedLayout = ctx.parser(layoutHtml, { filename: layoutPath }) + const parsedLayout = ctx.parser(layoutHtml, {filename: layoutPath}) const layoutTree = handleExtendsNodes(parsedLayout, options, ctx) // add dependency if applicable @@ -51,8 +60,8 @@ function handleExtendsNodes (tree, options, ctx) { } // merge the contents of the current node into the layout - m = m.concat(mergeExtendsAndLayout(layoutTree, node.content, ctx)) - return m + p = p.concat(mergeExtendsAndLayout(layoutTree, handleExtendsNodes(node.content, options, ctx), ctx)) + return p }, []) } @@ -80,13 +89,13 @@ function mergeExtendsAndLayout (layoutTree, templateTree, ctx) { // if there's a block left over after this, it means it exists in the template // but not in the layout template, so we throw an error - for (let templateBlockName in templateBlockNodes) { - throw new ctx.PluginError({ - message: `Block "${templateBlockName}" doesn't exist in the layout template`, - plugin: 'reshape-extend', - location: templateBlockNodes[templateBlockName].location - }) - } + // for (let templateBlockName in templateBlockNodes) { + // throw new ctx.PluginError({ + // message: `Block "${templateBlockName}" doesn't exist in the layout template`, + // plugin: 'reshape-extend', + // location: templateBlockNodes[templateBlockName].location + // }) + // } return layoutTree } @@ -139,7 +148,7 @@ function getBlockNodes (tree = [], ctx) { // if the block has no "name" attr, throw an error if (!node.attrs || !node.attrs.name) { throw new ctx.PluginError({ - message: "'block' element is missing a 'name' attribute", + message: '\'block\' element is missing a \'name\' attribute', plugin: 'reshape-extend', location: node.location }) @@ -157,7 +166,10 @@ function unwrapBlocks (tree) { if (node.type === 'tag' && node.content) { node.content = unwrapBlocks(node.content) } - if (node.name !== 'block') { m.push(node); return m } + if (node.name !== 'block') { + m.push(node) + return m + } if (node.content) { m = m.concat(node.content) } return m }, []) diff --git a/package.json b/package.json index 17e8e6f..1017cc6 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "reshape-layouts", + "name": "@josephfinlayson/reshape-layouts", "description": "flexible layouts using 'extend' and 'block' tags", "version": "1.0.0", "author": "Jeff Escalante", @@ -31,7 +31,6 @@ "scripts": { "coverage": "nyc ava && nyc report --reporter=html && open ./coverage/index.html", "coveralls": "nyc report --reporter=text-lcov | coveralls", - "pretest": "standard | snazzy", - "test": "nyc ava" + "test": "ava" } } diff --git a/test/fixtures/card.html b/test/fixtures/card.html new file mode 100644 index 0000000..38dc40d --- /dev/null +++ b/test/fixtures/card.html @@ -0,0 +1,4 @@ +
+

this is a card

+ this is a card Title +
diff --git a/test/fixtures/nested_extend.html b/test/fixtures/nested_extend.html new file mode 100644 index 0000000..d0283f7 --- /dev/null +++ b/test/fixtures/nested_extend.html @@ -0,0 +1,10 @@ + + +

blah

+ + + + + +
+
diff --git a/test/index.js b/test/index.js index 9ca97df..3a9843b 100644 --- a/test/index.js +++ b/test/index.js @@ -16,7 +16,7 @@ let mfs = { } } -const extend = proxyquire('../lib/index', { fs: mfs }) +const extend = proxyquire('../lib/index', {fs: mfs}) const fixtures = path.join(__dirname, 'fixtures') test.beforeEach(() => { mfs._files = {} }) @@ -24,7 +24,7 @@ test.beforeEach(() => { mfs._files = {} }) test('resolves correctly with reshape filename option', (t) => { const p = path.join(fixtures, 'basic.html') const html = fs.readFileSync(p, 'utf8') - return reshape({ plugins: layouts(), filename: p }) + return reshape({plugins: layouts(), filename: p}) .process(html) .then((res) => { t.truthy(cleanHtml(res.output()) === '

hello!

') @@ -35,7 +35,7 @@ test('reports dependencies correctly', (t) => { const p = path.join(fixtures, 'basic.html') const html = fs.readFileSync(p, 'utf8') - return reshape({ plugins: layouts(), dependencies: [], filename: p }) + return reshape({plugins: layouts(), dependencies: [], filename: p}) .process(html) .then((res) => { t.truthy(res.dependencies) @@ -184,7 +184,7 @@ test('uses the correct source location for layouts and templates', (t) => { const html = 'hello!' - return reshape({ plugins: [extend(), interceptLocation] }) + return reshape({plugins: [extend(), interceptLocation]}) .process(html) function interceptLocation (tree) { @@ -194,6 +194,32 @@ test('uses the correct source location for layouts and templates', (t) => { } }) +testq('it recursively extends layout', (t) => { + const p = path.join(fixtures, 'nested_extend.html') + const html = fs.readFileSync(p, 'utf8') + mfs.writeFileSync('./layout.html', '
templatecontent
') + mfs.writeFileSync('./card.html', '
cardtemplatecontent
') + + const extended = init(` + +

extended content

+ + +

extended card content

+
+
+
+
+`) + .then(extended => { + + + }) + + t.truthy(extended, html) + +}) + function assertError (t, promise, expectedErrorMessage) { return promise .catch((error) => error.message) @@ -201,7 +227,7 @@ function assertError (t, promise, expectedErrorMessage) { } function init (html, options = {}) { - return reshape({ plugins: extend(options) }) + return reshape({plugins: extend(options)}) .process(html) .then((res) => cleanHtml(res.output())) } From 8f8aa6460d28b29f979db9c16ea63c276b81ecce Mon Sep 17 00:00:00 2001 From: HoldYourWaffle Date: Fri, 19 Apr 2019 12:38:23 +0100 Subject: [PATCH 2/3] Undo formatting changes --- lib/index.js | 37 +++++++++++++++----------------- package.json | 5 +++-- test/fixtures/card.html | 4 ---- test/fixtures/nested_extend.html | 10 --------- test/index.js | 36 +++++-------------------------- 5 files changed, 25 insertions(+), 67 deletions(-) delete mode 100644 test/fixtures/card.html delete mode 100644 test/fixtures/nested_extend.html diff --git a/lib/index.js b/lib/index.js index ac357f2..5eb4afd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -23,23 +23,23 @@ module.exports = function reshapeLayouts (options = {}) { } function handleExtendsNodes (tree, options, ctx) { - return tree.reduce((p, node) => { + return tree.reduce((m, node) => { // if it's not an "extends" tag, move on if (node.name !== 'extends') { if (Array.isArray(node.content)) { node.content = handleExtendsNodes(node.content, options, ctx) - p.push(node) + m.push(node) } else { - p.push(node) + m.push(node) } - return p + return m } // if the extends tag has no "src", throw an error if (!node.attrs || !node.attrs.src) { throw new ctx.PluginError({ - message: 'Extends tag has no \'src\' attribute', + message: "Extends tag has no 'src' attribute", plugin: 'reshape-extend', location: node.location }) @@ -48,7 +48,7 @@ function handleExtendsNodes (tree, options, ctx) { // Get the layout file contents and parse it const layoutPath = path.resolve(options.root, node.attrs.src[0].content) const layoutHtml = fs.readFileSync(layoutPath, options.encoding) - const parsedLayout = ctx.parser(layoutHtml, {filename: layoutPath}) + const parsedLayout = ctx.parser(layoutHtml, { filename: layoutPath }) const layoutTree = handleExtendsNodes(parsedLayout, options, ctx) // add dependency if applicable @@ -60,8 +60,8 @@ function handleExtendsNodes (tree, options, ctx) { } // merge the contents of the current node into the layout - p = p.concat(mergeExtendsAndLayout(layoutTree, handleExtendsNodes(node.content, options, ctx), ctx)) - return p + m = m.concat(mergeExtendsAndLayout(layoutTree, handleExtendsNodes(node.content, options, ctx), ctx)) + return m }, []) } @@ -89,13 +89,13 @@ function mergeExtendsAndLayout (layoutTree, templateTree, ctx) { // if there's a block left over after this, it means it exists in the template // but not in the layout template, so we throw an error - // for (let templateBlockName in templateBlockNodes) { - // throw new ctx.PluginError({ - // message: `Block "${templateBlockName}" doesn't exist in the layout template`, - // plugin: 'reshape-extend', - // location: templateBlockNodes[templateBlockName].location - // }) - // } + /* for (let templateBlockName in templateBlockNodes) { + throw new ctx.PluginError({ + message: `Block "${templateBlockName}" doesn't exist in the layout template`, + plugin: 'reshape-extend', + location: templateBlockNodes[templateBlockName].location + }) + } */ return layoutTree } @@ -148,7 +148,7 @@ function getBlockNodes (tree = [], ctx) { // if the block has no "name" attr, throw an error if (!node.attrs || !node.attrs.name) { throw new ctx.PluginError({ - message: '\'block\' element is missing a \'name\' attribute', + message: "'block' element is missing a 'name' attribute", plugin: 'reshape-extend', location: node.location }) @@ -166,10 +166,7 @@ function unwrapBlocks (tree) { if (node.type === 'tag' && node.content) { node.content = unwrapBlocks(node.content) } - if (node.name !== 'block') { - m.push(node) - return m - } + if (node.name !== 'block') { m.push(node); return m } if (node.content) { m = m.concat(node.content) } return m }, []) diff --git a/package.json b/package.json index 1017cc6..17e8e6f 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@josephfinlayson/reshape-layouts", + "name": "reshape-layouts", "description": "flexible layouts using 'extend' and 'block' tags", "version": "1.0.0", "author": "Jeff Escalante", @@ -31,6 +31,7 @@ "scripts": { "coverage": "nyc ava && nyc report --reporter=html && open ./coverage/index.html", "coveralls": "nyc report --reporter=text-lcov | coveralls", - "test": "ava" + "pretest": "standard | snazzy", + "test": "nyc ava" } } diff --git a/test/fixtures/card.html b/test/fixtures/card.html deleted file mode 100644 index 38dc40d..0000000 --- a/test/fixtures/card.html +++ /dev/null @@ -1,4 +0,0 @@ -
-

this is a card

- this is a card Title -
diff --git a/test/fixtures/nested_extend.html b/test/fixtures/nested_extend.html deleted file mode 100644 index d0283f7..0000000 --- a/test/fixtures/nested_extend.html +++ /dev/null @@ -1,10 +0,0 @@ - - -

blah

- - - - - -
-
diff --git a/test/index.js b/test/index.js index 3a9843b..9ca97df 100644 --- a/test/index.js +++ b/test/index.js @@ -16,7 +16,7 @@ let mfs = { } } -const extend = proxyquire('../lib/index', {fs: mfs}) +const extend = proxyquire('../lib/index', { fs: mfs }) const fixtures = path.join(__dirname, 'fixtures') test.beforeEach(() => { mfs._files = {} }) @@ -24,7 +24,7 @@ test.beforeEach(() => { mfs._files = {} }) test('resolves correctly with reshape filename option', (t) => { const p = path.join(fixtures, 'basic.html') const html = fs.readFileSync(p, 'utf8') - return reshape({plugins: layouts(), filename: p}) + return reshape({ plugins: layouts(), filename: p }) .process(html) .then((res) => { t.truthy(cleanHtml(res.output()) === '

hello!

') @@ -35,7 +35,7 @@ test('reports dependencies correctly', (t) => { const p = path.join(fixtures, 'basic.html') const html = fs.readFileSync(p, 'utf8') - return reshape({plugins: layouts(), dependencies: [], filename: p}) + return reshape({ plugins: layouts(), dependencies: [], filename: p }) .process(html) .then((res) => { t.truthy(res.dependencies) @@ -184,7 +184,7 @@ test('uses the correct source location for layouts and templates', (t) => { const html = 'hello!' - return reshape({plugins: [extend(), interceptLocation]}) + return reshape({ plugins: [extend(), interceptLocation] }) .process(html) function interceptLocation (tree) { @@ -194,32 +194,6 @@ test('uses the correct source location for layouts and templates', (t) => { } }) -testq('it recursively extends layout', (t) => { - const p = path.join(fixtures, 'nested_extend.html') - const html = fs.readFileSync(p, 'utf8') - mfs.writeFileSync('./layout.html', '
templatecontent
') - mfs.writeFileSync('./card.html', '
cardtemplatecontent
') - - const extended = init(` - -

extended content

- - -

extended card content

-
-
-
-
-`) - .then(extended => { - - - }) - - t.truthy(extended, html) - -}) - function assertError (t, promise, expectedErrorMessage) { return promise .catch((error) => error.message) @@ -227,7 +201,7 @@ function assertError (t, promise, expectedErrorMessage) { } function init (html, options = {}) { - return reshape({plugins: extend(options)}) + return reshape({ plugins: extend(options) }) .process(html) .then((res) => cleanHtml(res.output())) } From ab1d870af7d7bbf2f06b744d3a5f1c5ea030ab68 Mon Sep 17 00:00:00 2001 From: HoldYourWaffle Date: Fri, 19 Apr 2019 14:20:46 +0200 Subject: [PATCH 3/3] Add test --- lib/index.js | 5 ++--- test/index.js | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5eb4afd..ea7c0ba 100644 --- a/lib/index.js +++ b/lib/index.js @@ -26,7 +26,6 @@ function handleExtendsNodes (tree, options, ctx) { return tree.reduce((m, node) => { // if it's not an "extends" tag, move on if (node.name !== 'extends') { - if (Array.isArray(node.content)) { node.content = handleExtendsNodes(node.content, options, ctx) m.push(node) @@ -89,13 +88,13 @@ function mergeExtendsAndLayout (layoutTree, templateTree, ctx) { // if there's a block left over after this, it means it exists in the template // but not in the layout template, so we throw an error - /* for (let templateBlockName in templateBlockNodes) { + for (let templateBlockName in templateBlockNodes) { throw new ctx.PluginError({ message: `Block "${templateBlockName}" doesn't exist in the layout template`, plugin: 'reshape-extend', location: templateBlockNodes[templateBlockName].location }) - } */ + } return layoutTree } diff --git a/test/index.js b/test/index.js index 9ca97df..70bf302 100644 --- a/test/index.js +++ b/test/index.js @@ -194,6 +194,27 @@ test('uses the correct source location for layouts and templates', (t) => { } }) +test('recursive layout extension', (t) => { + mfs.writeFileSync('./layout.html', '

default

') + mfs.writeFileSync('./component.html', '

this is a very interesting component

this is default content
') + + return init(` + +

blah

+ + + Hello! + + +
+
+ `).then((html) => { + t.truthy((html) === cleanHtml(`

blah

this is a very interesting component

+ Hello! +
`)) + }) +}) + function assertError (t, promise, expectedErrorMessage) { return promise .catch((error) => error.message)