From 0b70d5371d579103029e6dae87c600a5fe189b31 Mon Sep 17 00:00:00 2001 From: Marko Knoebl Date: Sat, 11 Apr 2020 12:49:15 +0200 Subject: [PATCH 1/2] fixing tests The tests previously had an incorrect behaviour: They were comparing the transformed results to themselves (to see this, try changing any entry in the map variable - tests will still succeed) This change ensures the expected values are created before the transformation is run --- test/test.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/test.js b/test/test.js index 971cea3..08ac31c 100644 --- a/test/test.js +++ b/test/test.js @@ -31,27 +31,30 @@ function loadFile (filePath) { tap.test('should include by exact path', function (t) { var file = loadFile('exact.md') + var expected = transform(file.contents.split('\n')) t.equal( processor.processSync(file).toString(), - transform(file.contents.split('\n')) + expected ) t.end() }) tap.test('should include by guessing extension', function (t) { var file = loadFile('guess.md') + var expected = transform(file.contents.split('\n')) t.equal( processor.processSync(file).toString(), - transform(file.contents.split('\n')) + expected ) t.end() }) tap.test('should include from sub and super paths', function (t) { var file = loadFile('super.md') + var expected = transform(file.contents.split('\n')) t.equal( processor.processSync(file).toString(), - transform(file.contents.split('\n')) + expected ) t.end() }) From eb2cce70c8d6284217dd3e3ad58418afe88a3753 Mon Sep 17 00:00:00 2001 From: Marko Knoebl Date: Sat, 11 Apr 2020 19:46:22 +0200 Subject: [PATCH 2/2] enabling imports via glob patterns - e.g. @import foo/*.md --- index.js | 85 +++++++++++++++++++++++++++---------------------- package.json | 1 + test/c1.md | 1 + test/c2.md | 1 + test/pattern.md | 1 + test/test.js | 15 ++++++++- 6 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 test/c1.md create mode 100644 test/c2.md create mode 100644 test/pattern.md diff --git a/index.js b/index.js index 96d8255..0babda2 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ var VFile = require('vfile') var path = require('path') var fs = require('fs') +var fastGlob = require('fast-glob') var parseInclude = /^@include (.*)(\n|$)/ @@ -14,32 +15,28 @@ module.exports = function (options) { prt.blockMethods.unshift('include') return function transformer(ast, file) { - var children = ast.children + // look for any "include" elements - for (var i = 0; i < children.length; i++) { - var child = children[i] + var i = 0; + while (i < ast.children.length) { + var child = ast.children[i]; if (child.type === 'include') { - // Load file and create VFile - // console.log(cwd, file) - // var file = toFile(path.join(file.dirname || cwd, child.value)) - - // Parse vfile contents - // var parser = new processor.Parser(file, null, processor) - var root = proc.runSync(proc.parse( - toFile(path.join(child.source.dirname || cwd, child.value)) - )) - - // Split and merge the head and tail around the new children - var head = children.slice(0, i) - var tail = children.slice(i + 1) - children = head.concat(root.children).concat(tail) - - // Remember to update the offset! - i += root.children.length - 1 + var includedChildren = []; + + var includePattern = path.join(child.source.dirname || cwd, child.value) + var includePathsUnique = matchMdPaths(includePattern, glob=options.glob) + for (var includePath of includePathsUnique) { + var fileContents = fs.readFileSync(includePath, {encoding: "utf-8"}) + var vfile = new VFile({path: includePath, contents: fileContents}) + var includedChildrenFromCurrentFile = proc.runSync(proc.parse(vfile)).children; + includedChildren = includedChildren.concat(includedChildrenFromCurrentFile) + } + ast.children.splice(i, 1, ...includedChildren) + i += includedChildren.length + } else { + i ++ } } - - ast.children = children } } @@ -70,20 +67,32 @@ function tokenizer (eat, value, silent) { return node } -function toFile(full) { - return new VFile({path: full, contents: loadContent(full).toString('utf8')}) -} - -function loadContent(file) { - // console.log('loading', file) - try { return fs.readFileSync(file) } - catch (e) {} - - try { return fs.readFileSync(file + '.md') } - catch (e) {} - - try { return fs.readFileSync(file + '.markdown') } - catch (e) {} - - throw new Error('Unable to include ' + file) +/** + * returns an array of paths that match the given pattern + * if glob is true, find matches based on a glob pattern + * otherwise, look for "pattern", "pattern.md" or "pattern.markdown" + */ +function matchMdPaths(pattern, glob=false) { + var patterns = [pattern, pattern + ".md", pattern + ".markdown"] + if (glob) { + var includePaths = []; + for (let pat of patterns) { + includePaths = includePaths.concat(fastGlob.sync(pat)) + } + // remove any duplicates that were matched + // both with and without extensions + var includePathsUnique = [...new Set(includePaths)] + includePathsUnique.sort() + if (includePaths.length === 0) { + throw new Error('Unable to include ' + pattern) + } + return includePathsUnique + } else { + for (let pat of patterns) { + if (fs.existsSync(pat)) { + return [pat] + } + } + throw new Error('Unable to include ' + pattern) + } } diff --git a/package.json b/package.json index 1aa42f9..82feb90 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "tap": "^10.0.0" }, "dependencies": { + "fast-glob": "^3.2.2", "vfile": "^2.0.0" } } diff --git a/test/c1.md b/test/c1.md new file mode 100644 index 0000000..905e73a --- /dev/null +++ b/test/c1.md @@ -0,0 +1 @@ +# C1 \ No newline at end of file diff --git a/test/c2.md b/test/c2.md new file mode 100644 index 0000000..f91294a --- /dev/null +++ b/test/c2.md @@ -0,0 +1 @@ +# C2 \ No newline at end of file diff --git a/test/pattern.md b/test/pattern.md new file mode 100644 index 0000000..24e0836 --- /dev/null +++ b/test/pattern.md @@ -0,0 +1 @@ +@include c*.md \ No newline at end of file diff --git a/test/test.js b/test/test.js index 08ac31c..67f8046 100644 --- a/test/test.js +++ b/test/test.js @@ -5,13 +5,16 @@ var tap = require('tap') var fs = require('fs') var include = require('../index') + var processor = remark().use(include) +var processorGlob = remark().use(include, {glob: true}) var map = { '@include a.md': '# A', '@include a': '# A', '@include b': '# B', - '@include sub/sub': '# A\n\n# sub' + '@include sub/sub': '# A\n\n# sub', + '@include c*.md': '# C1\n\n# C2' } function transform (lines) { @@ -66,3 +69,13 @@ tap.test('should fail to include non-existent file', function (t) { ) t.end() }) + +tap.test('should include by glob pattern', function(t) { + var file = loadFile('pattern.md') + var expected = transform(file.contents.split('\n')) + t.equal( + processorGlob.processSync(file).toString(), + expected + ) + t.end() +})