remark-custom-container
Advanced tools
Comparing version 1.1.2 to 1.2.0
@@ -1,3 +0,4 @@ | ||
import { Plugin } from "unified"; | ||
export declare const REGEX_CUSTOM_CONTAINER: RegExp; | ||
import type { Plugin } from "unified"; | ||
export declare const REGEX_BEGIN: RegExp; | ||
export declare const REGEX_END: RegExp; | ||
interface CustomContainerOptions { | ||
@@ -4,0 +5,0 @@ /** |
import { visit } from "unist-util-visit"; | ||
export const REGEX_CUSTOM_CONTAINER = /^\s*:::\s*(\w+)\s*(.*?)[\n\r]([\s\S]+?)\s*:::\s*?/; | ||
export const REGEX_BEGIN = /^\s*:::\s*(\w+)\s*(.*)?/; | ||
export const REGEX_END = /^\s*:::$/; | ||
const DEFAULT_SETTINGS = { | ||
@@ -10,45 +11,81 @@ className: "remark-container", | ||
}; | ||
const isParagraph = (node) => { | ||
return "paragraph" === node.type; | ||
}; | ||
export const plugin = (options) => { | ||
const settings = Object.assign({}, DEFAULT_SETTINGS, options); | ||
// Constructs `Parent` node of custom directive which contains given children. | ||
const constructContainer = (children, className) => { | ||
return { | ||
type: "container", | ||
children, | ||
data: { | ||
hName: settings.containerTag, | ||
hProperties: { | ||
className: [settings.className, className.toLowerCase()], | ||
}, | ||
}, | ||
}; | ||
}; | ||
const constructTitle = (title) => { | ||
return { | ||
type: "paragraph", | ||
children: [{ type: "text", value: title }], | ||
data: { | ||
hName: "div", | ||
hProperties: { className: [`${settings.className}__title`] }, | ||
}, | ||
}; | ||
}; | ||
const transformer = (tree) => { | ||
visit(tree, (node, index, parent) => { | ||
if (index == null) | ||
return; | ||
visit(tree, (_node, _index, parent) => { | ||
if (!parent) | ||
return; | ||
if (!isLiteralNode(node)) | ||
return; | ||
if (typeof node.value !== "string" || node.type !== "text") | ||
return; | ||
const match = node.value.match(REGEX_CUSTOM_CONTAINER); | ||
if (!match) | ||
return; | ||
// NOTE title may be null | ||
const [_input, type, title, content] = match; | ||
const children = []; | ||
if (title.length > 0) { | ||
children.push({ | ||
type: "container", | ||
children: [{ type: "text", value: title }], | ||
data: { | ||
hName: "div", | ||
hProperties: { className: [`${settings.className}__title`] }, | ||
}, | ||
}); | ||
const len = parent.children.length; | ||
// we walk through each children in `parent` to look for custom directive. | ||
let currentIndex = -1; | ||
while (currentIndex < len - 1) { | ||
currentIndex += 1; | ||
// check if currentIndex of children contains begin node of custom directive | ||
const currentNode = parent.children[currentIndex]; | ||
children.push(currentNode); | ||
if (!isParagraph(currentNode)) | ||
continue; | ||
// XXX: Consider checking other children in currentNode | ||
const currentElem = currentNode.children[0]; | ||
if (!isLiteralNode(currentElem)) | ||
continue; | ||
const match = currentElem.value.match(REGEX_BEGIN); | ||
if (!match) | ||
continue; | ||
// Here we're inside of the custom directive. let's find nearest closing directive. | ||
// remove last element, which is custom directive marker. | ||
children.pop(); | ||
const beginIndex = currentIndex; | ||
let innerIndex = currentIndex - 1; | ||
while (innerIndex < len - 1) { | ||
innerIndex += 1; | ||
const currentNode = parent.children[innerIndex]; | ||
if (!isParagraph(currentNode)) | ||
continue; | ||
const currentElem = currentNode.children[0]; | ||
if (!isLiteralNode(currentElem) || | ||
!currentElem.value.match(REGEX_END)) | ||
continue; | ||
// here we found the closing directive. | ||
const [_input, type, title] = match; | ||
// remove surrounding `:::` markers and treat rest of them as children of the container | ||
const containerChildren = parent.children.slice(beginIndex + 1, innerIndex); | ||
if (title?.length > 0) { | ||
containerChildren.splice(0, 0, constructTitle(title)); | ||
} | ||
const container = constructContainer(containerChildren, type.toLowerCase()); | ||
children.push(container); | ||
currentIndex = innerIndex - 1; | ||
break; | ||
} | ||
currentIndex += 1; | ||
} | ||
children.push({ | ||
type: "text", | ||
value: content, | ||
}); | ||
const container = { | ||
type: "container", | ||
children, | ||
data: { | ||
hName: settings.containerTag, | ||
hProperties: { | ||
className: [settings.className, type.toLowerCase()], | ||
}, | ||
}, | ||
}; | ||
parent.children[index] = container; | ||
parent.children = children; | ||
}); | ||
@@ -55,0 +92,0 @@ }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.plugin = exports.REGEX_CUSTOM_CONTAINER = void 0; | ||
exports.plugin = exports.REGEX_END = exports.REGEX_BEGIN = void 0; | ||
const unist_util_visit_1 = require("unist-util-visit"); | ||
exports.REGEX_CUSTOM_CONTAINER = /^\s*:::\s*(\w+)\s*(.*?)[\n\r]([\s\S]+?)\s*:::\s*?/; | ||
exports.REGEX_BEGIN = /^\s*:::\s*(\w+)\s*(.*)?/; | ||
exports.REGEX_END = /^\s*:::$/; | ||
const DEFAULT_SETTINGS = { | ||
@@ -13,45 +14,81 @@ className: "remark-container", | ||
}; | ||
const isParagraph = (node) => { | ||
return "paragraph" === node.type; | ||
}; | ||
const plugin = (options) => { | ||
const settings = Object.assign({}, DEFAULT_SETTINGS, options); | ||
// Constructs `Parent` node of custom directive which contains given children. | ||
const constructContainer = (children, className) => { | ||
return { | ||
type: "container", | ||
children, | ||
data: { | ||
hName: settings.containerTag, | ||
hProperties: { | ||
className: [settings.className, className.toLowerCase()], | ||
}, | ||
}, | ||
}; | ||
}; | ||
const constructTitle = (title) => { | ||
return { | ||
type: "paragraph", | ||
children: [{ type: "text", value: title }], | ||
data: { | ||
hName: "div", | ||
hProperties: { className: [`${settings.className}__title`] }, | ||
}, | ||
}; | ||
}; | ||
const transformer = (tree) => { | ||
(0, unist_util_visit_1.visit)(tree, (node, index, parent) => { | ||
if (index == null) | ||
return; | ||
(0, unist_util_visit_1.visit)(tree, (_node, _index, parent) => { | ||
if (!parent) | ||
return; | ||
if (!isLiteralNode(node)) | ||
return; | ||
if (typeof node.value !== "string" || node.type !== "text") | ||
return; | ||
const match = node.value.match(exports.REGEX_CUSTOM_CONTAINER); | ||
if (!match) | ||
return; | ||
// NOTE title may be null | ||
const [_input, type, title, content] = match; | ||
const children = []; | ||
if (title.length > 0) { | ||
children.push({ | ||
type: "container", | ||
children: [{ type: "text", value: title }], | ||
data: { | ||
hName: "div", | ||
hProperties: { className: [`${settings.className}__title`] }, | ||
}, | ||
}); | ||
const len = parent.children.length; | ||
// we walk through each children in `parent` to look for custom directive. | ||
let currentIndex = -1; | ||
while (currentIndex < len - 1) { | ||
currentIndex += 1; | ||
// check if currentIndex of children contains begin node of custom directive | ||
const currentNode = parent.children[currentIndex]; | ||
children.push(currentNode); | ||
if (!isParagraph(currentNode)) | ||
continue; | ||
// XXX: Consider checking other children in currentNode | ||
const currentElem = currentNode.children[0]; | ||
if (!isLiteralNode(currentElem)) | ||
continue; | ||
const match = currentElem.value.match(exports.REGEX_BEGIN); | ||
if (!match) | ||
continue; | ||
// Here we're inside of the custom directive. let's find nearest closing directive. | ||
// remove last element, which is custom directive marker. | ||
children.pop(); | ||
const beginIndex = currentIndex; | ||
let innerIndex = currentIndex - 1; | ||
while (innerIndex < len - 1) { | ||
innerIndex += 1; | ||
const currentNode = parent.children[innerIndex]; | ||
if (!isParagraph(currentNode)) | ||
continue; | ||
const currentElem = currentNode.children[0]; | ||
if (!isLiteralNode(currentElem) || | ||
!currentElem.value.match(exports.REGEX_END)) | ||
continue; | ||
// here we found the closing directive. | ||
const [_input, type, title] = match; | ||
// remove surrounding `:::` markers and treat rest of them as children of the container | ||
const containerChildren = parent.children.slice(beginIndex + 1, innerIndex); | ||
if (title?.length > 0) { | ||
containerChildren.splice(0, 0, constructTitle(title)); | ||
} | ||
const container = constructContainer(containerChildren, type.toLowerCase()); | ||
children.push(container); | ||
currentIndex = innerIndex - 1; | ||
break; | ||
} | ||
currentIndex += 1; | ||
} | ||
children.push({ | ||
type: "text", | ||
value: content, | ||
}); | ||
const container = { | ||
type: "container", | ||
children, | ||
data: { | ||
hName: settings.containerTag, | ||
hProperties: { | ||
className: [settings.className, type.toLowerCase()], | ||
}, | ||
}, | ||
}; | ||
parent.children[index] = container; | ||
parent.children = children; | ||
}); | ||
@@ -58,0 +95,0 @@ }; |
{ | ||
"name": "remark-custom-container", | ||
"version": "1.1.2", | ||
"version": "1.2.0", | ||
"description": "remark parser plugin for custom directive in markdown", | ||
@@ -35,15 +35,14 @@ "author": "koka831", | ||
"devDependencies": { | ||
"@jest/types": "^27.0.6", | ||
"@types/jest": "^27.0.3", | ||
"@types/node": "^16.4.2", | ||
"@jest/types": "^29.3.1", | ||
"@types/jest": "^29.2.3", | ||
"@types/node": "^18.11.9", | ||
"@types/unist": "^2.0.3", | ||
"@typescript-eslint/eslint-plugin": "^4.28.4", | ||
"@typescript-eslint/parser": "^4.28.4", | ||
"eslint": "^8.1.0", | ||
"eslint-config-prettier": "^8.3.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"jest": "^27.0.6", | ||
"@typescript-eslint/eslint-plugin": "^5.44.0", | ||
"@typescript-eslint/parser": "^5.44.0", | ||
"eslint": "^8.28.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"jest": "^29.3.1", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^2.3.2", | ||
"rehype-stringify": "^8.0.0", | ||
"prettier": "^2.7.1", | ||
"rehype-stringify": "^9.0.3", | ||
"remark": "^14.0.0", | ||
@@ -53,8 +52,8 @@ "remark-gfm": "^3.0.0", | ||
"rimraf": "^3.0.2", | ||
"ts-jest": "^27.0.4", | ||
"ts-node": "^10.1.0", | ||
"typescript": "^4.3.5", | ||
"ts-jest": "^29.0.3", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.9.3", | ||
"unified": "^10.1.0", | ||
"vfile": "^5.1.0" | ||
"vfile": "^5.3.6" | ||
} | ||
} |
# remark-custom-container | ||
[remarkjs][remarkjs] parser plugin for custom directive (compatible with new parser in remark. see [#536][536]) | ||
NOTE: This plugin is highly inspired by [vuepress-plugin-container][vuepress-plugin-container]. | ||
> **Note** | ||
> This plugin is highly inspired by [vuepress-plugin-container][vuepress-plugin-container]. | ||
This package is ESM only: Node 12+ is needed to use it and it must be `import`ed instead of `require`d. | ||
@@ -16,3 +18,5 @@ | ||
::: className Custom Title | ||
Container Body | ||
::: | ||
@@ -62,8 +66,4 @@ ``` | ||
### Milestone | ||
- [ ] custom container in container | ||
[remarkjs]: https://github.com/remarkjs/remark | ||
[536]: https://github.com/remarkjs/remark/pull/536 | ||
[vuepress-plugin-container]: https://github.com/vuepress/vuepress-community/tree/main/packages/vuepress-plugin-container |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
12713
21
7
207
1