markdownlint-rule-helpers
Advanced tools
Comparing version 0.26.0 to 0.27.0
434
helpers.js
@@ -5,3 +5,3 @@ // @ts-check | ||
const micromark = require("./micromark.cjs"); | ||
const micromark = require("./micromark-helpers.cjs"); | ||
@@ -13,5 +13,8 @@ const { newLineRe, nextLinesRe } = require("./shared.js"); | ||
/** @typedef {import("../lib/markdownlint.js").RuleOnError} RuleOnError */ | ||
/** @typedef {import("../lib/markdownlint.js").RuleOnErrorFixInfo} RuleOnErrorFixInfo */ | ||
// Regular expression for matching common front matter (YAML and TOML) | ||
module.exports.frontMatterRe = | ||
/((^---\s*$[\s\S]+?^---\s*)|(^\+\+\+\s*$[\s\S]+?^(\+\+\+|\.\.\.)\s*)|(^\{\s*$[\s\S]+?^\}\s*))(\r\n|\r|\n|$)/m; | ||
/((^---[^\S\r\n\u2028\u2029]*$[\s\S]+?^---\s*)|(^\+\+\+[^\S\r\n\u2028\u2029]*$[\s\S]+?^(\+\+\+|\.\.\.)\s*)|(^\{[^\S\r\n\u2028\u2029]*$[\s\S]+?^\}\s*))(\r\n|\r|\n|$)/m; | ||
@@ -23,10 +26,2 @@ // Regular expression for matching the start of inline disable/enable comments | ||
// Regular expression for blockquote prefixes | ||
const blockquotePrefixRe = /^[>\s]*/; | ||
module.exports.blockquotePrefixRe = blockquotePrefixRe; | ||
// Regular expression for link reference definitions | ||
const linkReferenceDefinitionRe = /^ {0,3}\[([^\]]*[^\\])\]:/; | ||
module.exports.linkReferenceDefinitionRe = linkReferenceDefinitionRe; | ||
// Regular expression for identifying an HTML entity at the end of a line | ||
@@ -230,95 +225,2 @@ module.exports.endOfLineHtmlEntityRe = | ||
/** | ||
* Return the string representation of a fence markup character. | ||
* | ||
* @param {string} markup Fence string. | ||
* @returns {string} String representation. | ||
*/ | ||
module.exports.fencedCodeBlockStyleFor = | ||
function fencedCodeBlockStyleFor(markup) { | ||
switch (markup[0]) { | ||
case "~": | ||
return "tilde"; | ||
default: | ||
return "backtick"; | ||
} | ||
}; | ||
/** | ||
* Return the string representation of a emphasis or strong markup character. | ||
* | ||
* @param {string} markup Emphasis or strong string. | ||
* @returns {"asterisk" | "underscore"} String representation. | ||
*/ | ||
module.exports.emphasisOrStrongStyleFor = | ||
function emphasisOrStrongStyleFor(markup) { | ||
switch (markup[0]) { | ||
case "*": | ||
return "asterisk"; | ||
default: | ||
return "underscore"; | ||
} | ||
}; | ||
/** | ||
* @callback InlineCodeSpanCallback | ||
* @param {string} code Code content. | ||
* @param {number} lineIndex Line index (0-based). | ||
* @param {number} columnIndex Column index (0-based). | ||
* @param {number} ticks Count of backticks. | ||
* @returns {void} | ||
*/ | ||
/** | ||
* Calls the provided function for each inline code span's content. | ||
* | ||
* @param {string} input Markdown content. | ||
* @param {InlineCodeSpanCallback} handler Callback function taking (code, | ||
* lineIndex, columnIndex, ticks). | ||
* @returns {void} | ||
*/ | ||
function forEachInlineCodeSpan(input, handler) { | ||
const backtickRe = /`+/g; | ||
let match = null; | ||
const backticksLengthAndIndex = []; | ||
while ((match = backtickRe.exec(input)) !== null) { | ||
backticksLengthAndIndex.push([ match[0].length, match.index ]); | ||
} | ||
const newLinesIndex = []; | ||
while ((match = newLineRe.exec(input)) !== null) { | ||
newLinesIndex.push(match.index); | ||
} | ||
let lineIndex = 0; | ||
let lineStartIndex = 0; | ||
let k = 0; | ||
for (let i = 0; i < backticksLengthAndIndex.length - 1; i++) { | ||
const [ startLength, startIndex ] = backticksLengthAndIndex[i]; | ||
if ((startIndex === 0) || (input[startIndex - 1] !== "\\")) { | ||
for (let j = i + 1; j < backticksLengthAndIndex.length; j++) { | ||
const [ endLength, endIndex ] = backticksLengthAndIndex[j]; | ||
if (startLength === endLength) { | ||
for (; k < newLinesIndex.length; k++) { | ||
const newLineIndex = newLinesIndex[k]; | ||
if (startIndex < newLineIndex) { | ||
break; | ||
} | ||
lineIndex++; | ||
lineStartIndex = newLineIndex + 1; | ||
} | ||
const columnIndex = startIndex - lineStartIndex + startLength; | ||
handler( | ||
input.slice(startIndex + startLength, endIndex), | ||
lineIndex, | ||
columnIndex, | ||
startLength | ||
); | ||
i = j; | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
module.exports.forEachInlineCodeSpan = forEachInlineCodeSpan; | ||
/** | ||
* Adds ellipsis to the left/right/middle of the specified text. | ||
@@ -348,3 +250,3 @@ * | ||
* | ||
* @param {Object} onError RuleOnError instance. | ||
* @param {RuleOnError} onError RuleOnError instance. | ||
* @param {number} lineNumber Line number. | ||
@@ -354,3 +256,3 @@ * @param {string} [detail] Error details. | ||
* @param {number[]} [range] Column and length of error. | ||
* @param {Object} [fixInfo] RuleOnErrorFixInfo instance. | ||
* @param {RuleOnErrorFixInfo} [fixInfo] RuleOnErrorFixInfo instance. | ||
* @returns {void} | ||
@@ -372,3 +274,3 @@ */ | ||
* | ||
* @param {Object} onError RuleOnError instance. | ||
* @param {RuleOnError} onError RuleOnError instance. | ||
* @param {number} lineNumber Line number. | ||
@@ -380,3 +282,3 @@ * @param {Object} expected Expected value. | ||
* @param {number[]} [range] Column and length of error. | ||
* @param {Object} [fixInfo] RuleOnErrorFixInfo instance. | ||
* @param {RuleOnErrorFixInfo} [fixInfo] RuleOnErrorFixInfo instance. | ||
* @returns {void} | ||
@@ -402,3 +304,3 @@ */ | ||
* | ||
* @param {Object} onError RuleOnError instance. | ||
* @param {RuleOnError} onError RuleOnError instance. | ||
* @param {number} lineNumber Line number. | ||
@@ -409,3 +311,3 @@ * @param {string} context Error context. | ||
* @param {number[]} [range] Column and length of error. | ||
* @param {Object} [fixInfo] RuleOnErrorFixInfo instance. | ||
* @param {RuleOnErrorFixInfo} [fixInfo] RuleOnErrorFixInfo instance. | ||
* @returns {void} | ||
@@ -421,47 +323,39 @@ */ | ||
/** | ||
* Adds an error object with context for a construct missing a blank line. | ||
* Defines a range within a file (start line/column to end line/column, subset of MicromarkToken). | ||
* | ||
* @param {Object} onError RuleOnError instance. | ||
* @param {string[]} lines Lines of Markdown content. | ||
* @param {number} lineIndex Line index of line. | ||
* @param {number} [lineNumber] Line number for override. | ||
* @returns {void} | ||
* @typedef {Object} FileRange | ||
* @property {number} startLine Start line (1-based). | ||
* @property {number} startColumn Start column (1-based). | ||
* @property {number} endLine End line (1-based). | ||
* @property {number} endColumn End column (1-based). | ||
*/ | ||
function addErrorContextForLine(onError, lines, lineIndex, lineNumber) { | ||
const line = lines[lineIndex]; | ||
// @ts-ignore | ||
const quotePrefix = line.match(blockquotePrefixRe)[0].trimEnd(); | ||
addErrorContext( | ||
onError, | ||
lineIndex + 1, | ||
line.trim(), | ||
undefined, | ||
undefined, | ||
undefined, | ||
{ | ||
lineNumber, | ||
"insertText": `${quotePrefix}\n` | ||
} | ||
); | ||
} | ||
module.exports.addErrorContextForLine = addErrorContextForLine; | ||
/** | ||
* Determines whether the specified range is within another range. | ||
* Returns whether line/column A is less than or equal to line/column B. | ||
* | ||
* @param {number[][]} ranges Array of ranges (line, index, length). | ||
* @param {number} lineIndex Line index to check. | ||
* @param {number} index Index to check. | ||
* @param {number} length Length to check. | ||
* @returns {boolean} True iff the specified range is within. | ||
* @param {number} lineA Line A. | ||
* @param {number} columnA Column A. | ||
* @param {number} lineB Line B. | ||
* @param {number} columnB Column B. | ||
* @returns {boolean} True iff A is less than or equal to B. | ||
*/ | ||
const withinAnyRange = (ranges, lineIndex, index, length) => ( | ||
!ranges.every((span) => ( | ||
(lineIndex !== span[0]) || | ||
(index < span[1]) || | ||
(index + length > span[1] + span[2]) | ||
)) | ||
const positionLessThanOrEqual = (lineA, columnA, lineB, columnB) => ( | ||
(lineA < lineB) || | ||
((lineA === lineB) && (columnA <= columnB)) | ||
); | ||
module.exports.withinAnyRange = withinAnyRange; | ||
/** | ||
* Returns whether two ranges (or MicromarkTokens) overlap anywhere. | ||
* | ||
* @param {FileRange|import("../lib/markdownlint.js").MicromarkToken} rangeA Range A. | ||
* @param {FileRange|import("../lib/markdownlint.js").MicromarkToken} rangeB Range B. | ||
* @returns {boolean} True iff the two ranges overlap. | ||
*/ | ||
module.exports.hasOverlap = function hasOverlap(rangeA, rangeB) { | ||
const lte = positionLessThanOrEqual(rangeA.startLine, rangeA.startColumn, rangeB.startLine, rangeB.startColumn); | ||
const first = lte ? rangeA : rangeB; | ||
const second = lte ? rangeB : rangeA; | ||
return positionLessThanOrEqual(second.startLine, second.startColumn, first.endLine, first.endColumn); | ||
}; | ||
// Determines if the front matter includes a title | ||
@@ -484,3 +378,3 @@ module.exports.frontMatterHasTitle = | ||
* | ||
* @param {import("../helpers/micromark.cjs").Token[]} tokens Micromark tokens. | ||
* @param {import("../helpers/micromark-helpers.cjs").Token[]} tokens Micromark tokens. | ||
* @returns {Object} Reference link/image data. | ||
@@ -490,7 +384,19 @@ */ | ||
const normalizeReference = (s) => s.toLowerCase().trim().replace(/\s+/g, " "); | ||
const references = new Map(); | ||
const shortcuts = new Map(); | ||
const addReferenceToDictionary = (token, label, isShortcut) => { | ||
const referenceDatum = [ | ||
token.startLine - 1, | ||
token.startColumn - 1, | ||
token.text.length | ||
]; | ||
const reference = normalizeReference(label); | ||
const dictionary = isShortcut ? shortcuts : references; | ||
const referenceData = dictionary.get(reference) || []; | ||
referenceData.push(referenceDatum); | ||
dictionary.set(reference, referenceData); | ||
}; | ||
const definitions = new Map(); | ||
const definitionLineIndices = []; | ||
const duplicateDefinitions = []; | ||
const references = new Map(); | ||
const shortcuts = new Map(); | ||
const filteredTokens = | ||
@@ -505,3 +411,5 @@ micromark.filterByTypes( | ||
// references and shortcuts | ||
"gfmFootnoteCall", "image", "link" | ||
"gfmFootnoteCall", "image", "link", | ||
// undefined link labels | ||
"undefinedReferenceCollapsed", "undefinedReferenceFull", "undefinedReferenceShortcut" | ||
] | ||
@@ -529,11 +437,6 @@ ); | ||
} else { | ||
let destinationString = null; | ||
const parent = | ||
micromark.getTokenParentOfType(token, [ "definition" ]); | ||
if (parent) { | ||
destinationString = micromark.getTokenTextByType( | ||
micromark.filterByPredicate(parent.children), | ||
"definitionDestinationString" | ||
); | ||
} | ||
micromark.getParentOfType(token, [ "definition" ]); | ||
const destinationString = parent && | ||
micromark.getDescendantsByType(parent, [ "definitionDestination", "definitionDestinationRaw", "definitionDestinationString" ])[0]?.text; | ||
definitions.set( | ||
@@ -550,63 +453,34 @@ reference, | ||
{ | ||
let isShortcut = false; | ||
let isFullOrCollapsed = false; | ||
let labelText = null; | ||
let referenceStringText = null; | ||
const shortcutCandidate = | ||
micromark.matchAndGetTokensByType(token.children, [ "label" ]); | ||
if (shortcutCandidate) { | ||
labelText = | ||
micromark.getTokenTextByType( | ||
shortcutCandidate[0].children, "labelText" | ||
); | ||
isShortcut = (labelText !== null); | ||
} | ||
const fullAndCollapsedCandidate = | ||
micromark.matchAndGetTokensByType( | ||
token.children, [ "label", "reference" ] | ||
// Identify if shortcut or full/collapsed | ||
let isShortcut = (token.children.length === 1); | ||
const isFullOrCollapsed = (token.children.length === 2) && !token.children.some((t) => t.type === "resource"); | ||
const [ labelText ] = micromark.getDescendantsByType(token, [ "label", "labelText" ]); | ||
const [ referenceString ] = micromark.getDescendantsByType(token, [ "reference", "referenceString" ]); | ||
let label = labelText?.text; | ||
// Identify if footnote | ||
if (!isShortcut && !isFullOrCollapsed) { | ||
const [ footnoteCallMarker, footnoteCallString ] = token.children.filter( | ||
(t) => [ "gfmFootnoteCallMarker", "gfmFootnoteCallString" ].includes(t.type) | ||
); | ||
if (fullAndCollapsedCandidate) { | ||
labelText = | ||
micromark.getTokenTextByType( | ||
fullAndCollapsedCandidate[0].children, "labelText" | ||
); | ||
referenceStringText = | ||
micromark.getTokenTextByType( | ||
fullAndCollapsedCandidate[1].children, "referenceString" | ||
); | ||
isFullOrCollapsed = (labelText !== null); | ||
if (footnoteCallMarker && footnoteCallString) { | ||
label = `${footnoteCallMarker.text}${footnoteCallString.text}`; | ||
isShortcut = true; | ||
} | ||
} | ||
const footnote = micromark.matchAndGetTokensByType( | ||
token.children, | ||
[ | ||
"gfmFootnoteCallLabelMarker", "gfmFootnoteCallMarker", | ||
"gfmFootnoteCallString", "gfmFootnoteCallLabelMarker" | ||
], | ||
[ "gfmFootnoteCallMarker", "gfmFootnoteCallString" ] | ||
); | ||
if (footnote) { | ||
const callMarkerText = footnote[0].text; | ||
const callString = footnote[1].text; | ||
labelText = `${callMarkerText}${callString}`; | ||
isShortcut = true; | ||
} | ||
// Track shortcuts separately due to ambiguity in "text [text] text" | ||
// Track link (handle shortcuts separately due to ambiguity in "text [text] text") | ||
if (isShortcut || isFullOrCollapsed) { | ||
const referenceDatum = [ | ||
token.startLine - 1, | ||
token.startColumn - 1, | ||
token.text.length, | ||
// @ts-ignore | ||
labelText.length, | ||
(referenceStringText || "").length | ||
]; | ||
const reference = | ||
normalizeReference(referenceStringText || labelText); | ||
const dictionary = isShortcut ? shortcuts : references; | ||
const referenceData = dictionary.get(reference) || []; | ||
referenceData.push(referenceDatum); | ||
dictionary.set(reference, referenceData); | ||
addReferenceToDictionary(token, referenceString?.text || label, isShortcut); | ||
} | ||
} | ||
break; | ||
case "undefinedReferenceCollapsed": | ||
case "undefinedReferenceFull": | ||
case "undefinedReferenceShortcut": | ||
{ | ||
const undefinedReference = micromark.getDescendantsByType(token, [ "undefinedReference" ])[0]; | ||
const label = undefinedReference.children.map((t) => t.text).join(""); | ||
const isShortcut = (token.type === "undefinedReferenceShortcut"); | ||
addReferenceToDictionary(token, label, isShortcut); | ||
} | ||
break; | ||
} | ||
@@ -665,116 +539,2 @@ } | ||
/** | ||
* Normalizes the fields of a RuleOnErrorFixInfo instance. | ||
* | ||
* @param {Object} fixInfo RuleOnErrorFixInfo instance. | ||
* @param {number} [lineNumber] Line number. | ||
* @returns {Object} Normalized RuleOnErrorFixInfo instance. | ||
*/ | ||
function normalizeFixInfo(fixInfo, lineNumber) { | ||
return { | ||
"lineNumber": fixInfo.lineNumber || lineNumber, | ||
"editColumn": fixInfo.editColumn || 1, | ||
"deleteCount": fixInfo.deleteCount || 0, | ||
"insertText": fixInfo.insertText || "" | ||
}; | ||
} | ||
/** | ||
* Fixes the specified error on a line of Markdown content. | ||
* | ||
* @param {string} line Line of Markdown content. | ||
* @param {Object} fixInfo RuleOnErrorFixInfo instance. | ||
* @param {string} [lineEnding] Line ending to use. | ||
* @returns {string | null} Fixed content. | ||
*/ | ||
function applyFix(line, fixInfo, lineEnding) { | ||
const { editColumn, deleteCount, insertText } = normalizeFixInfo(fixInfo); | ||
const editIndex = editColumn - 1; | ||
return (deleteCount === -1) ? | ||
null : | ||
line.slice(0, editIndex) + | ||
insertText.replace(/\n/g, lineEnding || "\n") + | ||
line.slice(editIndex + deleteCount); | ||
} | ||
module.exports.applyFix = applyFix; | ||
/** | ||
* Applies as many fixes as possible to Markdown content. | ||
* | ||
* @param {string} input Lines of Markdown content. | ||
* @param {Object[]} errors RuleOnErrorInfo instances. | ||
* @returns {string} Corrected content. | ||
*/ | ||
function applyFixes(input, errors) { | ||
const lineEnding = getPreferredLineEnding(input, require("node:os")); | ||
const lines = input.split(newLineRe); | ||
// Normalize fixInfo objects | ||
let fixInfos = errors | ||
.filter((error) => error.fixInfo) | ||
.map((error) => normalizeFixInfo(error.fixInfo, error.lineNumber)); | ||
// Sort bottom-to-top, line-deletes last, right-to-left, long-to-short | ||
fixInfos.sort((a, b) => { | ||
const aDeletingLine = (a.deleteCount === -1); | ||
const bDeletingLine = (b.deleteCount === -1); | ||
return ( | ||
(b.lineNumber - a.lineNumber) || | ||
(aDeletingLine ? 1 : (bDeletingLine ? -1 : 0)) || | ||
(b.editColumn - a.editColumn) || | ||
(b.insertText.length - a.insertText.length) | ||
); | ||
}); | ||
// Remove duplicate entries (needed for following collapse step) | ||
let lastFixInfo = {}; | ||
fixInfos = fixInfos.filter((fixInfo) => { | ||
const unique = ( | ||
(fixInfo.lineNumber !== lastFixInfo.lineNumber) || | ||
(fixInfo.editColumn !== lastFixInfo.editColumn) || | ||
(fixInfo.deleteCount !== lastFixInfo.deleteCount) || | ||
(fixInfo.insertText !== lastFixInfo.insertText) | ||
); | ||
lastFixInfo = fixInfo; | ||
return unique; | ||
}); | ||
// Collapse insert/no-delete and no-insert/delete for same line/column | ||
lastFixInfo = { | ||
"lineNumber": -1 | ||
}; | ||
for (const fixInfo of fixInfos) { | ||
if ( | ||
(fixInfo.lineNumber === lastFixInfo.lineNumber) && | ||
(fixInfo.editColumn === lastFixInfo.editColumn) && | ||
!fixInfo.insertText && | ||
(fixInfo.deleteCount > 0) && | ||
lastFixInfo.insertText && | ||
!lastFixInfo.deleteCount) { | ||
fixInfo.insertText = lastFixInfo.insertText; | ||
lastFixInfo.lineNumber = 0; | ||
} | ||
lastFixInfo = fixInfo; | ||
} | ||
fixInfos = fixInfos.filter((fixInfo) => fixInfo.lineNumber); | ||
// Apply all (remaining/updated) fixes | ||
let lastLineIndex = -1; | ||
let lastEditIndex = -1; | ||
for (const fixInfo of fixInfos) { | ||
const { lineNumber, editColumn, deleteCount } = fixInfo; | ||
const lineIndex = lineNumber - 1; | ||
const editIndex = editColumn - 1; | ||
if ( | ||
(lineIndex !== lastLineIndex) || | ||
(deleteCount === -1) || | ||
((editIndex + deleteCount) <= | ||
(lastEditIndex - ((deleteCount > 0) ? 0 : 1))) | ||
) { | ||
// @ts-ignore | ||
lines[lineIndex] = applyFix(lines[lineIndex], fixInfo, lineEnding); | ||
} | ||
lastLineIndex = lineIndex; | ||
lastEditIndex = editIndex; | ||
} | ||
// Return corrected input | ||
return lines.filter((line) => line !== null).join(lineEnding); | ||
} | ||
module.exports.applyFixes = applyFixes; | ||
/** | ||
* Expands a path with a tilde to an absolute path. | ||
@@ -791,21 +551,1 @@ * | ||
module.exports.expandTildePath = expandTildePath; | ||
// Copied from markdownlint.js to avoid TypeScript compiler import() issue. | ||
/** | ||
* @typedef {Object} MarkdownItToken | ||
* @property {string[][]} attrs HTML attributes. | ||
* @property {boolean} block Block-level token. | ||
* @property {MarkdownItToken[]} children Child nodes. | ||
* @property {string} content Tag contents. | ||
* @property {boolean} hidden Ignore element. | ||
* @property {string} info Fence info. | ||
* @property {number} level Nesting level. | ||
* @property {number[]} map Beginning/ending line numbers. | ||
* @property {string} markup Markup text. | ||
* @property {Object} meta Arbitrary data. | ||
* @property {number} nesting Level change. | ||
* @property {string} tag HTML tag name. | ||
* @property {string} type Token type. | ||
* @property {number} lineNumber Line number (1-based). | ||
* @property {string} line Line content. | ||
*/ |
{ | ||
"name": "markdownlint-rule-helpers", | ||
"version": "0.26.0", | ||
"version": "0.27.0", | ||
"description": "A collection of markdownlint helper functions for custom rules", | ||
"main": "./helpers.js", | ||
"exports": "./helpers.js", | ||
"exports": { | ||
".": "./helpers.js", | ||
"./micromark": "./micromark-helpers.cjs" | ||
}, | ||
"author": "David Anson (https://dlaa.me/)", | ||
@@ -8,0 +11,0 @@ "license": "MIT", |
@@ -20,18 +20,2 @@ # markdownlint-rule-helpers | ||
## Examples | ||
### Applying Recommended Fixes | ||
```javascript | ||
const { "sync": markdownlintSync } = require("markdownlint"); | ||
const markdownlintRuleHelpers = require("markdownlint-rule-helpers"); | ||
function fixMarkdownlintViolations(content) { | ||
const fixResults = markdownlintSync({ strings: { content } }); | ||
return markdownlintRuleHelpers.applyFixes(content, fixResults.content); | ||
} | ||
``` | ||
See also: [`markdownlint` built-in rule implementations][lib]. | ||
## Tests | ||
@@ -42,7 +26,6 @@ | ||
[custom-rules]: https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/CustomRules.md | ||
[custom-rules]: https://github.com/DavidAnson/markdownlint/blob/v0.36.0/doc/CustomRules.md | ||
[jsdoc]: https://en.m.wikipedia.org/wiki/JSDoc | ||
[lib]: https://github.com/DavidAnson/markdownlint/tree/v0.35.0/lib | ||
[markdown]: https://en.wikipedia.org/wiki/Markdown | ||
[markdownlint]: https://github.com/DavidAnson/markdownlint | ||
[rules]: https://github.com/DavidAnson/markdownlint/blob/v0.35.0/doc/Rules.md | ||
[rules]: https://github.com/DavidAnson/markdownlint/blob/v0.36.0/doc/Rules.md |
@@ -5,2 +5,8 @@ // @ts-check | ||
// Symbol for identifing the flat tokens array from micromark parse | ||
module.exports.flatTokensSymbol = Symbol("flat-tokens"); | ||
// Symbol for identifying the htmlFlow token from micromark parse | ||
module.exports.htmlFlowSymbol = Symbol("html-flow"); | ||
// Regular expression for matching common newline characters | ||
@@ -7,0 +13,0 @@ // See NEWLINES_RE in markdown-it/lib/rules_core/normalize.js |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
8
40841
1101
30
2
1