├── test
├── fixtures
│ ├── test.exs
│ ├── test.rs
│ ├── test.js
│ ├── test.ts
│ ├── custom.hbs
│ ├── line.js
│ ├── marker.cpp
│ └── template.hbs
├── patterns
│ ├── import-only
│ │ ├── actual.md
│ │ ├── test.js
│ │ └── expected.md
│ ├── import-cpp-bug-workaround
│ │ ├── test.cpp
│ │ ├── actual.md
│ │ ├── expected.md
│ │ └── book.js
│ ├── import-hardcode
│ │ ├── test.ts
│ │ ├── actual.md
│ │ └── expected.md
│ ├── import-slice
│ │ ├── actual.md
│ │ ├── test.js
│ │ └── expected.md
│ ├── import-title
│ │ ├── test.js
│ │ ├── actual.md
│ │ └── expected.md
│ ├── import-unindent
│ │ ├── actual.md
│ │ ├── test.js
│ │ ├── expected.md
│ │ └── book.js
│ ├── import-exlixir-extension
│ │ ├── test.exs
│ │ ├── actual.md
│ │ └── expected.md
│ ├── import-rust-extension
│ │ ├── actual.md
│ │ ├── test.rs
│ │ └── expected.md
│ ├── import-ace-template
│ │ ├── test.js
│ │ ├── actual.md
│ │ ├── book.js
│ │ └── expected.md
│ ├── import-book-options
│ │ ├── actual.md
│ │ ├── test.js
│ │ ├── expected.md
│ │ └── book.js
│ ├── import-codeblock-issues-55
│ │ ├── actual.md
│ │ ├── test.js
│ │ ├── expected.md
│ │ └── book.js
│ ├── import-full-template
│ │ ├── actual.md
│ │ ├── test.js
│ │ ├── book.js
│ │ └── expected.md
│ ├── import-snippet
│ │ ├── actual.md
│ │ ├── expected.md
│ │ └── test.ts
│ ├── import-acefull-template
│ │ ├── actual.md
│ │ ├── test.js
│ │ ├── book.js
│ │ └── expected.md
│ ├── import-custom-template
│ │ ├── test.js
│ │ ├── actual.md
│ │ ├── expected.md
│ │ └── book.js
│ ├── import-default-template
│ │ ├── actual.md
│ │ ├── test.js
│ │ ├── expected.md
│ │ └── book.js
│ ├── import-output-escape
│ │ ├── test&1.js
│ │ ├── actual.md
│ │ ├── book.js
│ │ ├── dump.hbs
│ │ └── expected.md
│ ├── import-snippet-inner
│ │ ├── actual.md
│ │ ├── expected.md
│ │ └── test.ts
│ ├── import-unindent-slice
│ │ ├── actual.md
│ │ ├── test.js
│ │ ├── expected.md
│ │ └── book.js
│ ├── import-book-command-options
│ │ ├── test.js
│ │ ├── actual.md
│ │ ├── expected.md
│ │ └── book.js
│ ├── import-slice-only-first
│ │ ├── actual.md
│ │ ├── expected.md
│ │ └── line.js
│ ├── import-hardcode-not-found-warn
│ │ ├── test.unknownLang
│ │ ├── actual.md
│ │ └── expected.md
│ ├── import-slice-only-last
│ │ ├── actual.md
│ │ ├── expected.md
│ │ └── line.js
│ ├── import-snippet-multi
│ │ ├── actual.md
│ │ ├── expected.md
│ │ └── test.ts
│ ├── import-labels-ace
│ │ ├── test.js
│ │ ├── actual.md
│ │ ├── book.js
│ │ └── expected.md
│ └── import-infinity-loop-issue-57
│ │ ├── book.js
│ │ ├── actual.md
│ │ └── expected.md
├── title-test.js
├── generate-test.js
├── language-detection-test.js
├── slicer-test.js
├── marker-test.js
└── parser-test.js
├── examples
├── ace
│ ├── src
│ │ ├── test.js
│ │ ├── test.ts
│ │ ├── marker.ts
│ │ └── line.js
│ ├── user-template.hbs
│ ├── SUMMARY.md
│ ├── book.js
│ ├── README.md
│ ├── package.json
│ ├── test_asciidoc.adoc
│ └── test_markdown.md
├── custom
│ ├── src
│ │ ├── test.js
│ │ ├── test.ts
│ │ ├── marker.ts
│ │ └── line.js
│ ├── user-template.hbs
│ ├── SUMMARY.md
│ ├── README.md
│ ├── book.js
│ ├── package.json
│ ├── test_asciidoc.adoc
│ └── test_markdown.md
└── default
│ ├── src
│ ├── test.js
│ ├── test.ts
│ ├── marker.ts
│ └── line.js
│ ├── SUMMARY.md
│ ├── book.js
│ ├── README.md
│ ├── package.json
│ ├── test_asciidoc.adoc
│ └── test_markdown.md
├── .babelrc
├── .githooks
└── pre-commit
├── .mocharc.json
├── templates
├── default-template.hbs
├── ace-template.hbs
├── full-template.hbs
├── acefull-template.hbs
└── README.md
├── .editorconfig
├── .github
└── workflows
│ └── test.yml
├── src
├── title.js
├── backtick-maker.js
├── include-codeblock.js
├── ace-check.js
├── unescape-string.js
├── template.js
├── slicer.js
├── language-detection.js
├── marker.js
├── options.js
└── parser.js
├── .eslintrc.js
├── bin
└── include-codeblock.js
├── .gitignore
├── LICENSE
├── package.json
└── README.md
/test/fixtures/test.exs:
--------------------------------------------------------------------------------
1 | IO.puts "test"
--------------------------------------------------------------------------------
/test/fixtures/test.rs:
--------------------------------------------------------------------------------
1 | extern crate num;
--------------------------------------------------------------------------------
/test/fixtures/test.js:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/test/fixtures/test.ts:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/examples/ace/src/test.js:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/examples/ace/src/test.ts:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/examples/custom/src/test.js:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/examples/custom/src/test.ts:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/examples/default/src/test.js:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/examples/default/src/test.ts:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/test/patterns/import-only/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.js)
--------------------------------------------------------------------------------
/test/patterns/import-only/test.js:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/test/patterns/import-cpp-bug-workaround/test.cpp:
--------------------------------------------------------------------------------
1 | int i:
--------------------------------------------------------------------------------
/test/patterns/import-hardcode/test.ts:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/test/patterns/import-slice/actual.md:
--------------------------------------------------------------------------------
1 | [import:1-2](test.js)
--------------------------------------------------------------------------------
/test/patterns/import-title/test.js:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/test/patterns/import-unindent/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.js)
--------------------------------------------------------------------------------
/test/patterns/import-exlixir-extension/test.exs:
--------------------------------------------------------------------------------
1 | IO.puts "test"
--------------------------------------------------------------------------------
/test/patterns/import-rust-extension/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.rs)
--------------------------------------------------------------------------------
/test/patterns/import-rust-extension/test.rs:
--------------------------------------------------------------------------------
1 | extern crate num;
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/env"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.githooks/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | npx --no-install lint-staged
3 |
--------------------------------------------------------------------------------
/test/patterns/import-ace-template/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
4 |
--------------------------------------------------------------------------------
/test/patterns/import-book-options/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-book-options/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
4 |
--------------------------------------------------------------------------------
/test/patterns/import-codeblock-issues-55/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.js)
--------------------------------------------------------------------------------
/test/patterns/import-cpp-bug-workaround/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.cpp)
--------------------------------------------------------------------------------
/test/patterns/import-exlixir-extension/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.exs)
--------------------------------------------------------------------------------
/test/patterns/import-full-template/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-snippet/actual.md:
--------------------------------------------------------------------------------
1 | [import:"marker0"](test.ts)
--------------------------------------------------------------------------------
/test/patterns/import-acefull-template/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-acefull-template/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
4 |
--------------------------------------------------------------------------------
/test/patterns/import-custom-template/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
4 |
--------------------------------------------------------------------------------
/test/patterns/import-default-template/actual.md:
--------------------------------------------------------------------------------
1 | [import](test.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-default-template/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
4 |
--------------------------------------------------------------------------------
/test/patterns/import-full-template/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
4 |
--------------------------------------------------------------------------------
/test/patterns/import-output-escape/test&1.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
4 |
--------------------------------------------------------------------------------
/test/patterns/import-snippet-inner/actual.md:
--------------------------------------------------------------------------------
1 | [import:"marker1"](test.ts)
--------------------------------------------------------------------------------
/test/patterns/import-title/actual.md:
--------------------------------------------------------------------------------
1 | [include,title:"custom.js"](test.js)
--------------------------------------------------------------------------------
/test/patterns/import-unindent-slice/actual.md:
--------------------------------------------------------------------------------
1 | [import:1-2](test.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-unindent/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
--------------------------------------------------------------------------------
/.mocharc.json:
--------------------------------------------------------------------------------
1 | {
2 | "require": [
3 | "@babel/register"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/test/patterns/import-book-command-options/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
4 |
--------------------------------------------------------------------------------
/test/patterns/import-slice-only-first/actual.md:
--------------------------------------------------------------------------------
1 | [include:9-, line.js](line.js)
--------------------------------------------------------------------------------
/test/patterns/import-unindent-slice/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | bar;
3 | baz;
--------------------------------------------------------------------------------
/test/patterns/import-cpp-bug-workaround/expected.md:
--------------------------------------------------------------------------------
1 | ``` cpp
2 | int i:
3 | ```
4 |
--------------------------------------------------------------------------------
/test/patterns/import-hardcode-not-found-warn/test.unknownLang:
--------------------------------------------------------------------------------
1 | console.log("test");
--------------------------------------------------------------------------------
/test/patterns/import-hardcode/actual.md:
--------------------------------------------------------------------------------
1 | [import, lang:"typescript"](test.ts)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-snippet-inner/expected.md:
--------------------------------------------------------------------------------
1 | ``` xml
2 | var b;
3 | ```
4 |
--------------------------------------------------------------------------------
/templates/default-template.hbs:
--------------------------------------------------------------------------------
1 | {{{backtick}}} {{lang}}
2 | {{{content}}}
3 | {{{backtick}}}
--------------------------------------------------------------------------------
/test/patterns/import-ace-template/actual.md:
--------------------------------------------------------------------------------
1 | [import,check:"false",edit:"true"](test.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-custom-template/actual.md:
--------------------------------------------------------------------------------
1 | [import, title:"title", id:"foo"](test.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-exlixir-extension/expected.md:
--------------------------------------------------------------------------------
1 | ``` elixir
2 | IO.puts "test"
3 | ```
4 |
--------------------------------------------------------------------------------
/test/patterns/import-hardcode/expected.md:
--------------------------------------------------------------------------------
1 | ``` typescript
2 | console.log("test");
3 | ```
4 |
--------------------------------------------------------------------------------
/test/patterns/import-only/expected.md:
--------------------------------------------------------------------------------
1 | ``` javascript
2 | console.log("test");
3 | ```
4 |
--------------------------------------------------------------------------------
/test/patterns/import-rust-extension/expected.md:
--------------------------------------------------------------------------------
1 | ``` rust
2 | extern crate num;
3 | ```
4 |
--------------------------------------------------------------------------------
/test/patterns/import-slice-only-last/actual.md:
--------------------------------------------------------------------------------
1 | [include:-2, title:"line.js", line.js](line.js)
--------------------------------------------------------------------------------
/test/patterns/import-slice/test.js:
--------------------------------------------------------------------------------
1 | console.log(1);
2 | console.log(2);
3 | console.log(3);
--------------------------------------------------------------------------------
/test/patterns/import-snippet-multi/actual.md:
--------------------------------------------------------------------------------
1 | [import:"marker0,marker1,marker2"](test.ts)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-title/expected.md:
--------------------------------------------------------------------------------
1 | ``` javascript
2 | console.log("test");
3 | ```
4 |
--------------------------------------------------------------------------------
/test/patterns/import-unindent-slice/expected.md:
--------------------------------------------------------------------------------
1 | ``` javascript
2 | foo;
3 | bar;
4 | ```
5 |
--------------------------------------------------------------------------------
/test/patterns/import-labels-ace/test.js:
--------------------------------------------------------------------------------
1 | foo;
2 | //! [tag]
3 | bar;
4 | //! [tag]
5 | baz;
6 |
--------------------------------------------------------------------------------
/test/patterns/import-unindent/expected.md:
--------------------------------------------------------------------------------
1 | ``` javascript
2 | foo;
3 | bar;
4 | baz;
5 | ```
6 |
--------------------------------------------------------------------------------
/test/patterns/import-book-command-options/actual.md:
--------------------------------------------------------------------------------
1 | [import, template:"ace", check:"false"](test.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-default-template/expected.md:
--------------------------------------------------------------------------------
1 | ``` javascript
2 | foo;
3 | bar;
4 | baz;
5 |
6 | ```
7 |
--------------------------------------------------------------------------------
/test/patterns/import-hardcode-not-found-warn/actual.md:
--------------------------------------------------------------------------------
1 | [import, lang:"unknownLang"](test.unknownLang)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-slice/expected.md:
--------------------------------------------------------------------------------
1 | ``` javascript
2 | console.log(1);
3 | console.log(2);
4 | ```
5 |
--------------------------------------------------------------------------------
/test/patterns/import-snippet/expected.md:
--------------------------------------------------------------------------------
1 | ``` xml
2 | var a;
3 | var b;
4 | var c;
5 | ```
6 |
--------------------------------------------------------------------------------
/test/fixtures/custom.hbs:
--------------------------------------------------------------------------------
1 | custom title "{{title}}" with id "{{id}}"
2 | ``` {{lang}}
3 | {{{content}}}
4 | ```
5 |
--------------------------------------------------------------------------------
/test/patterns/import-hardcode-not-found-warn/expected.md:
--------------------------------------------------------------------------------
1 | ``` unknownLang
2 | console.log("test");
3 | ```
4 |
--------------------------------------------------------------------------------
/test/patterns/import-snippet-multi/expected.md:
--------------------------------------------------------------------------------
1 | ``` xml
2 | var a;
3 | var c;
4 | var e;
5 | ```
6 |
--------------------------------------------------------------------------------
/test/patterns/import-labels-ace/actual.md:
--------------------------------------------------------------------------------
1 | [include:"tag",check:"false",edit:"true",theme:"monokai",template:"ace"](test.js)
2 |
--------------------------------------------------------------------------------
/examples/ace/user-template.hbs:
--------------------------------------------------------------------------------
1 | > {{fileName}}
2 |
3 | ``` {{lang}}
4 | {{{content}}}
5 | ```
--------------------------------------------------------------------------------
/examples/custom/user-template.hbs:
--------------------------------------------------------------------------------
1 | > {{fileName}}
2 |
3 | ``` {{lang}}
4 | {{{content}}}
5 | ```
--------------------------------------------------------------------------------
/test/patterns/import-codeblock-issues-55/test.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @example
3 | * ```js
4 | * a()
5 | * ```
6 | */
7 | function a(){
8 |
9 | }
--------------------------------------------------------------------------------
/test/patterns/import-custom-template/expected.md:
--------------------------------------------------------------------------------
1 | custom title "title" with id "foo"
2 | ``` javascript
3 | foo;
4 | bar;
5 | baz;
6 |
7 | ```
8 |
--------------------------------------------------------------------------------
/test/patterns/import-slice-only-first/expected.md:
--------------------------------------------------------------------------------
1 | ``` javascript
2 | console.log("this is line 9");
3 | console.log("this is line 10");
4 | ```
5 |
--------------------------------------------------------------------------------
/test/patterns/import-slice-only-last/expected.md:
--------------------------------------------------------------------------------
1 | ``` javascript
2 | console.log("this is line 1");
3 | console.log("this is line 2");
4 | ```
5 |
--------------------------------------------------------------------------------
/examples/ace/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # SUMMARY
2 |
3 | - [Readme](./README.md)
4 | - [Test markdown](./test_markdown.md)
5 | - [Test Asciidoc](./test_asciidoc.adoc)
6 |
--------------------------------------------------------------------------------
/test/patterns/import-infinity-loop-issue-57/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {}
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/examples/custom/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # SUMMARY
2 |
3 | - [Readme](./README.md)
4 | - [Test markdown](./test_markdown.md)
5 | - [Test Asciidoc](./test_asciidoc.adoc)
6 |
--------------------------------------------------------------------------------
/examples/default/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # SUMMARY
2 |
3 | - [Readme](./README.md)
4 | - [Test markdown](./test_markdown.md)
5 | - [Test Asciidoc](./test_asciidoc.adoc)
6 |
--------------------------------------------------------------------------------
/examples/ace/src/marker.ts:
--------------------------------------------------------------------------------
1 | function test(){
2 | //! [marker0]
3 | var a;
4 | //! [marker1]
5 | var b;
6 | //! [marker1]
7 | var c;
8 | //! [marker0]
9 | }
--------------------------------------------------------------------------------
/test/patterns/import-codeblock-issues-55/expected.md:
--------------------------------------------------------------------------------
1 | ```` javascript
2 | /**
3 | * @example
4 | * ```js
5 | * a()
6 | * ```
7 | */
8 | function a(){
9 |
10 | }
11 | ````
--------------------------------------------------------------------------------
/examples/custom/src/marker.ts:
--------------------------------------------------------------------------------
1 | function test(){
2 | //! [marker0]
3 | var a;
4 | //! [marker1]
5 | var b;
6 | //! [marker1]
7 | var c;
8 | //! [marker0]
9 | }
--------------------------------------------------------------------------------
/examples/default/src/marker.ts:
--------------------------------------------------------------------------------
1 | function test(){
2 | //! [marker0]
3 | var a;
4 | //! [marker1]
5 | var b;
6 | //! [marker1]
7 | var c;
8 | //! [marker0]
9 | }
--------------------------------------------------------------------------------
/test/patterns/import-unindent-slice/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | pluginsConfig: {
3 | "include-codeblock": {
4 | unindent: true
5 | }
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/test/patterns/import-ace-template/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {
4 | "template": "ace",
5 | }
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/test/patterns/import-codeblock-issues-55/book.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | module.exports = {
3 | "pluginsConfig": {
4 | "include-codeblock": {
5 | }
6 | }
7 | };
--------------------------------------------------------------------------------
/test/patterns/import-labels-ace/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {
4 | "template": "ace",
5 | }
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/test/patterns/import-snippet/test.ts:
--------------------------------------------------------------------------------
1 | function test(){
2 | //! [marker0]
3 | var a;
4 | //! [marker1]
5 | var b;
6 | //! [marker1]
7 | var c;
8 | //! [marker0]
9 | }
--------------------------------------------------------------------------------
/test/patterns/import-cpp-bug-workaround/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {
4 | "fixlang":"true"
5 | }
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/test/patterns/import-full-template/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {
4 | "template": "full",
5 | }
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/test/patterns/import-output-escape/actual.md:
--------------------------------------------------------------------------------
1 | [import, title:"title<1>", id:"edit:true<2>", lang:"javascript+theme:abc<3>", class="class<4>", edit=true, check=true, theme="monokai"](./test&1.js)
2 |
--------------------------------------------------------------------------------
/test/patterns/import-snippet-inner/test.ts:
--------------------------------------------------------------------------------
1 | function test(){
2 | //! [marker0]
3 | var a;
4 | //! [marker1]
5 | var b;
6 | //! [marker1]
7 | var c;
8 | //! [marker0]
9 | }
--------------------------------------------------------------------------------
/test/patterns/import-acefull-template/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {
4 | "template": "acefull",
5 | }
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/test/patterns/import-default-template/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {
4 | "template": "default",
5 | }
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/test/patterns/import-unindent/book.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | module.exports = {
3 | "pluginsConfig": {
4 | "include-codeblock": {
5 | "unindent": true
6 | }
7 | }
8 | };
--------------------------------------------------------------------------------
/templates/ace-template.hbs:
--------------------------------------------------------------------------------
1 | {% if file.type=="asciidoc" %}++++{% endif %}
2 | {%ace edit={{edit}}, check={{check}}, theme="{{theme}}", lang="{{lang}}" %}
3 | {{{content}}}
4 | {%endace%}
5 | {% if file.type=="asciidoc" %}++++{% endif %}
6 |
--------------------------------------------------------------------------------
/test/patterns/import-labels-ace/expected.md:
--------------------------------------------------------------------------------
1 | {% if file.type=="asciidoc" %}++++{% endif %}
2 | {%ace edit=true, check=false, theme="monokai", lang="javascript" %}
3 | bar;
4 | {%endace%}
5 | {% if file.type=="asciidoc" %}++++{% endif %}
6 |
--------------------------------------------------------------------------------
/examples/default/book.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | module.exports = {
3 | "gitbook": "3.x.x",
4 | "title": "gitbook-plugin-include-codeblock example-default",
5 | "plugins": [
6 | "include-codeblock"
7 | ]
8 | };
9 |
--------------------------------------------------------------------------------
/test/patterns/import-output-escape/book.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | module.exports = {
3 | "pluginsConfig": {
4 | "include-codeblock": {
5 | "template": path.join(__dirname, "dump.hbs")
6 | }
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/test/patterns/import-ace-template/expected.md:
--------------------------------------------------------------------------------
1 | {% if file.type=="asciidoc" %}++++{% endif %}
2 | {%ace edit=true, check=false, theme="chrome", lang="javascript" %}
3 | foo;
4 | bar;
5 | baz;
6 |
7 | {%endace%}
8 | {% if file.type=="asciidoc" %}++++{% endif %}
9 |
--------------------------------------------------------------------------------
/test/patterns/import-book-options/expected.md:
--------------------------------------------------------------------------------
1 | {% if file.type=="asciidoc" %}++++{% endif %}
2 | {%ace edit=true, check=true, theme="monokai", lang="javascript" %}
3 | foo;
4 | bar;
5 | baz;
6 |
7 | {%endace%}
8 | {% if file.type=="asciidoc" %}++++{% endif %}
9 |
--------------------------------------------------------------------------------
/test/patterns/import-book-command-options/expected.md:
--------------------------------------------------------------------------------
1 | {% if file.type=="asciidoc" %}++++{% endif %}
2 | {%ace edit=true, check=false, theme="monokai", lang="javascript" %}
3 | foo;
4 | bar;
5 | baz;
6 |
7 | {%endace%}
8 | {% if file.type=="asciidoc" %}++++{% endif %}
9 |
--------------------------------------------------------------------------------
/test/patterns/import-custom-template/book.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | module.exports = {
3 | "pluginsConfig": {
4 | "include-codeblock": {
5 | "template": path.join(__dirname,"../../fixtures/custom.hbs")
6 | }
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/test/patterns/import-full-template/expected.md:
--------------------------------------------------------------------------------
1 | {% if file.type=="asciidoc" %}
2 | > [[test.js]]link:test.js[test.js]
3 | {% else %}
4 | > test.js
5 | {% endif %}
6 |
7 | ``` javascript
8 | foo;
9 | bar;
10 | baz;
11 |
12 | ```
13 |
--------------------------------------------------------------------------------
/test/patterns/import-snippet-multi/test.ts:
--------------------------------------------------------------------------------
1 | function test(){
2 | //! [marker0]
3 | var a;
4 | //! [marker0]
5 | var b;
6 | //! [marker1]
7 | var c;
8 | //! [marker1]
9 | var d;
10 | //! [marker2]
11 | var e;
12 | //! [marker2]
13 | }
14 |
--------------------------------------------------------------------------------
/test/patterns/import-book-options/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {
4 | "template": "ace",
5 | "edit": "true",
6 | "check": "true",
7 | "theme": "monokai"
8 | }
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/test/patterns/import-book-command-options/book.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "pluginsConfig": {
3 | "include-codeblock": {
4 | "template": "default",
5 | "edit": "true",
6 | "check": "true",
7 | "theme": "monokai"
8 | }
9 | }
10 | };
11 |
--------------------------------------------------------------------------------
/test/patterns/import-output-escape/dump.hbs:
--------------------------------------------------------------------------------
1 | {{lang}}
2 | {{{lang}}}
3 |
4 | {{{content}}}
5 |
6 | {{originalPath}}
7 | {{{originalPath}}}
8 |
9 | {{fileName}}
10 | {{{fileName}}}
11 |
12 | {{title}}
13 | {{{title}}}
14 |
15 | {{id}}
16 | {{{id}}}
17 |
18 | {{class}}
19 | {{{class}}}
20 |
21 | {{edit}}
22 |
23 | {{check}}
24 |
25 | {{theme}}
26 |
--------------------------------------------------------------------------------
/test/fixtures/line.js:
--------------------------------------------------------------------------------
1 | console.log("this is line 1");
2 | console.log("this is line 2");
3 | console.log("this is line 3");
4 | console.log("this is line 4");
5 | console.log("this is line 5");
6 | console.log("this is line 6");
7 | console.log("this is line 7");
8 | console.log("this is line 8");
9 | console.log("this is line 9");
10 | console.log("this is line 10");
--------------------------------------------------------------------------------
/examples/ace/src/line.js:
--------------------------------------------------------------------------------
1 | console.log("this is line 1");
2 | console.log("this is line 2");
3 | console.log("this is line 3");
4 | console.log("this is line 4");
5 | console.log("this is line 5");
6 | console.log("this is line 6");
7 | console.log("this is line 7");
8 | console.log("this is line 8");
9 | console.log("this is line 9");
10 | console.log("this is line 10");
--------------------------------------------------------------------------------
/examples/custom/src/line.js:
--------------------------------------------------------------------------------
1 | console.log("this is line 1");
2 | console.log("this is line 2");
3 | console.log("this is line 3");
4 | console.log("this is line 4");
5 | console.log("this is line 5");
6 | console.log("this is line 6");
7 | console.log("this is line 7");
8 | console.log("this is line 8");
9 | console.log("this is line 9");
10 | console.log("this is line 10");
--------------------------------------------------------------------------------
/examples/default/src/line.js:
--------------------------------------------------------------------------------
1 | console.log("this is line 1");
2 | console.log("this is line 2");
3 | console.log("this is line 3");
4 | console.log("this is line 4");
5 | console.log("this is line 5");
6 | console.log("this is line 6");
7 | console.log("this is line 7");
8 | console.log("this is line 8");
9 | console.log("this is line 9");
10 | console.log("this is line 10");
--------------------------------------------------------------------------------
/examples/ace/book.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | module.exports = {
3 | "gitbook": "3.x.x",
4 | "title": "gitbook-plugin-include-codeblock example-ace",
5 | "plugins": [
6 | "include-codeblock",
7 | "ace"
8 | ],
9 | "pluginsConfig": {
10 | "include-codeblock": {
11 | "template": "ace"
12 | }
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/test/patterns/import-slice-only-first/line.js:
--------------------------------------------------------------------------------
1 | console.log("this is line 1");
2 | console.log("this is line 2");
3 | console.log("this is line 3");
4 | console.log("this is line 4");
5 | console.log("this is line 5");
6 | console.log("this is line 6");
7 | console.log("this is line 7");
8 | console.log("this is line 8");
9 | console.log("this is line 9");
10 | console.log("this is line 10");
--------------------------------------------------------------------------------
/test/patterns/import-slice-only-last/line.js:
--------------------------------------------------------------------------------
1 | console.log("this is line 1");
2 | console.log("this is line 2");
3 | console.log("this is line 3");
4 | console.log("this is line 4");
5 | console.log("this is line 5");
6 | console.log("this is line 6");
7 | console.log("this is line 7");
8 | console.log("this is line 8");
9 | console.log("this is line 9");
10 | console.log("this is line 10");
--------------------------------------------------------------------------------
/examples/ace/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## Test example
10 |
11 | Test full codes.
12 |
13 | test.js
14 |
15 | [import](./src/test.js)
16 |
17 | line.js
18 |
19 | [import](./src/line.js)
20 |
21 | test.ts
22 |
23 | [import](./src/test.ts)
24 |
25 | marker.ts
26 |
27 | [import](./src/marker.ts)
28 |
--------------------------------------------------------------------------------
/test/patterns/import-output-escape/expected.md:
--------------------------------------------------------------------------------
1 | javascript+theme:abc<3>
2 | javascript+theme:abc<3>
3 |
4 | foo;
5 | bar;
6 | baz;
7 |
8 |
9 | ./test&1.js
10 | ./test&1.js
11 |
12 | test&1.js
13 | test&1.js
14 |
15 | title<1>
16 | title<1>
17 |
18 | edit:true<2>
19 | edit:true<2>
20 |
21 | class<4>
22 | class<4>
23 |
24 | true
25 |
26 | true
27 |
28 | monokai
29 |
--------------------------------------------------------------------------------
/examples/custom/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## Test example
10 |
11 | Test full codes.
12 |
13 | test.js
14 |
15 | [import](./src/test.js)
16 |
17 | line.js
18 |
19 | [import](./src/line.js)
20 |
21 | test.ts
22 |
23 | [import](./src/test.ts)
24 |
25 | marker.ts
26 |
27 | [import](./src/marker.ts)
28 |
--------------------------------------------------------------------------------
/examples/default/README.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## Test example
10 |
11 | Test full codes.
12 |
13 | test.js
14 |
15 | [import](./src/test.js)
16 |
17 | line.js
18 |
19 | [import](./src/line.js)
20 |
21 | test.ts
22 |
23 | [import](./src/test.ts)
24 |
25 | marker.ts
26 |
27 | [import](./src/marker.ts)
28 |
--------------------------------------------------------------------------------
/test/patterns/import-acefull-template/expected.md:
--------------------------------------------------------------------------------
1 | {% if file.type=="asciidoc" %}
2 | > [[test.js]]link:test.js[test.js]
3 | {% else %}
4 | > test.js
5 | {% endif %}
6 |
7 | {% if file.type=="asciidoc" %}++++{% endif %}
8 | {%ace edit=false, check=false, theme="chrome", lang="javascript" %}
9 | foo;
10 | bar;
11 | baz;
12 |
13 | {%endace%}
14 | {% if file.type=="asciidoc" %}++++{% endif %}
15 |
--------------------------------------------------------------------------------
/examples/custom/book.js:
--------------------------------------------------------------------------------
1 | const path = require("path")
2 | const fs = require("fs");
3 | module.exports = {
4 | "gitbook": "3.x.x",
5 | "title": "gitbook-plugin-include-codeblock example-custom",
6 | "plugins": [
7 | "include-codeblock"
8 | ],
9 | "pluginsConfig": {
10 | "include-codeblock": {
11 | "template": path.join(__dirname,"user-template.hbs")
12 | }
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | # Unix-style newlines with a newline ending every file
4 | [*]
5 | end_of_line = lf
6 | insert_final_newline = true
7 |
8 | # Matches multiple files with brace expansion notation
9 | # Set default charset
10 | [*.{js}]
11 | charset = utf-8
12 | indent_style = space
13 | indent_size = 4
14 |
15 | # Matches the exact files either package.json or .travis.yml
16 | [{package.json,.travis.yml}]
17 | indent_style = space
18 | indent_size = 2
19 |
--------------------------------------------------------------------------------
/examples/ace/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-ace",
3 | "version": "1.0.0",
4 | "description": "gitbook-plugin-include-codeblock",
5 | "private": true,
6 | "scripts": {
7 | "start": "honkit serve",
8 | "build": "honkit build",
9 | "test": "yarn install && npm run build"
10 | },
11 | "keywords": [
12 | "gitbook"
13 | ],
14 | "author": "azu",
15 | "license": "MIT",
16 | "devDependencies": {
17 | "honkit": "^3.6.23",
18 | "gitbook-plugin-include-codeblock": "file:../../"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/examples/custom/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-custom",
3 | "version": "1.0.0",
4 | "description": "gitbook-plugin-include-codeblock",
5 | "private": true,
6 | "scripts": {
7 | "start": "honkit serve",
8 | "build": "honkit build",
9 | "test": "yarn install && npm run build"
10 | },
11 | "keywords": [
12 | "gitbook"
13 | ],
14 | "author": "azu",
15 | "license": "MIT",
16 | "devDependencies": {
17 | "honkit": "^3.6.23",
18 | "gitbook-plugin-include-codeblock": "file:../../"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/examples/default/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-default",
3 | "version": "1.0.0",
4 | "description": "gitbook-plugin-include-codeblock",
5 | "private": true,
6 | "scripts": {
7 | "start": "honkit serve",
8 | "build": "honkit build",
9 | "test": "yarn install && npm run build"
10 | },
11 | "keywords": [
12 | "gitbook"
13 | ],
14 | "author": "azu",
15 | "license": "MIT",
16 | "devDependencies": {
17 | "honkit": "^3.6.23",
18 | "gitbook-plugin-include-codeblock": "file:../../"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/test/title-test.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | const assert = require("assert");
4 | import { getTitle } from "../src/title";
5 |
6 | describe("title", function () {
7 | context("#getTitle", function () {
8 | it("should return the title", function () {
9 | const obj = {
10 | title: "an example of title",
11 | id: "test",
12 | marker: undefined
13 | };
14 | const title = getTitle(obj);
15 | assert.equal(title, "an example of title");
16 | });
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 | on: [push, pull_request]
3 | jobs:
4 | test:
5 | name: "Test on Node.js ${{ matrix.node-version }}"
6 | runs-on: ubuntu-latest
7 | strategy:
8 | matrix:
9 | node-version: [12, 14, 16]
10 | steps:
11 | - name: checkout
12 | uses: actions/checkout@v2
13 | - name: setup Node.js ${{ matrix.node-version }}
14 | uses: actions/setup-node@v2
15 | with:
16 | node-version: ${{ matrix.node-version }}
17 | - name: Install
18 | run: yarn install
19 | - name: Test
20 | run: yarn test
21 |
--------------------------------------------------------------------------------
/src/title.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | /*
3 | * Gibook usage:
4 | *
5 | * [import,title:](path/to/file)
6 | */
7 |
8 | /* Get the specified
9 | * @example:
10 | * getTitle(keyValObject)
11 | * @param {Object} keyValObject
12 | * @return {string}
13 | */
14 | export function getTitle(keyValObject) {
15 | return keyValObject.title;
16 | }
17 |
18 | /* Check if a title is specified in the option
19 | * @param {Object} keyValObject
20 | * @return {boolean}
21 | */
22 | export function hasTitle(keyValObject) {
23 | const title = getTitle(keyValObject);
24 | return title !== undefined;
25 | }
26 |
--------------------------------------------------------------------------------
/src/backtick-maker.js:
--------------------------------------------------------------------------------
1 | // MIT © 2017 azu
2 | "use strict";
3 |
4 | const codeBlockBackTick = /```/;
5 |
6 | /**
7 | * backtcik count is 3 by default.
8 | * But, We should increase backtick if content include ```.
9 | * https://github.com/azu/gitbook-plugin-include-codeblock/issues/55
10 | * https://stackoverflow.com/questions/33224686/how-to-render-triple-backticks-as-inline-code-block-in-markdown
11 | * @param {string} content
12 | * @return {string} codebloack begin/end backtick
13 | */
14 | export function codeBlockBacktick(content) {
15 | if (codeBlockBackTick.test(content)) {
16 | return "````";
17 | }
18 | return "```";
19 | }
20 |
--------------------------------------------------------------------------------
/examples/ace/test_asciidoc.adoc:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## import/include
10 |
11 | [import, test.js](./src/test.js)
12 |
13 | ## Hardcoded class
14 |
15 |
16 | [import, test.ts, lang-typescript](src/test.ts)
17 |
18 | ### Sliced Code
19 |
20 | [import:5-8](src/line.js)
21 |
22 | ### Snippet code
23 |
24 | [import:"marker0", lang-typescript](src/marker.ts)
25 |
26 |
27 | {% if file.type=="asciidoc" %}
28 | > link:test.js[test.js]
29 | {% else %}
30 | > test.js
31 | {% endif %}
32 |
33 | ``` javascript
34 | console.log("test");
35 | ```
36 |
--------------------------------------------------------------------------------
/examples/ace/test_markdown.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## import/include
10 |
11 | [import, test.js](./src/test.js)
12 |
13 | ## Hardcoded class
14 |
15 |
16 | [import, test.ts, lang-typescript](src/test.ts)
17 |
18 | ### Sliced Code
19 |
20 | [import:5-8](src/line.js)
21 |
22 | ### Snippet code
23 |
24 | [import:"marker0", lang-typescript](src/marker.ts)
25 |
26 |
27 | {% if file.type=="asciidoc" %}
28 | > link:test.js[test.js]
29 | {% else %}
30 | > test.js
31 | {% endif %}
32 |
33 | ``` javascript
34 | console.log("test");
35 | ```
36 |
--------------------------------------------------------------------------------
/examples/custom/test_asciidoc.adoc:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## import/include
10 |
11 | [import, test.js](./src/test.js)
12 |
13 | ## Hardcoded class
14 |
15 |
16 | [import, test.ts, lang-typescript](src/test.ts)
17 |
18 | ### Sliced Code
19 |
20 | [import:5-8](src/line.js)
21 |
22 | ### Snippet code
23 |
24 | [import:"marker0", lang-typescript](src/marker.ts)
25 |
26 |
27 | {% if file.type=="asciidoc" %}
28 | > link:test.js[test.js]
29 | {% else %}
30 | > test.js
31 | {% endif %}
32 |
33 | ``` javascript
34 | console.log("test");
35 | ```
36 |
--------------------------------------------------------------------------------
/examples/custom/test_markdown.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## import/include
10 |
11 | [import, test.js](./src/test.js)
12 |
13 | ## Hardcoded class
14 |
15 |
16 | [import, test.ts, lang-typescript](src/test.ts)
17 |
18 | ### Sliced Code
19 |
20 | [import:5-8](src/line.js)
21 |
22 | ### Snippet code
23 |
24 | [import:"marker0", lang-typescript](src/marker.ts)
25 |
26 |
27 | {% if file.type=="asciidoc" %}
28 | > link:test.js[test.js]
29 | {% else %}
30 | > test.js
31 | {% endif %}
32 |
33 | ``` javascript
34 | console.log("test");
35 | ```
36 |
--------------------------------------------------------------------------------
/examples/default/test_asciidoc.adoc:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## import/include
10 |
11 | [import, test.js](./src/test.js)
12 |
13 | ## Hardcoded class
14 |
15 |
16 | [import, test.ts, lang-typescript](src/test.ts)
17 |
18 | ### Sliced Code
19 |
20 | [import:5-8](src/line.js)
21 |
22 | ### Snippet code
23 |
24 | [import:"marker0", lang-typescript](src/marker.ts)
25 |
26 |
27 | {% if file.type=="asciidoc" %}
28 | > link:test.js[test.js]
29 | {% else %}
30 | > test.js
31 | {% endif %}
32 |
33 | ``` javascript
34 | console.log("test");
35 | ```
36 |
--------------------------------------------------------------------------------
/examples/default/test_markdown.md:
--------------------------------------------------------------------------------
1 | # Example
2 |
3 | ## Usage
4 |
5 | npm install
6 | npm start
7 | open http://localhost:4000/
8 |
9 | ## import/include
10 |
11 | [import, test.js](./src/test.js)
12 |
13 | ## Hardcoded class
14 |
15 |
16 | [import, test.ts, lang-typescript](src/test.ts)
17 |
18 | ### Sliced Code
19 |
20 | [import:5-8](src/line.js)
21 |
22 | ### Snippet code
23 |
24 | [import:"marker0", lang-typescript](src/marker.ts)
25 |
26 |
27 | {% if file.type=="asciidoc" %}
28 | > link:test.js[test.js]
29 | {% else %}
30 | > test.js
31 | {% endif %}
32 |
33 | ``` javascript
34 | console.log("test");
35 | ```
36 |
--------------------------------------------------------------------------------
/test/fixtures/marker.cpp:
--------------------------------------------------------------------------------
1 | // test.cpp source code
2 | int main()
3 | {
4 | // Test inner markers.
5 |
6 | //! [marker0]
7 | int a;
8 | //! [marker1]
9 | int b;
10 | //! [marker1]
11 | int c;
12 | //! [marker0]
13 |
14 | // Test different comment style.
15 |
16 | /** [marker2] */
17 | int d;
18 | /** [marker2] */
19 | /// [marker3]
20 | int e;
21 | /// [marker3]
22 |
23 | // Test different naming and spacing.
24 |
25 | /// [marker 4]
26 | int f;
27 | /// [marker 4]
28 |
29 | /// [marker5 space]
30 | int g;
31 | /// [marker5 space]
32 | /// [ marker 6 ]
33 | int h;
34 | /// [ marker 6 ]
35 | }
--------------------------------------------------------------------------------
/test/fixtures/template.hbs:
--------------------------------------------------------------------------------
1 | {{#if title}}
2 | {{#if id}}
3 | {% if file.type=="asciidoc" %}
4 | > [[{{id}}]]link:{{originalPath}}[{{title}}]
5 | {% else %}
6 | > {{title}}
7 | {% endif %}
8 | {{else}}
9 | {% if file.type=="asciidoc" %}
10 | > [[{{title}}]]link:{{originalPath}}[{{title}}]
11 | {% else %}
12 | > {{title}}
13 | {% endif %}
14 | {{/if}}
15 | {{else}}
16 | {% if file.type=="asciidoc" %}
17 | > [[{{fileName}}]]link:{{originalPath}}[{{fileName}}]
18 | {% else %}
19 | > {{fileName}}
20 | {% endif %}
21 | {{/if}}
22 |
23 | ``` {{lang}}
24 | {{{content}}}
25 | ```
--------------------------------------------------------------------------------
/templates/full-template.hbs:
--------------------------------------------------------------------------------
1 | {{#if title}}
2 | {{#if id}}
3 | {% if file.type=="asciidoc" %}
4 | > [[{{id}}]]link:{{originalPath}}[{{title}}]
5 | {% else %}
6 | > {{title}}
7 | {% endif %}
8 | {{else}}
9 | {% if file.type=="asciidoc" %}
10 | > [[{{title}}]]link:{{originalPath}}[{{title}}]
11 | {% else %}
12 | > {{title}}
13 | {% endif %}
14 | {{/if}}
15 | {{else}}
16 | {% if file.type=="asciidoc" %}
17 | > [[{{fileName}}]]link:{{originalPath}}[{{fileName}}]
18 | {% else %}
19 | > {{fileName}}
20 | {% endif %}
21 | {{/if}}
22 |
23 | {{{backtick}}} {{lang}}
24 | {{{content}}}
25 | {{{backtick}}}
--------------------------------------------------------------------------------
/src/include-codeblock.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | var path = require("path");
4 | import { parse } from "./parser";
5 | import { aceCheck } from "./ace-check";
6 |
7 | aceCheck();
8 |
9 | module.exports = {
10 | hooks: {
11 | "page:before": function (page) {
12 | var options = this.options.pluginsConfig["include-codeblock"];
13 | var pageDir = path.dirname(page.rawPath);
14 | var results = parse(page.content, pageDir, options);
15 | results.forEach((result) => {
16 | var { target, replaced } = result;
17 | page.content = page.content.replace(target, replaced);
18 | });
19 | return page;
20 | }
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | commonjs: true,
5 | node: true,
6 | es6: true,
7 | mocha: true
8 | },
9 | plugins: ["prettier"],
10 | extends: ["eslint:recommended"],
11 | parserOptions: {
12 | sourceType: "module"
13 | },
14 | rules: {
15 | "prettier/prettier": [
16 | "error",
17 | {
18 | singleQuote: false,
19 | printWidth: 120,
20 | tabWidth: 4,
21 | trailingComma: "none"
22 | }
23 | ],
24 | "prefer-const": "error",
25 | "no-console": 0,
26 | "no-extra-semi": 0,
27 | "no-mixed-spaces-and-tabs": 0
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/src/ace-check.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // Check that ace plugin is loaded after include-codeblock
3 | export function aceCheck() {
4 | // Check ace is used.
5 | try {
6 | require.resolve("gitbook-plugin-ace");
7 |
8 | // Check is not currently loaded.
9 | const aceLoaded = Boolean(require("module")._cache[require.resolve("gitbook-plugin-ace")]);
10 | if (aceLoaded) {
11 | console.log(""); // flush
12 | console.error("`gitbook-plugin-include-codeblock` plugin must be loaded before `gitbook-plugin-ace`!");
13 | }
14 | } catch (e) {
15 | console.log(""); // flush
16 | console.warn("ace features disabled (`gitbook-plugin-ace` required)");
17 | }
18 | }
19 |
20 | /* eslint-enable */
21 |
--------------------------------------------------------------------------------
/templates/acefull-template.hbs:
--------------------------------------------------------------------------------
1 | {{#if title}}
2 | {{#if id}}
3 | {% if file.type=="asciidoc" %}
4 | > [[{{id}}]]link:{{originalPath}}[{{title}}]
5 | {% else %}
6 | > {{title}}
7 | {% endif %}
8 | {{else}}
9 | {% if file.type=="asciidoc" %}
10 | > [[{{title}}]]link:{{originalPath}}[{{title}}]
11 | {% else %}
12 | > {{title}}
13 | {% endif %}
14 | {{/if}}
15 | {{else}}
16 | {% if file.type=="asciidoc" %}
17 | > [[{{fileName}}]]link:{{originalPath}}[{{fileName}}]
18 | {% else %}
19 | > {{fileName}}
20 | {% endif %}
21 | {{/if}}
22 |
23 | {% if file.type=="asciidoc" %}++++{% endif %}
24 | {%ace edit={{edit}}, check={{check}}, theme="{{theme}}", lang="{{lang}}" %}
25 | {{{content}}}
26 | {%endace%}
27 | {% if file.type=="asciidoc" %}++++{% endif %}
28 |
--------------------------------------------------------------------------------
/test/patterns/import-infinity-loop-issue-57/actual.md:
--------------------------------------------------------------------------------
1 | Issue by [Infinite loop with a specific markdown file · Issue #57 · azu/gitbook-plugin-include-codeblock](https://github.com/azu/gitbook-plugin-include-codeblock/issues/57 "Infinite loop with a specific markdown file · Issue #57 · azu/gitbook-plugin-include-codeblock")
2 |
3 | [\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890](\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890
4 |
--------------------------------------------------------------------------------
/test/patterns/import-infinity-loop-issue-57/expected.md:
--------------------------------------------------------------------------------
1 | Issue by [Infinite loop with a specific markdown file · Issue #57 · azu/gitbook-plugin-include-codeblock](https://github.com/azu/gitbook-plugin-include-codeblock/issues/57 "Infinite loop with a specific markdown file · Issue #57 · azu/gitbook-plugin-include-codeblock")
2 |
3 | [\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890[\1\2\34567890](\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890(\1\2\34567890
4 |
--------------------------------------------------------------------------------
/src/unescape-string.js:
--------------------------------------------------------------------------------
1 | // The code in this file is extracted from commonmark.js
2 | // (https://github.com/jgm/commonmark.js), which is owned by John MacFarlane.
3 | // LICENSE : BSD-2-Clause
4 | "use strict";
5 |
6 | var decodeHTML = require("entities").decodeHTML;
7 |
8 | var C_BACKSLASH = 92;
9 | var ENTITY = "&(?:#x[a-f0-9]{1,8}|#[0-9]{1,8}|[a-z][a-z0-9]{1,31});";
10 | var reBackslashOrAmp = /[\\&]/;
11 | var ESCAPABLE = "[!\"#$%&'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]";
12 | var reEntityOrEscapedChar = new RegExp("\\\\" + ESCAPABLE + "|" + ENTITY, "gi");
13 |
14 | function unescapeChar(s) {
15 | if (s.charCodeAt(0) === C_BACKSLASH) {
16 | return s.charAt(1);
17 | } else {
18 | return decodeHTML(s);
19 | }
20 | }
21 |
22 | // Replace entities and backslash escapes with literal characters.
23 | export function unescapeString(s) {
24 | if (reBackslashOrAmp.test(s)) {
25 | return s.replace(reEntityOrEscapedChar, unescapeChar);
26 | } else {
27 | return s;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/bin/include-codeblock.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | 'use strict';
3 | const meow = require('meow');
4 | const fs = require('fs');
5 | const path = require('path');
6 | const parse = require("../lib/parser").parse;
7 | const cli = meow(`
8 | Usage
9 | $ include-codeblock --output
10 |
11 | Options
12 | --output Output to write index json file
13 |
14 | Other Options:
15 | same with gitbook config
16 | For example, --unindent=true
17 |
18 | Example:
19 | $ include-codeblock ./README.md --output RENDER_README.md
20 | `);
21 | // main
22 | const input = cli.input[0];
23 | if (!input) {
24 | cli.showHelp();
25 | }
26 | const inputContent = fs.readFileSync(input, "utf-8");
27 | const baseDir = path.dirname(path.resolve(process.cwd(), input));
28 | const replacements = parse(inputContent, baseDir, cli.flags);
29 | const replaceContent = (inputContent, replacements) => {
30 | replacements.forEach(result => {
31 | const { target, replaced } = result;
32 | inputContent = inputContent.replace(target, replaced);
33 | });
34 | return inputContent;
35 | };
36 | const outputContent = replaceContent(inputContent, replacements);
37 | if (cli.flags.output) {
38 | fs.writeFileSync(cli.flags.output, outputContent, "utf-8");
39 | } else {
40 | console.log(outputContent);
41 | }
42 |
--------------------------------------------------------------------------------
/src/template.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | const fs = require("fs");
4 | import { defaultBookOptionsMap, defaultTemplateMap } from "./options.js";
5 |
6 | /**
7 | * Sunc file read with path check
8 | * @param {string} path
9 | * @return {string}
10 | */
11 | export function readFileFromPath(path) {
12 | let content;
13 | try {
14 | content = fs.readFileSync(path, "utf8");
15 | } catch (err) {
16 | if (err.code === "ENOENT") {
17 | console.warn("Error: file not found: " + path);
18 | return "Error: file not found: " + path;
19 | } else {
20 | throw err;
21 | }
22 | }
23 | return content;
24 | }
25 |
26 | /**
27 | * Load template from template label
28 | * @param {object} kvMap
29 | * @return {string}
30 | */
31 | export function getTemplateContent(kvMap) {
32 | const t = kvMap.template;
33 | const dt = defaultBookOptionsMap.template;
34 | const tPath = defaultTemplateMap[t];
35 | const dtPath = defaultTemplateMap[dt];
36 |
37 | const isTemplateDefault = t === dt;
38 | const isTemplatePath = tPath === undefined;
39 |
40 | let p;
41 | // No template option.
42 | if (isTemplateDefault) {
43 | p = dtPath;
44 | } else if (isTemplatePath) {
45 | // Template option is a path.
46 | p = t;
47 | } else {
48 | // Template option one of template/ directory.
49 | p = tPath || dtPath;
50 | }
51 | return readFileFromPath(p);
52 | }
53 |
--------------------------------------------------------------------------------
/test/generate-test.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | const assert = require("assert");
4 | const fs = require("fs");
5 | const path = require("path");
6 | import { parse } from "../src/parser";
7 | function trim(str) {
8 | return str.replace(/^\s+|\s+$/, "");
9 | }
10 |
11 | describe("generate test", () => {
12 | const fixturesDir = path.join(__dirname, "patterns");
13 | fs.readdirSync(fixturesDir).map((caseName) => {
14 | it(`should ${caseName.split("-").join(" ")}`, () => {
15 | const fixtureDir = path.join(fixturesDir, caseName);
16 | let actualPath = path.join(fixtureDir, "actual.md");
17 | let content = fs.readFileSync(actualPath, "utf-8");
18 | const bookjs = path.join(fixtureDir, "book.js");
19 | const options = {};
20 | try {
21 | const book = require(bookjs);
22 | Object.assign(options, book.pluginsConfig["include-codeblock"]);
23 | } catch (e) {
24 | // no book
25 | }
26 | const results = parse(content, fixtureDir, options);
27 | results.forEach((result) => {
28 | const { target, replaced } = result;
29 | content = content.replace(target, replaced);
30 | });
31 | if (path.sep === "\\") {
32 | // Specific case of windows, transformFileSync return code with '/'
33 | actualPath = actualPath.replace(/\\/g, "/");
34 | }
35 |
36 | const expected = fs
37 | .readFileSync(path.join(fixtureDir, "expected.md"))
38 | .toString()
39 | .replace(/%FIXTURE_PATH%/g, actualPath);
40 | assert.equal(trim(content), trim(expected));
41 | return true;
42 | });
43 | return true;
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /lib
2 | _book/
3 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Node.gitignore
4 |
5 | # Logs
6 | logs
7 | *.log
8 |
9 | # Runtime data
10 | pids
11 | *.pid
12 | *.seed
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directory
30 | # Commenting this out is preferred by some people, see
31 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
32 | node_modules
33 |
34 |
35 | ### https://raw.github.com/github/gitignore/408c616ae0ad8f4b8101d8e876b9b67ac6b14059/Global/JetBrains.gitignore
36 |
37 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
38 |
39 | *.iml
40 |
41 | ## Directory-based project format:
42 | .idea/
43 | # if you remove the above rule, at least ignore the following:
44 |
45 | # User-specific stuff:
46 | # .idea/workspace.xml
47 | # .idea/tasks.xml
48 | # .idea/dictionaries
49 |
50 | # Sensitive or high-churn files:
51 | # .idea/dataSources.ids
52 | # .idea/dataSources.xml
53 | # .idea/sqlDataSources.xml
54 | # .idea/dynamic.xml
55 | # .idea/uiDesigner.xml
56 |
57 | # Gradle:
58 | # .idea/gradle.xml
59 | # .idea/libraries
60 |
61 | # Mongo Explorer plugin:
62 | # .idea/mongoSettings.xml
63 |
64 | ## File-based project format:
65 | *.ipr
66 | *.iws
67 |
68 | ## Plugin-specific files:
69 |
70 | # IntelliJ
71 | out/
72 |
73 | # mpeltonen/sbt-idea plugin
74 | .idea_modules/
75 |
76 | # JIRA plugin
77 | atlassian-ide-plugin.xml
78 |
79 | # Crashlytics plugin (for Android Studio and IntelliJ)
80 | com_crashlytics_export_strings.xml
81 | crashlytics.properties
82 | crashlytics-build.properties
83 |
84 |
85 | /.eslintcache
86 |
--------------------------------------------------------------------------------
/src/slicer.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | /*
4 | format: [import:-](path/to/file)
5 | lineNumber start with 1.
6 |
7 | Patterns:
8 |
9 | All: [import, hello-world.js](../src/hello-world.js)
10 | 1-2: [import:1-2, hello-world.js](../src/hello-world.js)
11 | 2-3: [import:2-3, hello-world.js](../src/hello-world.js)
12 | 2>=: [import:2-, hello-world.js](../src/hello-world.js)
13 | <=3: [import:-3, hello-world.js](../src/hello-world.js)
14 | */
15 | /**
16 | * get range from label
17 | * @param {string} label
18 | * @returns {number[]}
19 | */
20 | export function getSliceRange(label) {
21 | const regExp = /^(?:include|import):(\d*)-(\d*)[,\s]?.*$/;
22 | const matches = regExp.exec(label);
23 | if (matches === null) {
24 | return [];
25 | }
26 | // return [undefined, undefined] if not matched, else contains [all,start,end].
27 | const [start, end] = matches.slice(1, 3);
28 | const startOrUndefined = start !== "" ? parseInt(start, 10) : undefined;
29 | const endOrUndefined = end !== "" ? parseInt(end, 10) : undefined;
30 | return [startOrUndefined, endOrUndefined];
31 | }
32 |
33 | /**
34 | * has range command in the label
35 | * @param {string} label
36 | * @returns {boolean}
37 | */
38 | export function hasSliceRange(label) {
39 | const range = getSliceRange(label);
40 | const [start, end] = range;
41 | return start !== undefined || end !== undefined;
42 | }
43 |
44 | /**
45 | * slice {@link code} with {@link start} and {@link end}
46 | * @param {string} code
47 | * @param {number|undefined} [start]
48 | * @param {number|undefined} [end]
49 | * @param {boolean|undefined} [untrimmed]
50 | * @returns {string}
51 | */
52 | export function sliceCode(code, start, end, untrimmed) {
53 | if (start === undefined && end === undefined) {
54 | return code;
55 | }
56 | const slitted = code.split("\n");
57 | if (start === undefined) {
58 | start = 1;
59 | }
60 | if (end === undefined) {
61 | end = slitted.length;
62 | }
63 | const sliced = slitted.slice(start - 1, end).join("\n");
64 | return untrimmed ? sliced : sliced.trim();
65 | }
66 |
--------------------------------------------------------------------------------
/templates/README.md:
--------------------------------------------------------------------------------
1 | # Template
2 |
3 | - Should remove space each line
4 | - `{{` and `}}` is GitBook template
5 | - [Templating · GitBook Toolchain Documentation](http://toolchain.gitbook.com/templating/)
6 | - `{%` and `%}` is handlebar template
7 | - [Handlebars.js: Minimal Templating on Steroids](http://handlebarsjs.com/)
8 |
9 | ## Values
10 |
11 | - `{{lang}}`: language for highlight
12 | - `{{{content}}}`: Code
13 | - `{{originalPath}}`: file path
14 | - `{{fileName}}`: file name
15 | - `{{count}}` : number of CodeBlock
16 | - `{{title}}`: if label contain `title:` like this `[import, title:]`
17 | - `{{id}}`: if label contain `id:` like this `[import, id:]`
18 | - `{{class}}`: if label contain `class:` like this `[import, class:]`
19 |
20 | ### ace plugin specific
21 |
22 | - {{edit}} : allow code edition
23 | - {{check}} : allow syntax validation
24 | - {{theme}} : label for the theme
25 |
26 | ## Limitation
27 |
28 | You should write with no space(indent).
29 | Spacing conflict GitBook behavior.
30 |
31 | ## Template Example
32 |
33 | Version 1.x template.
34 |
35 | {{#if title}}
36 | {{#if id}}
37 | {% if file.type=="asciidoc" %}
38 | > [[{{id}}]]link:{{originalPath}}[{{title}}]
39 | {% else %}
40 | > {{title}}
41 | {% endif %}
42 | {{else}}
43 | {% if file.type=="asciidoc" %}
44 | > [[{{title}}]]link:{{originalPath}}[{{title}}]
45 | {% else %}
46 | > {{title}}
47 | {% endif %}
48 | {{/if}}
49 | {{else}}
50 | {% if file.type=="asciidoc" %}
51 | > [[{{fileName}}]]link:{{originalPath}}[{{fileName}}]
52 | {% else %}
53 | > {{fileName}}
54 | {% endif %}
55 | {{/if}}
56 |
57 | ``` {{lang}}
58 | {{{content}}}
59 | ```
60 |
61 | ### Compile Example
62 |
63 | If use version 1.x template
64 |
65 | [import](test.rs)
66 |
67 | to be
68 |
69 | {% if file.type=="asciidoc" %}
70 | > [[test.rs]]link:test.rs[test.rs]
71 | {% else %}
72 | > test.rs
73 | {% endif %}
74 |
75 | ``` rust
76 | extern crate num;
77 | ```
78 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 azu
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
21 | ---
22 |
23 | src/unescape-string.js is extracted from https://github.com/jgm/commonmark.js:
24 |
25 | Copyright (c) 2014, John MacFarlane
26 |
27 | All rights reserved.
28 |
29 | Redistribution and use in source and binary forms, with or without
30 | modification, are permitted provided that the following conditions are met:
31 |
32 | * Redistributions of source code must retain the above copyright
33 | notice, this list of conditions and the following disclaimer.
34 |
35 | * Redistributions in binary form must reproduce the above
36 | copyright notice, this list of conditions and the following
37 | disclaimer in the documentation and/or other materials provided
38 | with the distribution.
39 |
40 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 |
--------------------------------------------------------------------------------
/test/language-detection-test.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | const assert = require("assert");
4 | import { defaultKeyValueMap } from "../src/options.js";
5 | import { getLang, lookupLanguageByAceMode, lookupLanguageByExtension } from "../src/language-detection";
6 |
7 | const kvmap = defaultKeyValueMap;
8 |
9 | describe("language-detection", function () {
10 | describe("#lookupLanguageByAceMode", function () {
11 | it("should resolve language type by acemode", function () {
12 | const kvm = Object.assign({}, kvmap);
13 | kvm.lang = "typescript";
14 | const aceMode = lookupLanguageByAceMode(kvm);
15 | assert.equal(aceMode, "typescript");
16 | });
17 | });
18 | describe("#lookupLanguageByExtension", function () {
19 | context("lang ext or file ext", function () {
20 | it("should resolve acemode by lang ext", function () {
21 | const kvm = Object.assign({}, kvmap);
22 | kvm.lang = ".js";
23 | const aceMode = lookupLanguageByExtension(kvm, "/path/to/file.rs");
24 | assert.equal(aceMode, "javascript");
25 | });
26 | it("should resolve acemode by file ext", function () {
27 | const aceMode = lookupLanguageByExtension(kvmap, "/path/to/file.rs");
28 | assert.equal(aceMode, "rust");
29 | });
30 | });
31 | });
32 | describe("#getLang", function () {
33 | context("specified aceMode", function () {
34 | it("should prefer use aceMode", function () {
35 | const kvm = Object.assign({}, kvmap);
36 | kvm.lang = "typescript";
37 | Object.freeze(kvm);
38 | const kvml = getLang(kvm, "/path/to/file.js");
39 | const lang = kvml.lang;
40 | assert.equal(lang, "typescript");
41 | });
42 | it("should detect using aceMode", function () {
43 | const kvm = Object.assign({}, kvmap);
44 | kvm.lang = "typescript";
45 | Object.freeze(kvm);
46 | const kvml = getLang(kvm, "/path/to/file.ts");
47 | const lang = kvml.lang;
48 | assert.equal(lang, "typescript");
49 | });
50 | it("should detect use default, aceMode not found (+warn)", function () {
51 | const kvml = getLang(kvmap, "/path/to/file.fakext");
52 | const lang = kvml.lang;
53 | assert.equal(lang, "");
54 | });
55 | });
56 | context("other using ext", function () {
57 | it("should detect using ext", function () {
58 | const kvml = getLang(kvmap, "/path/to/file.rs");
59 | const lang = kvml.lang;
60 | assert.equal(lang, "rust");
61 | });
62 | });
63 | });
64 | });
65 |
--------------------------------------------------------------------------------
/src/language-detection.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | const path = require("path");
4 | const languageMap = require("language-map");
5 | import { defaultKeyValueMap } from "./options.js";
6 |
7 | // Workaround for not working languages.
8 | // Redefine aceMode locally.
9 | // @param {string}
10 | // @return {string}
11 | export function languageAceModeFix(resultAceMode) {
12 | if (resultAceMode == "c_cpp") {
13 | resultAceMode = "cpp";
14 | }
15 | return resultAceMode;
16 | }
17 |
18 | /**
19 | * Return aceMode from lang in kvMap.
20 | * @param {object} kvMap
21 | * @return {object}
22 | */
23 | export function lookupLanguageByAceMode(kvMap) {
24 | let resultAceMode;
25 | const matchLang = kvMap.lang;
26 | Object.keys(languageMap).some((langKey) => {
27 | const aceMode = languageMap[langKey].aceMode;
28 | if (matchLang === aceMode) {
29 | resultAceMode = aceMode;
30 | return resultAceMode;
31 | }
32 | return undefined;
33 | });
34 | return resultAceMode;
35 | }
36 |
37 | /**
38 | * Return aceMode from file extension or lang in kvMap, if is
39 | * an extension.
40 | * @param {object} kvMap
41 | * @param {string} filePath
42 | * @return {object}
43 | */
44 | export function lookupLanguageByExtension(kvMap, filePath) {
45 | const lang = kvMap.lang;
46 | let ext;
47 | // Check first if map `lang` is an extension string.
48 | const matchext = /(.+)/g.exec(lang);
49 | if (matchext != null) {
50 | ext = matchext[1];
51 | } else {
52 | // Load from file extension.
53 | ext = path.extname(filePath);
54 | }
55 | let aceMode;
56 | Object.keys(languageMap).some((langKey) => {
57 | const extensions = languageMap[langKey].extensions;
58 | if (!extensions) {
59 | return false;
60 | }
61 | return extensions.some((extension) => {
62 | if (ext === extension) {
63 | aceMode = languageMap[langKey].aceMode;
64 | }
65 | return false;
66 | });
67 | });
68 | return aceMode;
69 | }
70 |
71 | /**
72 | * Update key-value map lang with aceMode lang.
73 | * @param {object} kvMap
74 | * @param {string} filePath
75 | * @return {object}
76 | */
77 | export function getLang(kvMap, filePath) {
78 | let aceMode;
79 | // Retrieve ace mode from lang.
80 | if (kvMap.lang !== defaultKeyValueMap.lang) {
81 | aceMode = lookupLanguageByAceMode(kvMap);
82 | }
83 | // Retrieve ace mode from file ext or lang ext.
84 | if (aceMode === undefined) {
85 | aceMode = lookupLanguageByExtension(kvMap, filePath);
86 | }
87 | // Ace mode not found, keep default.
88 | if (aceMode === undefined) {
89 | console.warn("include-codeblock: unknown language `" + kvMap.lang + "`, use default");
90 | return kvMap;
91 | }
92 | if (kvMap.fixlang) {
93 | aceMode = languageAceModeFix(aceMode);
94 | }
95 | const kvm = Object.assign({}, kvMap);
96 | kvm.lang = aceMode;
97 | return Object.freeze(kvm);
98 | }
99 |
--------------------------------------------------------------------------------
/src/marker.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | /*
3 | * Feature: doxygen like snippet code.
4 | * For code source documenting, see
5 | * https://www.stack.nl/~dimitri/doxygen/manual/commands.html#cmdsnippet
6 | *
7 | * Gibook usage:
8 | *
9 | * [import:](path/to/file)
10 | *
11 | * NB: markername must begin with a letter to avoid conflict with slice
12 | * line range.
13 | */
14 | "use strict";
15 | const commentOpen = "(/+/+|#|%|/\\*|)?";
17 | const doxChar = "[*!/#]"; // doxygen documentation character
18 | const spaces = "[ \t]*"; // h spaces
19 | const spacesAny = "\\s*"; // h+v spaces
20 | const markerNameFormat = "(\\s*[a-zA-Z][\\w\\s]*)"; // Must contain a char.
21 |
22 | /*
23 | * format: [import:](path/to/file)
24 | * @param {Object} keyValObject
25 | * @return {string}
26 | */
27 | export function getMarker(keyValObject) {
28 | return keyValObject.marker;
29 | }
30 |
31 | /**
32 | * format: [import:](path/to/file)
33 | * check if the import filled has a markername.
34 | * @example:
35 | * hasMarker(label)
36 | * @param {Object} keyValObject
37 | * @returns {boolean}
38 | */
39 | export function hasMarker(keyValObject) {
40 | const marker = getMarker(keyValObject);
41 | return marker !== undefined && marker !== "";
42 | }
43 |
44 | /* Parse the code from given markers
45 | *
46 | * see test/marker-test.js
47 | */
48 | /**
49 | * get sliced code by {@link markername}
50 | * @param {string} code
51 | * @param {string} markers
52 | * @returns {string}
53 | */
54 | export function markerSliceCode(code, markers) {
55 | if (markers === undefined || markers === "") {
56 | return code;
57 | }
58 | var parsedcode = "";
59 | const markerlist = markers.split(",");
60 |
61 | let i = 0;
62 | // regex
63 | markerlist.forEach((marker) => {
64 | const balise = "\\[" + marker + "\\]";
65 | const pattern = "\\n" + spacesAny + commentOpen + doxChar + spaces + balise + spaces + commentClose + spaces;
66 |
67 | const regstr = pattern + "\\n*([\\s\\S]*)" + pattern;
68 | const reg = new RegExp(regstr);
69 | const res = code.match(reg);
70 |
71 | if (res) {
72 | parsedcode += res[3]; // count parenthesis in pattern.
73 | } else {
74 | console.warn("markersSliceCode(): marker `" + marker + "` not found");
75 | parsedcode += "Error: marker `" + marker + "` not found";
76 | }
77 | if (markerlist.length > 0 && i < markerlist.length - 1) {
78 | parsedcode += "\n";
79 | }
80 | i++;
81 | });
82 | return parsedcode;
83 | }
84 |
85 | /** Replace all regex occurence by sub in the string str,
86 | * @param {string} str
87 | * @param {string} reg
88 | * @param {string} sub
89 | * @return {string}
90 | */
91 | export function replaceAll(str, reg, sub) {
92 | return str.replace(new RegExp(reg, "g"), sub);
93 | }
94 |
95 | /** Function that remove all markers in the given code
96 | * @param {string} code
97 | * @return {string}
98 | */
99 | export function removeMarkers(code) {
100 | // various language comment
101 | const tag = "\\[" + markerNameFormat + "\\]";
102 | const pattern = spacesAny + commentOpen + doxChar + spaces + tag + spaces + commentClose + spaces;
103 |
104 | return replaceAll(code, pattern, "");
105 | }
106 |
--------------------------------------------------------------------------------
/src/options.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | // Notes:
3 | // 1) If you add new options type, you have to update type checks in parser.js
4 | // (see parseVariableFromMap).
5 | // 2) The default map (objects) are immutable (frozen). They are updated (new map
6 | // with different names) while parsing book.json options first, then eventually
7 | // overwriten by commands options.
8 | "use strict";
9 | const path = require("path");
10 | const cfg = require("../package.json").gitbook.properties;
11 |
12 | export const defaultTemplateMap = Object.freeze({
13 | default: path.join(__dirname, "..", "templates", "default-template.hbs"),
14 | full: path.join(__dirname, "..", "templates", "full-template.hbs"),
15 | ace: path.join(__dirname, "..", "templates", "ace-template.hbs"),
16 | acefull: path.join(__dirname, "..", "templates", "acefull-template.hbs")
17 | });
18 |
19 | // Map for Book.json options. (avoid `undefined` for ace options),
20 | // NB: Default book option, type, desc are set in the package.json file.
21 | export const defaultBookOptionsMap = Object.freeze({
22 | check: cfg.check.default,
23 | edit: cfg.edit.default,
24 | lang: cfg.lang.default,
25 | fixlang: cfg.fixlang.default,
26 | template: cfg.template.default,
27 | theme: cfg.theme.default,
28 | unindent: cfg.unindent.default
29 | });
30 |
31 | // Possible command key-values (kv).
32 | // (avoid undefined default value because we check value types).
33 | export const defaultKeyValueMap = Object.freeze({
34 | // Local
35 | class: "",
36 | id: "",
37 | marker: "",
38 | name: "",
39 | title: "",
40 | // Global/Local
41 | check: defaultBookOptionsMap.check,
42 | edit: defaultBookOptionsMap.edit,
43 | lang: defaultBookOptionsMap.lang,
44 | fixlang: defaultBookOptionsMap.fixlang,
45 | template: defaultBookOptionsMap.template,
46 | theme: defaultBookOptionsMap.theme,
47 | unindent: defaultBookOptionsMap.unindent
48 | });
49 |
50 | /**
51 | * Convert string value to value type.
52 | * @param {string} valtype
53 | */
54 | export function convertValue(valstr, valtype) {
55 | // remove quotes
56 | if (valtype === "boolean" || valtype === "number") {
57 | return JSON.parse(valstr);
58 | }
59 | return valstr;
60 | }
61 |
62 | /**
63 | * Check that maps types equal to default key value map.
64 | * @param {object} kvMap
65 | * @param {string} funcLabel
66 | */
67 | export function checkMapTypes(kvMap, funcLabel) {
68 | Object.keys(kvMap).forEach((key) => {
69 | if (defaultKeyValueMap[key] !== undefined) {
70 | const leftType = typeof kvMap[key];
71 | const rightType = typeof defaultKeyValueMap[key];
72 | if (!(leftType === rightType)) {
73 | console.error(
74 | `include-codeblock: checkMapTypes (${funcLabel}) : wrong value type for key \`${key}\`: key type: \`${leftType}\` (!= \`${rightType}\`)`
75 | );
76 | }
77 | }
78 | });
79 | }
80 |
81 | /**
82 | * Check that maps types equal to default key value map.
83 | * @param {{template?: string}} options
84 | * @return {object} kvMap
85 | */
86 | export function initOptions(options) {
87 | const dbom = defaultBookOptionsMap;
88 | const kv = Object.assign({}, defaultKeyValueMap);
89 | // Overwrite default value with user book options.
90 | Object.keys(dbom).forEach((key) => {
91 | if (options[key] != undefined) {
92 | kv[key] = convertValue(options[key], typeof dbom[key]);
93 | }
94 | });
95 | const kvmap = Object.freeze(kv);
96 | checkMapTypes(kvmap, "initOptions");
97 | return kvmap;
98 | }
99 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "gitbook-plugin-include-codeblock",
3 | "repository": {
4 | "type": "git",
5 | "url": "https://github.com/azu/gitbook-plugin-include-codeblock.git"
6 | },
7 | "author": "azu",
8 | "email": "azuciao@gmail.com",
9 | "homepage": "https://github.com/azu/gitbook-plugin-include-codeblock",
10 | "license": "MIT",
11 | "bugs": {
12 | "url": "https://github.com/azu/gitbook-plugin-include-codeblock/issues"
13 | },
14 | "version": "3.2.3",
15 | "description": "GitBook plugin for including file",
16 | "main": "lib/include-codeblock.js",
17 | "bin": {
18 | "include-codeblock": "./bin/include-codeblock.js"
19 | },
20 | "files": [
21 | "bin",
22 | "lib",
23 | "templates",
24 | "src"
25 | ],
26 | "directories": {
27 | "test": "test"
28 | },
29 | "scripts": {
30 | "build": "NODE_ENV=production babel src --out-dir lib --source-maps",
31 | "lint": "eslint --cache src/*.js test/*.js",
32 | "lint:fix": "eslint --fix src/*.js test/*.js",
33 | "watch": "babel src --out-dir lib --watch --source-maps",
34 | "prepublish": "npm run --if-present build",
35 | "test": "npm run lint && mocha",
36 | "test:example-default": "cd examples/default && yarn && npm run build",
37 | "test:example-ace": "cd examples/ace && yarn && npm run build",
38 | "test:example-custom": "cd examples/custom && yarn && npm run build",
39 | "eslint-check": "eslint --print-config .eslintrc.js | eslint-config-prettier-check",
40 | "format": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"",
41 | "prepare": "git config --local core.hooksPath .githooks"
42 | },
43 | "keywords": [
44 | "gitbook",
45 | "plugin",
46 | "gitbook-plugin"
47 | ],
48 | "engines": {
49 | "gitbook": "*"
50 | },
51 | "gitbook": {
52 | "properties": {
53 | "check": {
54 | "type": "boolean",
55 | "description": "ace syntax validation (ace* template required)",
56 | "default": false,
57 | "required": false
58 | },
59 | "edit": {
60 | "type": "boolean",
61 | "description": "ace code edition (ace* template required)",
62 | "default": false,
63 | "required": false
64 | },
65 | "lang": {
66 | "type": "string",
67 | "description": "language for all codes",
68 | "default": "",
69 | "required": false
70 | },
71 | "fixlang": {
72 | "type": "boolean",
73 | "description": "Fix lang label (c++,...)",
74 | "default": false,
75 | "required": false
76 | },
77 | "template": {
78 | "type": "string",
79 | "description": "Template string",
80 | "default": "default",
81 | "required": false
82 | },
83 | "theme": {
84 | "type": "string",
85 | "description": "ace code editor theme (ace* template required)",
86 | "default": "chrome",
87 | "required": false
88 | },
89 | "unindent": {
90 | "type": "boolean",
91 | "description": "undindent inner snippets",
92 | "default": false,
93 | "required": false
94 | }
95 | }
96 | },
97 | "dependencies": {
98 | "entities": "^1.1.1",
99 | "handlebars": "^4.0.5",
100 | "language-map": "^1.1.1",
101 | "meow": "^4.0.0"
102 | },
103 | "devDependencies": {
104 | "@babel/cli": "^7.0.0",
105 | "@babel/core": "^7.0.0",
106 | "@babel/preset-env": "^7.0.0",
107 | "@babel/register": "^7.0.0",
108 | "eslint": "^8.6.0",
109 | "eslint-config-prettier": "^8.3.0",
110 | "eslint-plugin-prettier": "^4.0.0",
111 | "lint-staged": "^12.1.7",
112 | "mocha": "^9.1.3",
113 | "prettier": "^2.5.1"
114 | },
115 | "prettier": {
116 | "singleQuote": false,
117 | "printWidth": 120,
118 | "tabWidth": 4,
119 | "trailingComma": "none"
120 | },
121 | "lint-staged": {
122 | "*.{js,jsx,ts,tsx,css}": [
123 | "prettier --write"
124 | ]
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/test/slicer-test.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | const assert = require("assert");
4 | const fs = require("fs");
5 | const path = require("path");
6 | import { getSliceRange, hasSliceRange, sliceCode } from "../src/slicer";
7 | const lineFixture = fs.readFileSync(path.join(__dirname, "fixtures/line.js"), "utf-8");
8 | describe("slicer-test", function () {
9 | describe("#hasSliceRange", function () {
10 | context("when range is defined", function () {
11 | it("should return [undefined, undefined]", function () {
12 | assert(hasSliceRange("import:0-0 ,"));
13 | assert(hasSliceRange("import:1-2 ,"));
14 | assert(hasSliceRange("import:2-3 ,"));
15 | assert(hasSliceRange("import:2- ,"));
16 | assert(hasSliceRange("import:-3 ,"));
17 | });
18 | });
19 | context("when range is not defined", function () {
20 | it("should return [undefined, undefined]", function () {
21 | assert(!hasSliceRange("import:0"));
22 | assert(!hasSliceRange("import:test"));
23 | assert(!hasSliceRange("import"));
24 | assert(!hasSliceRange("1-5 only"));
25 | assert(!hasSliceRange("1-5"));
26 | });
27 | });
28 | });
29 | describe("#getSliceRange", function () {
30 | it("should return [start,end]", function () {
31 | const [start, end] = getSliceRange("import:1-5 , label");
32 | assert.equal(start, 1);
33 | assert.equal(end, 5);
34 | });
35 | context("when not defined range", function () {
36 | it("should return [undefined, undefined]", function () {
37 | const [start, end] = getSliceRange("import:test");
38 | assert(start === undefined);
39 | assert(end === undefined);
40 | });
41 | });
42 | context("when `import:1-2, hello-world.js`", function () {
43 | it("should return [1, 2]", function () {
44 | const [start, end] = getSliceRange("import:1-2, hello-world.js");
45 | assert(start === 1);
46 | assert(end === 2);
47 | });
48 | });
49 | context("when `import:2-3, hello-world.js`", function () {
50 | it("should return [2, 3]", function () {
51 | const [start, end] = getSliceRange("import:2-3, hello-world.js");
52 | assert(start === 2);
53 | assert(end === 3);
54 | });
55 | });
56 | context("when `import:2-, hello-world.js`", function () {
57 | it("should return [2, undefined]", function () {
58 | const [start, end] = getSliceRange("import:2-, hello-world.js");
59 | assert(start === 2);
60 | assert(end === undefined);
61 | });
62 | });
63 | context("when `import:-3, hello-world.js`", function () {
64 | it("should return [2, undefined]", function () {
65 | const [start, end] = getSliceRange("import:-3, hello-world.js");
66 | assert(start === undefined);
67 | assert(end === 3);
68 | });
69 | });
70 | });
71 | describe("#sliceCode", function () {
72 | it("should return sliced object for replace", function () {
73 | const [start, end] = getSliceRange("include:4-6, line.js");
74 | const result = sliceCode(lineFixture, start, end);
75 | assert(result.length > 0);
76 | const expected =
77 | 'console.log("this is line 4");\n' +
78 | 'console.log("this is line 5");\n' +
79 | 'console.log("this is line 6");';
80 | assert.equal(result, expected);
81 | });
82 | it("should return sliced `start`- text", function () {
83 | const [start, end] = getSliceRange("include:9-, line.js");
84 | const result = sliceCode(lineFixture, start, end);
85 | assert(result.length > 0);
86 | const expected = 'console.log("this is line 9");\n' + 'console.log("this is line 10");';
87 | assert.equal(result, expected);
88 | });
89 | it("should return sliced -`end` text", function () {
90 | const [start, end] = getSliceRange("include:-2, line.js");
91 | const result = sliceCode(lineFixture, start, end);
92 | assert(result.length > 0);
93 | const expected = 'console.log("this is line 1");\n' + 'console.log("this is line 2");';
94 | assert.equal(result, expected);
95 | });
96 | });
97 | });
98 |
--------------------------------------------------------------------------------
/test/marker-test.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | const assert = require("assert");
4 | import { getMarker, hasMarker, markerSliceCode, removeMarkers } from "../src/marker";
5 |
6 | // -------------------------------------------------------------------------------
7 | // Test C++ Code
8 | const cppcode = `
9 | // test.cpp source code
10 | int main()
11 | {
12 | // Test inner markers.
13 |
14 | //! [marker0]
15 | int a;
16 | //! [marker1]
17 | int b;
18 | //! [marker1]
19 | int c;
20 | //! [marker0]
21 |
22 | // Test different comment style.
23 |
24 | /** [marker2] */
25 | int d;
26 | /** [marker2] */
27 | /// [marker3]
28 | int e;
29 | /// [marker3]
30 | ## [marker4]
31 | int f;
32 | ## [marker4]
33 |
34 | // Test different naming and spacing.
35 |
36 | /// [marker 5]
37 | int g;
38 | /// [marker 5]
39 |
40 | /// [marker6 space]
41 | int h;
42 | /// [marker6 space]
43 | /// [ marker 7 ]
44 | int i;
45 | /// [ marker 7 ]
46 | }
47 | `;
48 | // -------------------------------------------------------------------------------
49 |
50 | const htmlcode = `
51 |
52 |
53 |
54 |
55 | Hello world
56 |
57 | Hola Mundo
58 |
59 |
60 | Hallo Welt
61 |
62 |
63 |
64 |
65 | `;
66 |
67 | // Expected results.
68 | const expectedMarker0 = ` int a;
69 | //! [marker1]
70 | int b;
71 | //! [marker1]
72 | int c;`;
73 | const expectedMarker01 = ` int a;
74 | int b;
75 | int c;`;
76 | const expectedMarker1 = " int b;";
77 | const expectedMarker2 = " int d;";
78 | const expectedMarker3 = " int e;";
79 | const expectedMarker4 = " int f;";
80 | const expectedMarker5 = " int g;";
81 | const expectedMarker6 = " int h;";
82 | const expectedMarker7 = " int i;";
83 |
84 | // Expected HTML results.
85 | const expectedHTMLMarker0 = ` Hello world
86 |
87 | Hola Mundo
88 |
89 |
90 | Hallo Welt
91 | `;
92 |
93 | const expectedHTMLMarker1 = " Hola Mundo";
94 |
95 | const expectedHTMLMarker2 = " Hallo Welt";
96 |
97 | describe("marker", function () {
98 | describe("#hasMarker", function () {
99 | context("when have not marker", function () {
100 | it("should return false", function () {
101 | assert(!hasMarker({ title: undefined, id: undefined, marker: undefined }));
102 | });
103 | });
104 | context("when have marker", function () {
105 | it("should return true", function () {
106 | assert(hasMarker({ title: undefined, id: undefined, marker: "test" }));
107 | });
108 | });
109 | });
110 | describe("marker-label", function () {
111 | describe("#getMarkerName", function () {
112 | it("should return", function () {
113 | const result = getMarker({ title: undefined, id: undefined, marker: "my marker" });
114 | assert.equal(result, "my marker");
115 | });
116 | });
117 | });
118 | describe("marker-slice", function () {
119 | context("#nested", function () {
120 | it("should slice code between [marker0] keeping inner markers", function () {
121 | const markerName = "marker0";
122 | const result = markerSliceCode(cppcode, markerName);
123 | assert.equal(result, expectedMarker0);
124 | });
125 | });
126 | context("#comment-style", function () {
127 | it("should slice code between [marker1] with comment //:", function () {
128 | const markerName = "marker1";
129 | const result = markerSliceCode(cppcode, markerName);
130 | assert.equal(result, expectedMarker1);
131 | });
132 | it("should slice code between [marker2] using comment /**", function () {
133 | const markerName = "marker2";
134 | const result = markerSliceCode(cppcode, markerName);
135 | assert.equal(result, expectedMarker2);
136 | });
137 | it("should slice code between [marker3] using comment ///", function () {
138 | const markerName = "marker3";
139 | const result = markerSliceCode(cppcode, markerName);
140 | assert.equal(result, expectedMarker3);
141 | });
142 | it("should slice code between [marker4] using comment ##", function () {
143 | const markerName = "marker4";
144 | const result = markerSliceCode(cppcode, markerName);
145 | assert.equal(result, expectedMarker4);
146 | });
147 | it("should slice code between [marker0] with HTML comment ", function () {
148 | const markerName = "marker0";
149 | const result = markerSliceCode(htmlcode, markerName);
150 | assert.equal(result, expectedHTMLMarker0);
151 | });
152 | it("should slice code between [marker1] with HTML comment ", function () {
153 | const markerName = "marker1";
154 | const result = markerSliceCode(htmlcode, markerName);
155 | assert.equal(result, expectedHTMLMarker1);
156 | });
157 | it("should slice code between [marker2] with HTML comment ", function () {
158 | const markerName = "marker2";
159 | const result = markerSliceCode(htmlcode, markerName);
160 | assert.equal(result, expectedHTMLMarker2);
161 | });
162 | });
163 | context("#comment-style", function () {
164 | it("should slice code between [marker 5]", function () {
165 | const markerName = "marker 5";
166 | const result = markerSliceCode(cppcode, markerName);
167 | assert.equal(result, expectedMarker5);
168 | });
169 | it("should slice code between [marker6 space]", function () {
170 | const markerName = "marker6 space";
171 | const result = markerSliceCode(cppcode, markerName);
172 | assert.equal(result, expectedMarker6);
173 | });
174 | it("should slice code between [ marker 7 ]", function () {
175 | const markerName = " marker 7 ";
176 | const result = markerSliceCode(cppcode, markerName);
177 | assert.equal(result, expectedMarker7);
178 | });
179 | });
180 | });
181 | describe("remove-marker", function () {
182 | context("#getMarkerName", function () {
183 | it("should slice code between [marker0] and remove markers [marker1]", function () {
184 | const markerName = "marker0";
185 | const result = removeMarkers(markerSliceCode(cppcode, markerName));
186 | assert.equal(result, expectedMarker01);
187 | });
188 | });
189 | });
190 | });
191 |
--------------------------------------------------------------------------------
/src/parser.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | const path = require("path");
4 | const Handlebars = require("handlebars");
5 | import { defaultKeyValueMap, initOptions, checkMapTypes } from "./options.js";
6 | import { unescapeString } from "./unescape-string.js";
7 | import { getLang } from "./language-detection";
8 | import { getMarker, hasMarker, markerSliceCode, removeMarkers } from "./marker";
9 | import { sliceCode, hasSliceRange, getSliceRange } from "./slicer";
10 | import { hasTitle } from "./title";
11 | import { getTemplateContent, readFileFromPath } from "./template";
12 | import { codeBlockBacktick } from "./backtick-maker";
13 |
14 | const markdownLinkFormatRegExp = /\[(?=((?:[^\]]|\\.)*))\1\]\((?=((?:[^)]|\\.)*))\2\)/gm;
15 |
16 | const keyEx = "\\w+";
17 | const kvsepEx = "[:=]";
18 | const spacesEx = "\\s*";
19 | const quoteEx = "[\"']";
20 | const valEx = "(?:[^'\"\\\\]|\\\\.)*";
21 | const argEx = `${quoteEx}${valEx}${quoteEx}|true|false`;
22 | const expressionEx = `(${keyEx})${kvsepEx}${spacesEx}(${argEx})`;
23 | const expressionRegExp = new RegExp(expressionEx, "g");
24 |
25 | const markerRegExp = /^\s*(([-\w\s]*,?)*)$/;
26 |
27 | /**
28 | * A counter to count how many code are imported.
29 | */
30 | var codeCounter = (function () {
31 | var count = 0;
32 | return function () {
33 | return count++;
34 | }; // Return and increment
35 | })();
36 |
37 | /**
38 | * split label to commands
39 | * @param {string} label
40 | * @returns {Array}
41 | */
42 | export function splitLabelToCommands(label = "") {
43 | const result = label.split(/(:|[,\s])/);
44 | if (!result) {
45 | return [];
46 | }
47 | // remove null command
48 | return result
49 | .map((command) => {
50 | return command.trim();
51 | })
52 | .filter((command) => {
53 | return command.length > 0;
54 | });
55 | }
56 |
57 | /**
58 | * Unindent code
59 | * @param {string} s
60 | * @return {string}
61 | */
62 | export function strip(s) {
63 | // inspired from https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/strip.rb
64 | if (s === undefined || s === "") {
65 | return s;
66 | }
67 | const indents = s
68 | .split(/\n/)
69 | .map((s) => s.match(/^[ \t]*(?=\S)/))
70 | .filter((m) => m)
71 | .map((m) => m[0]);
72 | const smallestIndent = indents.sort((a, b) => a.length - b.length)[0];
73 | return s.replace(new RegExp(`^${smallestIndent}`, "gm"), "");
74 | }
75 |
76 | /**
77 | * if contain "include" or "import" command, then return true
78 | * @param {Array} commands
79 | * @returns {boolean}
80 | */
81 | export function containIncludeCommand(commands = []) {
82 | const reg = /^(include|import)$/;
83 | return commands.length > 0 ? reg.test(commands[0].trim()) : false;
84 | }
85 |
86 | /**
87 | * Parse the given value to the given type. Returns the value if valid, otherwise returns undefined.
88 | * @param {string} value
89 | * @param {string} type "string", "boolean"
90 | * @param {string} key
91 | * @return {boolean|string|undefined}
92 | */
93 | export function parseValue(value, type, key) {
94 | if (type === "string") {
95 | const unescapedvalue = unescapeString(value.substring(1, value.length - 1));
96 | if (key === "marker" && !markerRegExp.test(unescapedvalue)) {
97 | console.error(
98 | "include-codeblock: parseVariablesFromLabel: invalid value " + `\`${unescapedvalue}\` in key \`marker\``
99 | );
100 | return undefined;
101 | }
102 | return unescapedvalue;
103 | }
104 |
105 | if (type === "boolean") {
106 | if (["true", '"true"', "'true'"].indexOf(value) >= 0) {
107 | return true;
108 | }
109 |
110 | if (["false", '"false"', "'false'"].indexOf(value) >= 0) {
111 | return false;
112 | }
113 |
114 | console.error(
115 | "include-codeblock: parseVariablesFromLabel: invalid value " +
116 | `\`${value}\` in key \`${key}\`. Expect true or false.`
117 | );
118 | return undefined;
119 | }
120 |
121 | console.error(`include-codeblock: parseVariablesFromLabel: unknown key type \`${type}\` (see options.js)`);
122 | return undefined;
123 | }
124 |
125 | /** Parse the command label and return a new key-value object
126 | * @example
127 | * [import,title:"",label:""](path/to/file.ext)
128 | * @param {object} kvMap
129 | * @param {string} label
130 | * @return {object}
131 | */
132 | export function parseVariablesFromLabel(kvMap, label) {
133 | const kv = Object.assign({}, kvMap);
134 |
135 | let match = "";
136 | while ((match = expressionRegExp.exec(label))) {
137 | let key = match[1];
138 | if (key === "include" || key === "import") {
139 | key = "marker";
140 | }
141 | const value = match[2];
142 |
143 | if (!Object.prototype.hasOwnProperty.call(kv, key)) {
144 | console.error("include-codeblock: parseVariablesFromLabel: unknown key " + `\`${key}\` (see options.js)`);
145 | return;
146 | }
147 |
148 | const parsedValue = parseValue(value, typeof defaultKeyValueMap[key], key);
149 | if (parsedValue !== undefined) {
150 | kv[key] = parsedValue;
151 | }
152 | }
153 |
154 | return Object.freeze(kv);
155 | }
156 |
157 | /**
158 | * generate code from options
159 | * @param {object} kvMap
160 | * @param {string} fileName
161 | * @param {string} originalPath
162 | * @param {string} content
163 | * @param {string} backtick
164 | * @return {string}
165 | */
166 | export function generateEmbedCode(kvMap, { fileName, originalPath, content, backtick }) {
167 | const tContent = getTemplateContent(kvMap);
168 | const kv = Object.assign({}, kvMap);
169 | const count = hasTitle(kv) ? codeCounter() : -1;
170 | checkMapTypes(kvMap, "generatedEmbedCode");
171 | const contextMap = Object.assign({}, kvMap, {
172 | content: content,
173 | count: count,
174 | fileName: fileName,
175 | originalPath: originalPath,
176 | backtick
177 | });
178 | // compile template
179 | const handlebars = Handlebars.compile(tContent);
180 | // compile with data.
181 | return handlebars(contextMap);
182 | }
183 |
184 | /**
185 | * return content from file or url.
186 | * @param {string} filePath it should be absolute path
187 | * @return {string}
188 | */
189 | export function getContent(filePath) {
190 | return readFileFromPath(filePath);
191 | }
192 |
193 | /**
194 | * generate code with options
195 | * @param {object} kvMap
196 | * @param {string} filePath
197 | * @param {string} originalPath
198 | * @param {string} label
199 | * @return {string}
200 | */
201 | export function embedCode(kvMap, { filePath, originalPath, label }) {
202 | const code = getContent(filePath);
203 | const fileName = path.basename(filePath);
204 | const kvmparsed = parseVariablesFromLabel(kvMap, label);
205 | const kvm = getLang(kvmparsed, originalPath);
206 | const unindent = kvm.unindent;
207 |
208 | let content = code;
209 | // Slice content via line numbers.
210 | if (hasSliceRange(label)) {
211 | const [start, end] = getSliceRange(label);
212 | content = sliceCode(code, start, end, unindent);
213 | } else if (hasMarker(kvm)) {
214 | // Slice content via markers.
215 | const marker = getMarker(kvm);
216 | content = removeMarkers(markerSliceCode(code, marker));
217 | }
218 | if (unindent === true) {
219 | content = strip(content);
220 | }
221 |
222 | const backtick = codeBlockBacktick(content);
223 | return generateEmbedCode(kvm, { fileName, originalPath, content, backtick });
224 | }
225 |
226 | /**
227 | * Parse command using options from pluginConfig.
228 | * @param {string} content
229 | * @param {string} baseDir
230 | * @param {{template?: string}} options
231 | * @return {Array}
232 | */
233 | export function parse(content, baseDir, options = {}) {
234 | const results = [];
235 | const kvMap = initOptions(options);
236 | let res = true;
237 | while ((res = markdownLinkFormatRegExp.exec(content))) {
238 | const [all, label, originalPath] = res;
239 | const commands = splitLabelToCommands(label);
240 | if (containIncludeCommand(commands)) {
241 | const absolutePath = path.resolve(baseDir, originalPath);
242 | const replacedContent = embedCode(kvMap, {
243 | filePath: absolutePath,
244 | originalPath: originalPath,
245 | label
246 | });
247 | results.push({
248 | target: all,
249 | replaced: replacedContent
250 | });
251 | }
252 | }
253 | return results;
254 | }
255 |
--------------------------------------------------------------------------------
/test/parser-test.js:
--------------------------------------------------------------------------------
1 | // LICENSE : MIT
2 | "use strict";
3 | import assert from "assert";
4 | import { defaultKeyValueMap } from "../src/options.js";
5 | import { containIncludeCommand, splitLabelToCommands, strip, parseValue, parseVariablesFromLabel } from "../src/parser";
6 |
7 | const kvmap = defaultKeyValueMap;
8 |
9 | describe("parse", function () {
10 | describe("#splitLabelToCommands", function () {
11 | it("should split label to commands", function () {
12 | const commands = splitLabelToCommands("import");
13 | assert.equal(commands.length, 1);
14 | assert.equal(commands[0], "import");
15 | });
16 | it("should not contain space in command", function () {
17 | const commands = splitLabelToCommands("command1 command2, command3 ");
18 | // Should 3 but 4..
19 | assert(commands.length > 3);
20 | assert(commands.indexOf("command1") !== -1);
21 | assert(commands.indexOf("command2") !== -1);
22 | assert(commands.indexOf("command3") !== -1);
23 | });
24 | });
25 | describe("containIncludeLabel", function () {
26 | it("support import", function () {
27 | const commands = splitLabelToCommands("import");
28 | assert(containIncludeCommand(commands));
29 | });
30 | it("support include", function () {
31 | const commands = splitLabelToCommands("include");
32 | assert(containIncludeCommand(commands));
33 | });
34 | it("support command split by space", function () {
35 | const commands = splitLabelToCommands("import title");
36 | assert(containIncludeCommand(commands));
37 | });
38 | it("support command split by ,", function () {
39 | const commands = splitLabelToCommands("import, title");
40 | assert(containIncludeCommand(commands));
41 | });
42 | it("only match first command", function () {
43 | const commands = splitLabelToCommands("Something import title");
44 | assert(!containIncludeCommand(commands));
45 | });
46 | });
47 | describe("parseValue", function () {
48 | it("should unescape string parameter", function () {
49 | const result = parseValue(
50 | '"\\!\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\-\\.\\/' +
51 | "\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~" +
52 | '&<>AA"',
53 | "string",
54 | ""
55 | );
56 | assert.strictEqual(result, "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~&<>AA");
57 | });
58 | it("should backslash unescape commonmark defined characters only", function () {
59 | const result = parseValue('"\\r\\n\\[\\]"', "string", "");
60 | assert.strictEqual(result, "\\r\\n[]"); // \r and \n should not be unescaped.
61 | });
62 | it("should validate markers", function () {
63 | let result = parseValue('" marker0 , marker1 "', "string", "marker");
64 | assert.strictEqual(result, " marker0 , marker1 ");
65 |
66 | result = parseValue('"~invalid~"', "string", "marker");
67 | assert.strictEqual(result, undefined);
68 | });
69 | it("should parse boolean values", function () {
70 | let result = parseValue("true", "boolean", "");
71 | assert.strictEqual(result, true);
72 | result = parseValue('"true"', "boolean", "");
73 | assert.strictEqual(result, true);
74 | result = parseValue("'true'", "boolean", "");
75 | assert.strictEqual(result, true);
76 |
77 | result = parseValue("false", "boolean", "");
78 | assert.strictEqual(result, false);
79 | result = parseValue('"false"', "boolean", "");
80 | assert.strictEqual(result, false);
81 | result = parseValue("'false'", "boolean", "");
82 | assert.strictEqual(result, false);
83 | });
84 | });
85 | describe("parseVariablesFromLabel ", function () {
86 | it("should retrieve edit boolean", function () {
87 | const resmap = parseVariablesFromLabel(kvmap, "include,edit:true");
88 | const results = resmap;
89 | assert.equal(results.edit, true);
90 | assert.equal(results.marker, "");
91 | });
92 | it("should retrieve edit boolean with quotes", function () {
93 | const resmap = parseVariablesFromLabel(kvmap, 'include,edit:"true"');
94 | const results = resmap;
95 | assert.equal(results.edit, true);
96 | assert.equal(results.marker, "");
97 | });
98 | it("should retrieve string title", function () {
99 | const resmap = parseVariablesFromLabel(kvmap, 'include,title:"a test"');
100 | const results = resmap;
101 | assert.equal(results.title, "a test");
102 | assert.equal(results.marker, "");
103 | });
104 | it("should retrieve include marker", function () {
105 | const resmap = parseVariablesFromLabel(kvmap, '[include:"marker0"](/path/to/file.ext)');
106 | const results = resmap;
107 | assert.equal(results.marker, "marker0");
108 | });
109 | it("should retrieve import marker", function () {
110 | const resmap = parseVariablesFromLabel(kvmap, '[import:"marker0"](/path/to/file.ext)');
111 | const results = resmap;
112 | assert.equal(results.marker, "marker0");
113 | });
114 | it("should retrieve include marker with title", function () {
115 | const resmap = parseVariablesFromLabel(kvmap, '[include:"marker0",title:"test"](/path/to/file.ext)');
116 | const results = resmap;
117 | assert.equal(results.marker, "marker0");
118 | assert.equal(results.title, "test");
119 | });
120 | it("should retrieve import multi markers", function () {
121 | const resmap = parseVariablesFromLabel(kvmap, '[import:"marker0,marker1,marker2"](/path/to/file.ext)');
122 | const results = resmap;
123 | assert.equal(results.marker, "marker0,marker1,marker2");
124 | });
125 | it("should retrieve each attribute", function () {
126 | const resmap = parseVariablesFromLabel(
127 | kvmap,
128 | 'include:"marker",title:"a test",id:"code1",class:"myclass",edit=false,check="true",theme:"monokai",template:"ace",unindent:true,fixlang:"false"'
129 | );
130 | const results = resmap;
131 | assert.equal(results.marker, "marker");
132 | assert.equal(results.title, "a test");
133 | assert.equal(results.id, "code1");
134 | assert.equal(results.class, "myclass");
135 | assert.equal(results.edit, false);
136 | assert.equal(results.check, true);
137 | assert.equal(results.theme, "monokai");
138 | assert.equal(results.template, "ace");
139 | assert.equal(results.unindent, true);
140 | assert.equal(results.fixlang, false);
141 | });
142 | it("should retrieve nothing", function () {
143 | const resmap = parseVariablesFromLabel(kvmap, "[import](/path/to/file.ext)");
144 | const results = resmap;
145 | assert.equal(results.marker, "");
146 | });
147 | it("should handle characters for string parameter", function () {
148 | const resmap = parseVariablesFromLabel(kvmap, 'import,title="test+with-special*string"');
149 | const results = resmap;
150 | assert.strictEqual(results.title, "test+with-special*string");
151 | });
152 | it("should unescape string parameter", function () {
153 | const resmap = parseVariablesFromLabel(
154 | kvmap,
155 | 'import,title="\\!\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\-\\.\\/' +
156 | "\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~" +
157 | '&<>AA"'
158 | );
159 | const results = resmap;
160 | assert.strictEqual(results.title, "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~&<>AA");
161 | });
162 | it("should backslash unescape commonmark defined characters only", function () {
163 | const resmap = parseVariablesFromLabel(kvmap, 'import,title="\\r\\n\\[\\]"');
164 | const results = resmap;
165 | assert.strictEqual(results.title, "\\r\\n[]"); // \r and \n should not be unescaped.
166 | });
167 | it("should not parse string argument into another key-value pair", function () {
168 | assert.strictEqual(kvmap.edit, false);
169 | const resmap = parseVariablesFromLabel(kvmap, 'import,title="edit:true"');
170 | const results = resmap;
171 | assert.strictEqual(results.edit, false);
172 | assert.strictEqual(results.title, "edit:true");
173 | });
174 | });
175 | // inspired from https://github.com/rails/rails/blob/master/activesupport/test/core_ext/string_ext_test.rb
176 | describe("strip", function () {
177 | it("strips leading space from empty string", function () {
178 | const stripped = strip("");
179 | assert.equal(stripped, "");
180 | });
181 | it("strips leading space from one-liner", function () {
182 | const stripped = strip(" x");
183 | assert.equal(stripped, "x");
184 | });
185 | it("strips leading space from multi-liner with no margin", function () {
186 | const stripped = strip("foo\n bar\nbaz\n");
187 | assert.equal(stripped, "foo\n bar\nbaz\n");
188 | });
189 | it("strips leading space from multi-liner", function () {
190 | const stripped = strip(" foo\n bar\n baz\n");
191 | assert.equal(stripped, "foo\n bar\nbaz\n");
192 | });
193 | });
194 | });
195 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # gitbook-plugin-include-codeblock [](https://github.com/azu/gitbook-plugin-include-codeblock/actions?query=workflow%3A"test")
2 |
3 | GitBook Plugin for including file.
4 |
5 |
6 | 1. [Installation](#installation)
7 | 2. [Plugin options](#plugin-options)
8 | 3. [Usage](#usage)
9 | 4. [Example](#example)
10 | 5. [CLI](#cli)
11 |
12 |
13 | ## Installation
14 |
15 | book.json
16 |
17 | ```json
18 | {
19 | "plugins": [
20 | "include-codeblock"
21 | ]
22 | }
23 | ```
24 |
25 | and
26 |
27 | ```sh
28 | gitbook install
29 | ```
30 |
31 | ## Plugin options
32 |
33 | Several options can be set in `book.json` to customize the plugin.
34 |
35 | | option | value | Description |
36 | | --- | --- | --- |
37 | | `template` | `{"default","full","ace",...}` or custom path | reindent code if marker or slice is used |
38 | | `unindent` | `{true,false}` default:`false` | reindent code if marker or slice is used |
39 | | `fixlang` | `{true,false}` default:`false` | fix some errors with code lang (e.g C++, ...) |
40 | | `lang` | `{"c_cpp","javascript", ...}` | lang color syntax (not set => auto deduce, see [lang section](#hardcoded-class)). |
41 | | `edit` | `{true,false}` | [allow edit code](https://github.com/ymcatar/gitbook-plugin-ace/blob/master/README.md) (**ace template required**) |
42 | | `check` | `{true,false}` | [syntax validation](https://github.com/ymcatar/gitbook-plugin-ace/blob/master/README.md) (**ace template required**) |
43 | | `theme` | `{"monokai","coffee",...}` | [check syntax](https://github.com/ymcatar/gitbook-plugin-ace/blob/master/README.md) (**ace template required**) |
44 |
45 | Just add the desired optin under `pluginConfig` in the `book.json` file
46 |
47 | ```js
48 | {
49 | "gitbook": "3.x.x",
50 | "pluginsConfig": {
51 | "include-codeblock": {
52 | "template": "ace",
53 | "unindent": true,
54 | "theme": "monokai"
55 | }
56 | }
57 | }
58 | ```
59 |
60 | ### Templates
61 |
62 | Templates let customize the rendered code. Several default templates are available
63 |
64 | | template | description |
65 | | --- | --- |
66 | | `"default"` | default template, standard markdown code style |
67 | | `"full"` | enable title, labeling, id, ... |
68 | | `"ace"` | enable ace code rendering (**ace plugin required**) |
69 | | `"acefull"` | enable ace code rendering with title, label, id, ... (**ace plugin required**) |
70 |
71 | - :information_source: For ace template, see [Ace section](#ace-plugin)
72 | - :information_source: For more template, consult the list in [template/](templates/).
73 |
74 | Custom templates can be created to render the code by specifying a custom path
75 | to the template file.
76 | ```js
77 | {
78 | "gitbook": "3.x.x",
79 | "pluginsConfig": {
80 | "include-codeblock": {
81 | "template": __dirname + "/" + "path/to/custom.hbs",
82 | }
83 | }
84 | }
85 | ```
86 | See [templates/](templates/) and [examples/](examples/) for details.
87 |
88 | Any contribution is welcome. Propose your new templates via pull-requests.
89 |
90 | ### Ace plugin
91 |
92 | It is possible to use the gitbook ace plugin to have code numbering or custom themes
93 | (See [gitbook-ace-plugin](https://github.com/ymcatar/gitbook-plugin-ace) for more details).
94 | To use ace within include-codeblock, you have to **load the ace plugin after include-codeblock!**
95 | and choose an ace temple (see [templates/](templates/))
96 |
97 | ```js
98 | {
99 | "gitbook": "3.x.x",
100 | "plugins" : [
101 | "include-codeblock",
102 | "ace"
103 | ]
104 | "pluginsConfig": {
105 | "include-codeblock": {
106 | "template": "ace", // or acefull
107 | }
108 | }
109 | }
110 | ```
111 |
112 | ## Usage
113 |
114 |
115 | #### General usage:
116 |
117 | ```
118 | [import:"tag",option0:"value0", ...](path/to/file)
119 | ```
120 |
121 | where `<...>` are required tags, `<<...>>` are optional tags.
122 |
123 | | tag | description |
124 | | --- | --- |
125 | | `import` | use `import` or `include` tag. |
126 | | `tag` | optional tag to include code snippet (see [snippet](#snippet-code). |
127 | | `optionX` | optional `key:value` or `key=value` option (See [Command options](#command-options)). |
128 |
129 | See [examples](#examples) for more details.
130 |
131 | #### Examples
132 |
133 | **fixtures/test.js**
134 | ```js
135 | console.log("test");
136 | ```
137 |
138 | Write following the link with `include` or `import` label.
139 |
140 | ```markdown
141 | [include](fixtures/test.js)
142 | ```
143 |
144 | or
145 |
146 | ```markdown
147 | [import](fixtures/test.js)
148 | ```
149 | Result
150 |
151 | ``` js
152 | console.log("test");
153 | ```
154 |
155 | :information_source: Do not inline!
156 | ``` js
157 | // won't work
158 | Example of code [import](fixtures/test.js)
159 | ```
160 |
161 | You could import the same code directly from the repository with nice color template
162 | ```markdown
163 | [import, template:"acefull", title:"example of code", theme:"monokai"](https://raw.githubusercontent.com/azu/gitbook-plugin-include-codeblock/master/test/fixtures/test.js)
164 | ```
165 |
166 |
167 | ### Command options
168 |
169 | Option can be passed locally and may depend on the template your are using.
170 |
171 | | option | value | Description |
172 | | --- | --- | --- |
173 | | `unindent` | `{"true","false"}` | reindent code if marker or slice is used |
174 | | `title`| `""` | Title for the code **full template required**|
175 | | `name` | `""` | name of the included file **full template required** |
176 | | `class` | `""` | html class for the title **full template required** |
177 | | `id` | `""` | html class for custom style **full template required** |
178 | | `label` | `""` | reference label (latex like) **full template required** |
179 | | `edit` | `{"true","false"}` | allow edit code (**ace template required**) |
180 | | `check` | `{"true","false"}` | check syntax (**ace template required**) |
181 | | `template` | `{default,full,ace,...}` or custom path | reindent code if marker or slice is used |
182 | | `lang` | `{"c_cpp","javascript", ...}` | lang color syntax (not set => auto deduce, see [lang section](#hardcoded-class)). |
183 | | `fixlang` | `{true,false}` default:`false` | fix some errors with code lang (e.g C++, ...) |
184 | | `theme` | `{"monokai","coffee",...}` | check syntax (**ace template required**) |
185 |
186 | For more details see sections below.
187 |
188 |
189 | ### Hardcoded class
190 |
191 | When you import a TypeScript file `.ts`:
192 | The parser correctly finds `.ts` in the
193 | [language-map](https://github.com/blakeembrey/language-map "language-map")
194 | extensions for both TypeScript and XML, then automatically chooses `XML`.
195 |
196 | If you want to specify language type, put `lang:""` to label.
197 |
198 | ```markdown
199 | [import, lang:"typescript"](hello-world.ts)
200 | ```
201 |
202 | - :information_source: choose `` of `lang-` from language-map's `aceMode` value.
203 | - [blakeembrey/language-map: JSON version of the programming language map used in Linguist](https://github.com/blakeembrey/language-map "blakeembrey/language-map: JSON version of the programming language map used in Linguist")
204 |
205 | e.g.) typescript's aceMode value is `typescript`.
206 |
207 | - https://github.com/blakeembrey/language-map/blob/b72edb8c2cb1b05d098782aa85dd2f573ed96ba3/languages.json#L4140
208 |
209 |
210 | ### Sliced Code
211 |
212 | If you want to slice imported code and show.
213 |
214 | ```markdown
215 | [import:-](path/to/file)
216 | ```
217 |
218 | - :information_source: lineNumber start with 1.
219 |
220 | All Patterns:
221 |
222 | ```
223 | All: [import, hello-world.js](../src/hello-world.js)
224 | 1-2: [import:1-2, hello-world.js](../src/hello-world.js)
225 | 2-3: [import:2-3, hello-world.js](../src/hello-world.js)
226 | 2>=: [import:2-, hello-world.js](../src/hello-world.js)
227 | <=3: [import:-3, hello-world.js](../src/hello-world.js)
228 | ```
229 |
230 | ### Snippet code
231 |
232 | You can also import snippet code delimited by a tag. It follows the
233 | [doxygen snippet standard](https://www.stack.nl/~dimitri/doxygen/manual/commands.html#cmdsnippet)
234 | Snippet is doxygen compatible.
235 | (See also [how to document the code](https://www.stack.nl/~dimitri/doxygen/manual/docblocks.html))
236 |
237 | ```markdown
238 | [import:''](path/to/file)
239 | ```
240 |
241 | #### Remarks
242 | - :information_source: **marker name** begins with an alphabet character
243 | - :information_source: tags follows the doxygen standard: **language comment for documenting code** + **tag between bracket**
244 | - :information_source: Several markers separated by a comma will concatene snippets into a unique snippet. Spaces are taken into account.
245 |
246 | For example, considering the following C++ source code
247 |
248 | ```cpp
249 | // test.cpp source code
250 | int main()
251 | {
252 | /// [marker0]
253 | int a;
254 | //! [marker1]
255 | int b;
256 | //! [marker1]
257 | int c;
258 | /// [marker0]
259 |
260 | // [notmarked]
261 | int d;
262 | // [notmarked]
263 |
264 | //! [marker2]
265 | int e;
266 | //! [marker2]
267 | }
268 |
269 | ```
270 | In GitBook, the following commands
271 |
272 | ```markdown
273 | [import:'marker1'](path/to/test.cpp)
274 | ```
275 |
276 | will result to
277 |
278 | ```cpp
279 | int b;
280 | ```
281 |
282 | The command `[import:'marker0'](path/to/test.cpp)` will result to
283 |
284 | ```cpp
285 | int a;
286 | int b;
287 | int c;
288 | ```
289 |
290 | The command `[import:'marker1,marker2'](path/to/test.cpp)` will result to
291 | ```cpp
292 | int b;
293 | int e;
294 | ```
295 |
296 | But the command `[import:'notmarked'](path/to/test.cpp)` will fail as it
297 | does not respect the doxygen documenting standard.
298 | (See [documenting the code](https://www.stack.nl/~dimitri/doxygen/manual/docblocks.html))
299 |
300 | ### Unindented code
301 |
302 | Consider the following source code:
303 |
304 | ```java
305 | class Hello {
306 | /// [some-marker]
307 | void world() {
308 | // nice
309 | }
310 | /// [some-marker]
311 | }
312 | ```
313 |
314 | And the following command:
315 |
316 | ```
317 | [import:"some-marker",unindent:"true"](path/to/test.java)
318 | ```
319 |
320 | This will result in unindented code:
321 |
322 | ```java
323 | void world() {
324 | // nice
325 | }
326 | ```
327 |
328 | Unindent behaviour can also be specified globally in the plugin configuration.
329 |
330 | See also
331 |
332 | - [Allow to put marker in xml · Issue #63 · azu/gitbook-plugin-include-codeblock](https://github.com/azu/gitbook-plugin-include-codeblock/issues/63)
333 |
334 | ## Example
335 |
336 | Please See [examples/](examples/).
337 |
338 | [](example/)
339 |
340 | ## CLI
341 |
342 | This gitbook plugin include Command line tools.
343 | It just convert markdown to markdown.
344 |
345 | $ npm install -g gitbook-plugin-include-codeblock
346 | # Convert Markdown to Markdown
347 | $ include-codeblock ./README.md --output RENDER_README.md
348 |
349 | ## FAQ
350 |
351 | ### How to migrate Version 1.x to 2.x
352 |
353 | Version 2.0 contain a breaking change.
354 |
355 | - [Breaking Change: change default template by azu · Pull Request #31 · azu/gitbook-plugin-include-codeblock](https://github.com/azu/gitbook-plugin-include-codeblock/pull/31 "Breaking Change: change default template by azu · Pull Request #31 · azu/gitbook-plugin-include-codeblock")
356 |
357 | It change default template for displaying embed code.
358 |
359 | Version 1.x template.
360 |
361 | {{#if title}}
362 | {{#if id}}
363 | {% if file.type=="asciidoc" %}
364 | > [[{{id}}]]link:{{originalPath}}[{{title}}]
365 | {% else %}
366 | > {{title}}
367 | {% endif %}
368 | {{else}}
369 | {% if file.type=="asciidoc" %}
370 | > [[{{title}}]]link:{{originalPath}}[{{title}}]
371 | {% else %}
372 | > {{title}}
373 | {% endif %}
374 | {{/if}}
375 | {{else}}
376 | {% if file.type=="asciidoc" %}
377 | > [[{{fileName}}]]link:{{originalPath}}[{{fileName}}]
378 | {% else %}
379 | > {{fileName}}
380 | {% endif %}
381 | {{/if}}
382 |
383 | ``` {{lang}}
384 | {{{content}}}
385 | ```
386 |
387 | Version 2.x template.
388 |
389 | ``` {{lang}}
390 | {{{content}}}
391 | ```
392 |
393 | If you want to use Version 1.x template, please set `template` option to `book.json` or `book.js`
394 |
395 | ```js
396 | const fs = require("fs");
397 | module.exports = {
398 | "gitbook": "3.x.x",
399 | "title": "gitbook-plugin-include-codeblock example",
400 | "plugins": [
401 | "include-codeblock"
402 | ],
403 | "pluginsConfig": {
404 | "include-codeblock": {
405 | // Before, create user-template.hbs
406 | "template": fs.readFileSync(__dirname + "/user-template.hbs", "utf-8")
407 | }
408 | }
409 | };
410 | ```
411 |
412 | If you want to know more details, please see [templates/](templates/).
413 |
414 | ## Tests
415 |
416 | npm test
417 |
418 | ## Contributing
419 |
420 | 1. Fork it!
421 | 2. Create your feature branch: `git checkout -b my-new-feature`
422 | 3. Commit your changes: `git commit -am 'Add some feature'`
423 | 4. Push to the branch: `git push origin my-new-feature`
424 | 5. Submit a pull request :D
425 |
426 | ## License
427 |
428 | MIT
429 |
--------------------------------------------------------------------------------