Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

unified-message-control

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

unified-message-control - npm Package Compare versions

Comparing version 3.0.3 to 4.0.0

205

index.d.ts

@@ -1,116 +0,103 @@

// TypeScript Version: 3.4
import {Node} from 'unist'
import {Transformer} from 'unified'
import {Test} from 'unist-util-is'
declare namespace messageControl {
/**
* @type {import('unified').Plugin<[Options]>}
* @returns {(tree: Node, file: VFile) => void}
*/
export default function messageControl(
options: Options
): (tree: Node, file: VFile) => void
export type Node = import('unist').Node
export type Parent = import('unist').Parent
export type Point = import('unist').Point
export type Test = import('unist-util-is').Test
export type VFile = import('vfile').VFile
export type VFileMessage = import('vfile-message').VFileMessage
export type Options = OptionsWithoutReset | OptionsWithReset
export type OptionsWithoutReset = OptionsBaseFields & OptionsWithoutResetFields
export type OptionsWithReset = OptionsBaseFields & OptionsWithResetFields
export type OptionsWithoutResetFields = {
/**
* A comment marker.
* Whether to treat all messages as turned off initially.
*/
interface Marker<N extends Node> {
/**
* Name of marker
*/
name: string
/**
* Value after name
*/
attributes: string
/**
* Parsed attributes
*/
parameters: Record<string, unknown>
/**
* Reference to given node
*/
node: N
}
reset?: false | undefined
/**
* Parse a possible comment marker node to a Marker
* List of `ruleId`s to turn off.
*/
type MarkerParser<N extends Node> = (node: N) => Marker<N> | null
interface MessageControlOptionsWithReset<T extends Node>
extends BaseMessageControlOptions<T> {
/**
* Whether to treat all messages as turned off initially
*/
reset: true
/**
* List of `ruleId`s to initially turn on.
*/
enable?: string[]
}
interface MessageControlOptionsWithoutReset<T extends Node>
extends BaseMessageControlOptions<T> {
/**
* Whether to treat all messages as turned off initially
*/
reset?: false
/**
* List of `ruleId`s to turn off
*/
disable?: string[]
}
interface BaseMessageControlOptions<T extends Node> {
/**
* Name of markers that can control the message sources.
*
* For example. `{name: 'alpha'}` controls `alpha` markers:
*
* `<!--alpha ignore-->`
*/
name: string
/**
* Test for possible markers
*/
test: Test<T>
/**
* Parse a possible marker to a comment marker object (Marker)
* if possible the marker isn't a marker, should return `null`.
*/
marker: MarkerParser<T>
/**
* List of allowed `ruleId`s. When given a warning is shown
* when someone tries to control an unknown rule.
*
* For example, `{name: 'alpha', known: ['bravo']}` results
* in a warning if `charlie is configured:
*
* `<!--alpha ignore charlie-->`
*/
known?: string[]
/**
* Sources that can be controlled with `name` markers.
*
* @defaultValue `MessageControlOptions.name`
*/
sources?: string | string[]
}
type MessageControlOptions<T extends Node> =
| MessageControlOptionsWithoutReset<T>
| MessageControlOptionsWithReset<T>
disable?: string[] | undefined
}
export type OptionsWithResetFields = {
/**
* Whether to treat all messages as turned off initially.
*/
reset: true
/**
* List of `ruleId`s to initially turn on.
*/
enable?: string[] | undefined
}
export type OptionsBaseFields = {
/**
* Name of markers that can control the message sources.
*
* For example, `{name: 'alpha'}` controls `alpha` markers:
*
* ```html
* <!--alpha ignore-->
* ```
*/
name: string
/**
* Parse a possible marker to a comment marker object (Marker).
* If the marker isn't a marker, should return `null`.
*/
marker: MarkerParser
/**
* Test for possible markers
*/
test?: Test
/**
* List of allowed `ruleId`s. When given a warning is shown
* when someone tries to control an unknown rule.
*
* For example, `{name: 'alpha', known: ['bravo']}` results in a warning if
* `charlie` is configured:
*
* ```html
* <!--alpha ignore charlie-->
* ```
*/
known?: string[] | undefined
/**
* Sources that can be controlled with `name` markers.
* Defaults to `name`.
*/
source?: string | string[] | undefined
}
/**
* Enable, disable, and ignore messages with unified.
* Parse a possible comment marker node to a Marker.
*/
declare function messageControl<T extends Node>(
options?: messageControl.MessageControlOptions<T>
): Transformer
export = messageControl
export type MarkerParser = (node: Node) => any
/**
* A comment marker.
*/
export type Marker = {
/**
* Name of marker.
*/
name: string
/**
* Value after name.
*/
attributes: string
/**
* Parsed attributes.
*/
parameters: Record<string, string | number | boolean>
/**
* Reference to given node.
*/
node: Node
}
export type Mark = {
point: Point | undefined
state: boolean
}

@@ -1,66 +0,148 @@

'use strict'
/**
* @typedef {import('unist').Node} Node
* @typedef {import('unist').Parent} Parent
* @typedef {import('unist').Point} Point
* @typedef {import('unist-util-is').Test} Test
* @typedef {import('vfile').VFile} VFile
* @typedef {import('vfile-message').VFileMessage} VFileMessage
*
* @typedef {OptionsWithoutReset|OptionsWithReset} Options
* @typedef {OptionsBaseFields & OptionsWithoutResetFields} OptionsWithoutReset
* @typedef {OptionsBaseFields & OptionsWithResetFields} OptionsWithReset
*
* @typedef OptionsWithoutResetFields
* @property {false} [reset]
* Whether to treat all messages as turned off initially.
* @property {string[]} [disable]
* List of `ruleId`s to turn off.
*
* @typedef OptionsWithResetFields
* @property {true} reset
* Whether to treat all messages as turned off initially.
* @property {string[]} [enable]
* List of `ruleId`s to initially turn on.
*
* @typedef OptionsBaseFields
* @property {string} name
* Name of markers that can control the message sources.
*
* For example, `{name: 'alpha'}` controls `alpha` markers:
*
* ```html
* <!--alpha ignore-->
* ```
* @property {MarkerParser} marker
* Parse a possible marker to a comment marker object (Marker).
* If the marker isn't a marker, should return `null`.
* @property {Test} [test]
* Test for possible markers
* @property {string[]} [known]
* List of allowed `ruleId`s. When given a warning is shown
* when someone tries to control an unknown rule.
*
* For example, `{name: 'alpha', known: ['bravo']}` results in a warning if
* `charlie` is configured:
*
* ```html
* <!--alpha ignore charlie-->
* ```
* @property {string|string[]} [source]
* Sources that can be controlled with `name` markers.
* Defaults to `name`.
*
* @callback MarkerParser
* Parse a possible comment marker node to a Marker.
* @param {Node} node
* Node to parse
*
* @typedef Marker
* A comment marker.
* @property {string} name
* Name of marker.
* @property {string} attributes
* Value after name.
* @property {Record<string, string|number|boolean>} parameters
* Parsed attributes.
* @property {Node} node
* Reference to given node.
*
* @typedef Mark
* @property {Point|undefined} point
* @property {boolean} state
*/
var location = require('vfile-location')
var visit = require('unist-util-visit')
import {location} from 'vfile-location'
import {visit} from 'unist-util-visit'
module.exports = messageControl
const own = {}.hasOwnProperty
function messageControl(options) {
var settings = options || {}
var enable = settings.enable || []
var disable = settings.disable || []
var sources = settings.source
var reset = settings.reset
if (!settings.name) {
throw new Error('Expected `name` in `options`, got `' + settings.name + '`')
/**
* @type {import('unified').Plugin<[Options]>}
* @returns {(tree: Node, file: VFile) => void}
*/
export default function messageControl(options) {
if (!options || typeof options !== 'object' || !options.name) {
throw new Error(
'Expected `name` in `options`, got `' + (options || {}).name + '`'
)
}
if (!settings.marker) {
if (!options.marker) {
throw new Error(
'Expected `marker` in `options`, got `' + settings.marker + '`'
'Expected `marker` in `options`, got `' + options.marker + '`'
)
}
if (!sources) {
sources = [settings.name]
} else if (typeof sources === 'string') {
sources = [sources]
}
const enable = 'enable' in options && options.enable ? options.enable : []
const disable = 'disable' in options && options.disable ? options.disable : []
let reset = options.reset
const sources =
typeof options.source === 'string'
? [options.source]
: options.source || [options.name]
return transformer
/**
* @param {Node} tree
* @param {VFile} file
*/
function transformer(tree, file) {
var toOffset = location(file).toOffset
var initial = !reset
var gaps = detectGaps(tree, file)
var scope = {}
var globals = []
const toOffset = location(file).toOffset
const initial = !reset
const gaps = detectGaps(tree, file)
/** @type {Record<string, Mark[]>} */
const scope = {}
/** @type {Mark[]} */
const globals = []
visit(tree, settings.test, visitor)
visit(tree, options.test, visitor)
file.messages = file.messages.filter(filter)
file.messages = file.messages.filter((m) => filter(m))
/**
* @param {Node} node
* @param {number|null} position
* @param {Parent|null} parent
*/
function visitor(node, position, parent) {
var mark = settings.marker(node)
var ruleIds
var verb
var pos
var tail
var index
var ruleId
/** @type {Marker|null} */
const mark = options.marker(node)
if (!mark || mark.name !== settings.name) {
if (!mark || mark.name !== options.name) {
return
}
ruleIds = mark.attributes.split(/\s/g)
verb = ruleIds.shift()
pos = mark.node.position && mark.node.position.start
tail =
parent.children[position + 1] &&
parent.children[position + 1].position &&
parent.children[position + 1].position.end
index = -1
const ruleIds = mark.attributes.split(/\s/g)
const point = mark.node.position && mark.node.position.start
const next =
(parent && position !== null && parent.children[position + 1]) ||
undefined
const tail = (next && next.position && next.position.end) || undefined
let index = -1
/** @type {string} */
// @ts-expect-error: we’ll check for unknown values next.
const verb = ruleIds.shift()
if (verb !== 'enable' && verb !== 'disable' && verb !== 'ignore') {

@@ -77,8 +159,8 @@ file.fail(

// Apply to all rules.
if (ruleIds.length) {
if (ruleIds.length > 0) {
while (++index < ruleIds.length) {
ruleId = ruleIds[index]
const ruleId = ruleIds[index]
if (isKnown(ruleId, verb, mark.node)) {
toggle(pos, verb === 'enable', ruleId)
toggle(point, verb === 'enable', ruleId)

@@ -91,6 +173,6 @@ if (verb === 'ignore') {

} else if (verb === 'ignore') {
toggle(pos, false)
toggle(point, false)
toggle(tail, true)
} else {
toggle(pos, verb === 'enable')
toggle(point, verb === 'enable')
reset = verb !== 'enable'

@@ -100,8 +182,11 @@ }

/**
* @param {VFileMessage} message
* @returns {boolean}
*/
function filter(message) {
var gapIndex = gaps.length
var pos
let gapIndex = gaps.length
// Keep messages from a different source.
if (!message.source || sources.indexOf(message.source) === -1) {
if (!message.source || !sources.includes(message.source)) {
return true

@@ -121,6 +206,7 @@ }

// Check whether the warning is inside a gap.
pos = toOffset(message)
// @ts-expect-error: we just normalized `null` to `number`s.
const offset = toOffset(message)
while (gapIndex--) {
if (gaps[gapIndex].start <= pos && gaps[gapIndex].end > pos) {
if (gaps[gapIndex][0] <= offset && gaps[gapIndex][1] > offset) {
return false

@@ -132,3 +218,4 @@ }

return (
check(message, scope[message.ruleId], message.ruleId) &&
(!message.ruleId ||
check(message, scope[message.ruleId], message.ruleId)) &&
check(message, globals)

@@ -138,5 +225,12 @@ )

// Helper to check (and possibly warn) if a `ruleId` is unknown.
function isKnown(ruleId, verb, pos) {
var result = settings.known ? settings.known.indexOf(ruleId) !== -1 : true
/**
* Helper to check (and possibly warn) if a `ruleId` is unknown.
*
* @param {string} ruleId
* @param {string} verb
* @param {Node} node
* @returns {boolean}
*/
function isKnown(ruleId, verb, node) {
const result = options.known ? options.known.includes(ruleId) : true

@@ -146,3 +240,3 @@ if (!result) {

'Unknown rule: cannot ' + verb + " `'" + ruleId + "'`",
pos
node
)

@@ -154,8 +248,13 @@ }

// Get the latest state of a rule.
// When without `ruleId`, gets global state.
/**
* Get the latest state of a rule.
* When without `ruleId`, gets global state.
*
* @param {string|undefined} ruleId
* @returns {boolean}
*/
function getState(ruleId) {
var ranges = ruleId ? scope[ruleId] : globals
const ranges = ruleId ? scope[ruleId] : globals
if (ranges && ranges.length) {
if (ranges && ranges.length > 0) {
return ranges[ranges.length - 1].state

@@ -168,19 +267,25 @@ }

return reset ? enable.indexOf(ruleId) > -1 : disable.indexOf(ruleId) < 0
return reset ? enable.includes(ruleId) : !disable.includes(ruleId)
}
// Handle a rule.
function toggle(pos, state, ruleId) {
var markers = ruleId ? scope[ruleId] : globals
var previousState
/**
* Handle a rule.
*
* @param {Point|undefined} point
* @param {boolean} state
* @param {string|undefined} [ruleId]
* @returns {void}
*/
function toggle(point, state, ruleId) {
let markers = ruleId ? scope[ruleId] : globals
if (!markers) {
markers = []
scope[ruleId] = markers
scope[String(ruleId)] = markers
}
previousState = getState(ruleId)
const previousState = getState(ruleId)
if (state !== previousState) {
markers.push({state: state, position: pos})
markers.push({state, point})
}

@@ -191,3 +296,5 @@

for (ruleId in scope) {
toggle(pos, state, ruleId)
if (own.call(scope, ruleId)) {
toggle(point, state, ruleId)
}
}

@@ -197,17 +304,30 @@ }

// Check all `ranges` for `message`.
/**
* Check all `ranges` for `message`.
*
* @param {VFileMessage} message
* @param {Mark[]|undefined} ranges
* @param {string|undefined} [ruleId]
* @returns {boolean}
*/
function check(message, ranges, ruleId) {
// Check the state at the message’s position.
var index = ranges && ranges.length
if (ranges && ranges.length > 0) {
// Check the state at the message’s position.
let index = ranges.length
while (index--) {
if (
ranges[index].position &&
ranges[index].position.line &&
ranges[index].position.column &&
(ranges[index].position.line < message.line ||
(ranges[index].position.line === message.line &&
ranges[index].position.column <= message.column))
) {
return ranges[index].state === true
while (index--) {
const range = ranges[index]
if (
message.line &&
message.column &&
range.point &&
range.point.line &&
range.point.column &&
(range.point.line < message.line ||
(range.point.line === message.line &&
range.point.column <= message.column))
) {
return range.state === true
}
}

@@ -219,6 +339,6 @@ }

if (!ruleId) {
return initial || reset
return Boolean(initial || reset)
}
return reset ? enable.indexOf(ruleId) > -1 : disable.indexOf(ruleId) < 0
return reset ? enable.includes(ruleId) : !disable.includes(ruleId)
}

@@ -228,9 +348,18 @@ }

// Detect gaps in `tree`.
/**
* Detect gaps in `tree`.
*
* @param {Node} tree
* @param {VFile} file
*/
function detectGaps(tree, file) {
var children = tree.children || []
var lastNode = children[children.length - 1]
var offset = 0
var gaps = []
var gap
/** @type {Node[]} */
// @ts-expect-error: fine.
const children = tree.children || []
const lastNode = children[children.length - 1]
/** @type {[number, number][]} */
const gaps = []
let offset = 0
/** @type {boolean|undefined} */
let gap

@@ -249,3 +378,3 @@ // Find all gaps.

offset === lastNode.position.end.offset &&
trim(file.toString().slice(offset)) !== ''
file.toString().slice(offset).trim() !== ''
) {

@@ -255,3 +384,7 @@ update()

update(
tree && tree.position && tree.position.end && tree.position.end.offset - 1
tree &&
tree.position &&
tree.position.end &&
tree.position.end.offset &&
tree.position.end.offset - 1
)

@@ -262,6 +395,9 @@ }

/**
* @param {Node} node
*/
function one(node) {
update(node.position && node.position.start && node.position.start.offset)
if (!node.children) {
if (!('children' in node)) {
update(node.position && node.position.end && node.position.end.offset)

@@ -271,3 +407,8 @@ }

// Detect a new position.
/**
* Detect a new position.
*
* @param {number|undefined} [latest]
* @returns {void}
*/
function update(latest) {

@@ -278,4 +419,4 @@ if (latest === null || latest === undefined) {

if (gap) {
gaps.push({start: offset, end: latest})
gap = null
gaps.push([offset, latest])
gap = undefined
}

@@ -287,5 +428,1 @@

}
function trim(value) {
return value.replace(/^\s+|\s+$/g, '')
}
{
"name": "unified-message-control",
"version": "3.0.3",
"version": "4.0.0",
"description": "Enable, disable, and ignore messages from unified processors",

@@ -26,18 +26,22 @@ "license": "MIT",

],
"sideEffects": false,
"type": "module",
"main": "index.js",
"types": "index.d.ts",
"files": [
"index.js",
"index.d.ts"
"index.d.ts",
"index.js"
],
"dependencies": {
"unist-util-visit": "^2.0.0",
"vfile-location": "^3.0.0"
"@types/unist": "^2.0.0",
"unist-util-is": "^5.0.0",
"unist-util-visit": "^3.0.0",
"vfile": "^5.0.0",
"vfile-location": "^4.0.0",
"vfile-message": "^3.0.0"
},
"devDependencies": {
"@types/hast": "^2.0.0",
"@types/mdast": "^3.0.0",
"@types/unist": "^2.0.0",
"browserify": "^17.0.0",
"dtslint": "^4.0.0",
"mdast-comment-marker": "^1.0.0",
"nyc": "^15.0.0",
"@types/tape": "^4.0.0",
"c8": "^7.0.0",
"mdast-comment-marker": "^2.0.0",
"prettier": "^2.0.0",

@@ -48,24 +52,16 @@ "remark": "^13.0.0",

"remark-toc": "^7.0.0",
"rimraf": "^3.0.0",
"tape": "^5.0.0",
"tinyify": "^3.0.0",
"unified": "^9.0.0",
"unist-util-is": "^4.0.0",
"xo": "^0.37.0"
"type-coverage": "^2.0.0",
"typescript": "^4.0.0",
"unified": "^10.0.0",
"xo": "^0.39.0"
},
"scripts": {
"format": "remark . -qfo && prettier . --write && xo --fix",
"build-bundle": "browserify index.js -s unifiedMessageControl -o unified-message-control.js",
"build-mangle": "browserify index.js -s unifiedMessageControl -p tinyify -o unified-message-control.min.js",
"build": "npm run build-bundle && npm run build-mangle",
"test-api": "node test",
"test-coverage": "nyc --reporter lcov tape test.js",
"test-types": "dtslint",
"test": "npm run test-types && npm run format && npm run build && npm run test-coverage"
"build": "rimraf \"*.d.ts\" && tsc && type-coverage",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"test-api": "node --conditions development test.js",
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node --conditions development test.js",
"test": "npm run build && npm run format && npm run test-coverage"
},
"nyc": {
"check-coverage": true,
"lines": 100,
"functions": 100,
"branches": 100
},
"prettier": {

@@ -80,15 +76,3 @@ "tabWidth": 2,

"xo": {
"prettier": true,
"esnext": false,
"rules": {
"guard-for-in": "off",
"unicorn/explicit-length-check": "off",
"unicorn/no-array-callback-reference": "off",
"unicorn/prefer-includes": "off",
"unicorn/string-content": "off"
},
"ignores": [
"*.ts",
"unified-message-control.js"
]
"prettier": true
},

@@ -99,3 +83,9 @@ "remarkConfig": {

]
},
"typeCoverage": {
"atLeast": 100,
"detail": true,
"strict": true,
"ignoreCatch": true
}
}

@@ -15,2 +15,5 @@ # unified-message-control

This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c):
Node 12+ is needed to use it and it must be `import`ed instead of `require`d.
[npm][]:

@@ -35,20 +38,27 @@

```js
var vfile = require('to-vfile')
var report = require('vfile-reporter')
var remark = require('remark')
var control = require('unified-message-control')
var mdastMarker = require('mdast-comment-marker')
import {toVFile} from 'to-vfile'
import {reporter} from 'vfile-reporter'
import {commentMarker} from 'mdast-comment-marker'
import {unified} from 'unified'
import unifiedMessageControl from 'unified-message-control'
import remarkParse from 'remark-parse'
import remarkStringify from 'remark-stringify'
remark()
.use(warn)
.use(control, {name: 'foo', marker: mdastMarker, test: 'html'})
.process(vfile.readSync('example.md'), function (err, file) {
console.error(report(err || file))
})
function warn() {
return function (tree, file) {
file.message('Whoops!', tree.children[1], 'foo:thing')
}
}
toVFile.read('example.md').then((file) => {
unified()
.use(remarkParse)
.use(remarkStringify)
.use(() => (tree, file) => {
file.message('Whoops!', tree.children[1], 'foo:thing')
})
.use(unifiedMessageControl, {
name: 'foo',
marker: commentMarker,
test: 'html'
})
.process(file)
.then((file) => {
console.error(reporter(file))
})
})
```

@@ -64,7 +74,10 @@

### `unified.use(control, options)`
This package exports the following identifiers: `messageControl`.
There is no default export.
### `unified().use(messageControl, options)`
Let comment markers control messages from certain sources.
##### Options
##### `options`

@@ -71,0 +84,0 @@ ###### `options.name`

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc