New source found from dndbeyond.com
This commit is contained in:
+787
@@ -0,0 +1,787 @@
|
||||
/**
|
||||
* @import {Identifier, Literal, MemberExpression} from 'estree'
|
||||
* @import {Jsx, JsxDev, Options, Props} from 'hast-util-to-jsx-runtime'
|
||||
* @import {Element, Nodes, Parents, Root, Text} from 'hast'
|
||||
* @import {MdxFlowExpressionHast, MdxTextExpressionHast} from 'mdast-util-mdx-expression'
|
||||
* @import {MdxJsxFlowElementHast, MdxJsxTextElementHast} from 'mdast-util-mdx-jsx'
|
||||
* @import {MdxjsEsmHast} from 'mdast-util-mdxjs-esm'
|
||||
* @import {Position} from 'unist'
|
||||
* @import {Child, Create, Field, JsxElement, State, Style} from './types.js'
|
||||
*/
|
||||
|
||||
import {stringify as commas} from 'comma-separated-tokens'
|
||||
import {ok as assert} from 'devlop'
|
||||
import {name as isIdentifierName} from 'estree-util-is-identifier-name'
|
||||
import {whitespace} from 'hast-util-whitespace'
|
||||
import {find, hastToReact, html, svg} from 'property-information'
|
||||
import {stringify as spaces} from 'space-separated-tokens'
|
||||
import styleToJs from 'style-to-js'
|
||||
import {pointStart} from 'unist-util-position'
|
||||
import {VFileMessage} from 'vfile-message'
|
||||
|
||||
// To do: next major: `Object.hasOwn`.
|
||||
const own = {}.hasOwnProperty
|
||||
|
||||
/** @type {Map<string, number>} */
|
||||
const emptyMap = new Map()
|
||||
|
||||
const cap = /[A-Z]/g
|
||||
|
||||
// `react-dom` triggers a warning for *any* white space in tables.
|
||||
// To follow GFM, `mdast-util-to-hast` injects line endings between elements.
|
||||
// Other tools might do so too, but they don’t do here, so we remove all of
|
||||
// that.
|
||||
|
||||
// See: <https://github.com/facebook/react/pull/7081>.
|
||||
// See: <https://github.com/facebook/react/pull/7515>.
|
||||
// See: <https://github.com/remarkjs/remark-react/issues/64>.
|
||||
// See: <https://github.com/rehypejs/rehype-react/pull/29>.
|
||||
// See: <https://github.com/rehypejs/rehype-react/pull/32>.
|
||||
// See: <https://github.com/rehypejs/rehype-react/pull/45>.
|
||||
const tableElements = new Set(['table', 'tbody', 'thead', 'tfoot', 'tr'])
|
||||
|
||||
const tableCellElement = new Set(['td', 'th'])
|
||||
|
||||
const docs = 'https://github.com/syntax-tree/hast-util-to-jsx-runtime'
|
||||
|
||||
/**
|
||||
* Transform a hast tree to preact, react, solid, svelte, vue, etc.,
|
||||
* with an automatic JSX runtime.
|
||||
*
|
||||
* @param {Nodes} tree
|
||||
* Tree to transform.
|
||||
* @param {Options} options
|
||||
* Configuration (required).
|
||||
* @returns {JsxElement}
|
||||
* JSX element.
|
||||
*/
|
||||
|
||||
export function toJsxRuntime(tree, options) {
|
||||
if (!options || options.Fragment === undefined) {
|
||||
throw new TypeError('Expected `Fragment` in options')
|
||||
}
|
||||
|
||||
const filePath = options.filePath || undefined
|
||||
/** @type {Create} */
|
||||
let create
|
||||
|
||||
if (options.development) {
|
||||
if (typeof options.jsxDEV !== 'function') {
|
||||
throw new TypeError(
|
||||
'Expected `jsxDEV` in options when `development: true`'
|
||||
)
|
||||
}
|
||||
|
||||
create = developmentCreate(filePath, options.jsxDEV)
|
||||
} else {
|
||||
if (typeof options.jsx !== 'function') {
|
||||
throw new TypeError('Expected `jsx` in production options')
|
||||
}
|
||||
|
||||
if (typeof options.jsxs !== 'function') {
|
||||
throw new TypeError('Expected `jsxs` in production options')
|
||||
}
|
||||
|
||||
create = productionCreate(filePath, options.jsx, options.jsxs)
|
||||
}
|
||||
|
||||
/** @type {State} */
|
||||
const state = {
|
||||
Fragment: options.Fragment,
|
||||
ancestors: [],
|
||||
components: options.components || {},
|
||||
create,
|
||||
elementAttributeNameCase: options.elementAttributeNameCase || 'react',
|
||||
evaluater: options.createEvaluater ? options.createEvaluater() : undefined,
|
||||
filePath,
|
||||
ignoreInvalidStyle: options.ignoreInvalidStyle || false,
|
||||
passKeys: options.passKeys !== false,
|
||||
passNode: options.passNode || false,
|
||||
schema: options.space === 'svg' ? svg : html,
|
||||
stylePropertyNameCase: options.stylePropertyNameCase || 'dom',
|
||||
tableCellAlignToStyle: options.tableCellAlignToStyle !== false
|
||||
}
|
||||
|
||||
const result = one(state, tree, undefined)
|
||||
|
||||
// JSX element.
|
||||
if (result && typeof result !== 'string') {
|
||||
return result
|
||||
}
|
||||
|
||||
// Text node or something that turned into nothing.
|
||||
return state.create(
|
||||
tree,
|
||||
state.Fragment,
|
||||
{children: result || undefined},
|
||||
undefined
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a node.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {Nodes} node
|
||||
* Current node.
|
||||
* @param {string | undefined} key
|
||||
* Key.
|
||||
* @returns {Child | undefined}
|
||||
* Child, optional.
|
||||
*/
|
||||
function one(state, node, key) {
|
||||
if (node.type === 'element') {
|
||||
return element(state, node, key)
|
||||
}
|
||||
|
||||
if (node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression') {
|
||||
return mdxExpression(state, node)
|
||||
}
|
||||
|
||||
if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') {
|
||||
return mdxJsxElement(state, node, key)
|
||||
}
|
||||
|
||||
if (node.type === 'mdxjsEsm') {
|
||||
return mdxEsm(state, node)
|
||||
}
|
||||
|
||||
if (node.type === 'root') {
|
||||
return root(state, node, key)
|
||||
}
|
||||
|
||||
if (node.type === 'text') {
|
||||
return text(state, node)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle element.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {Element} node
|
||||
* Current node.
|
||||
* @param {string | undefined} key
|
||||
* Key.
|
||||
* @returns {Child | undefined}
|
||||
* Child, optional.
|
||||
*/
|
||||
function element(state, node, key) {
|
||||
const parentSchema = state.schema
|
||||
let schema = parentSchema
|
||||
|
||||
if (node.tagName.toLowerCase() === 'svg' && parentSchema.space === 'html') {
|
||||
schema = svg
|
||||
state.schema = schema
|
||||
}
|
||||
|
||||
state.ancestors.push(node)
|
||||
|
||||
const type = findComponentFromName(state, node.tagName, false)
|
||||
const props = createElementProps(state, node)
|
||||
let children = createChildren(state, node)
|
||||
|
||||
if (tableElements.has(node.tagName)) {
|
||||
children = children.filter(function (child) {
|
||||
return typeof child === 'string' ? !whitespace(child) : true
|
||||
})
|
||||
}
|
||||
|
||||
addNode(state, props, type, node)
|
||||
addChildren(props, children)
|
||||
|
||||
// Restore.
|
||||
state.ancestors.pop()
|
||||
state.schema = parentSchema
|
||||
|
||||
return state.create(node, type, props, key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle MDX expression.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {MdxFlowExpressionHast | MdxTextExpressionHast} node
|
||||
* Current node.
|
||||
* @returns {Child | undefined}
|
||||
* Child, optional.
|
||||
*/
|
||||
function mdxExpression(state, node) {
|
||||
if (node.data && node.data.estree && state.evaluater) {
|
||||
const program = node.data.estree
|
||||
const expression = program.body[0]
|
||||
assert(expression.type === 'ExpressionStatement')
|
||||
|
||||
// Assume result is a child.
|
||||
return /** @type {Child | undefined} */ (
|
||||
state.evaluater.evaluateExpression(expression.expression)
|
||||
)
|
||||
}
|
||||
|
||||
crashEstree(state, node.position)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle MDX ESM.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {MdxjsEsmHast} node
|
||||
* Current node.
|
||||
* @returns {Child | undefined}
|
||||
* Child, optional.
|
||||
*/
|
||||
function mdxEsm(state, node) {
|
||||
if (node.data && node.data.estree && state.evaluater) {
|
||||
// Assume result is a child.
|
||||
return /** @type {Child | undefined} */ (
|
||||
state.evaluater.evaluateProgram(node.data.estree)
|
||||
)
|
||||
}
|
||||
|
||||
crashEstree(state, node.position)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle MDX JSX.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {MdxJsxFlowElementHast | MdxJsxTextElementHast} node
|
||||
* Current node.
|
||||
* @param {string | undefined} key
|
||||
* Key.
|
||||
* @returns {Child | undefined}
|
||||
* Child, optional.
|
||||
*/
|
||||
function mdxJsxElement(state, node, key) {
|
||||
const parentSchema = state.schema
|
||||
let schema = parentSchema
|
||||
|
||||
if (node.name === 'svg' && parentSchema.space === 'html') {
|
||||
schema = svg
|
||||
state.schema = schema
|
||||
}
|
||||
|
||||
state.ancestors.push(node)
|
||||
|
||||
const type =
|
||||
node.name === null
|
||||
? state.Fragment
|
||||
: findComponentFromName(state, node.name, true)
|
||||
const props = createJsxElementProps(state, node)
|
||||
const children = createChildren(state, node)
|
||||
|
||||
addNode(state, props, type, node)
|
||||
addChildren(props, children)
|
||||
|
||||
// Restore.
|
||||
state.ancestors.pop()
|
||||
state.schema = parentSchema
|
||||
|
||||
return state.create(node, type, props, key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle root.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {Root} node
|
||||
* Current node.
|
||||
* @param {string | undefined} key
|
||||
* Key.
|
||||
* @returns {Child | undefined}
|
||||
* Child, optional.
|
||||
*/
|
||||
function root(state, node, key) {
|
||||
/** @type {Props} */
|
||||
const props = {}
|
||||
|
||||
addChildren(props, createChildren(state, node))
|
||||
|
||||
return state.create(node, state.Fragment, props, key)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle text.
|
||||
*
|
||||
* @param {State} _
|
||||
* Info passed around.
|
||||
* @param {Text} node
|
||||
* Current node.
|
||||
* @returns {Child | undefined}
|
||||
* Child, optional.
|
||||
*/
|
||||
function text(_, node) {
|
||||
return node.value
|
||||
}
|
||||
|
||||
/**
|
||||
* Add `node` to props.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {Props} props
|
||||
* Props.
|
||||
* @param {unknown} type
|
||||
* Type.
|
||||
* @param {Element | MdxJsxFlowElementHast | MdxJsxTextElementHast} node
|
||||
* Node.
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
function addNode(state, props, type, node) {
|
||||
// If this is swapped out for a component:
|
||||
if (typeof type !== 'string' && type !== state.Fragment && state.passNode) {
|
||||
props.node = node
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add children to props.
|
||||
*
|
||||
* @param {Props} props
|
||||
* Props.
|
||||
* @param {Array<Child>} children
|
||||
* Children.
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
function addChildren(props, children) {
|
||||
if (children.length > 0) {
|
||||
const value = children.length > 1 ? children : children[0]
|
||||
|
||||
if (value) {
|
||||
props.children = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | undefined} _
|
||||
* Path to file.
|
||||
* @param {Jsx} jsx
|
||||
* Dynamic.
|
||||
* @param {Jsx} jsxs
|
||||
* Static.
|
||||
* @returns {Create}
|
||||
* Create a production element.
|
||||
*/
|
||||
function productionCreate(_, jsx, jsxs) {
|
||||
return create
|
||||
/** @type {Create} */
|
||||
function create(_, type, props, key) {
|
||||
// Only an array when there are 2 or more children.
|
||||
const isStaticChildren = Array.isArray(props.children)
|
||||
const fn = isStaticChildren ? jsxs : jsx
|
||||
return key ? fn(type, props, key) : fn(type, props)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | undefined} filePath
|
||||
* Path to file.
|
||||
* @param {JsxDev} jsxDEV
|
||||
* Development.
|
||||
* @returns {Create}
|
||||
* Create a development element.
|
||||
*/
|
||||
function developmentCreate(filePath, jsxDEV) {
|
||||
return create
|
||||
/** @type {Create} */
|
||||
function create(node, type, props, key) {
|
||||
// Only an array when there are 2 or more children.
|
||||
const isStaticChildren = Array.isArray(props.children)
|
||||
const point = pointStart(node)
|
||||
return jsxDEV(
|
||||
type,
|
||||
props,
|
||||
key,
|
||||
isStaticChildren,
|
||||
{
|
||||
columnNumber: point ? point.column - 1 : undefined,
|
||||
fileName: filePath,
|
||||
lineNumber: point ? point.line : undefined
|
||||
},
|
||||
undefined
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create props from an element.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {Element} node
|
||||
* Current element.
|
||||
* @returns {Props}
|
||||
* Props.
|
||||
*/
|
||||
function createElementProps(state, node) {
|
||||
/** @type {Props} */
|
||||
const props = {}
|
||||
/** @type {string | undefined} */
|
||||
let alignValue
|
||||
/** @type {string} */
|
||||
let prop
|
||||
|
||||
for (prop in node.properties) {
|
||||
if (prop !== 'children' && own.call(node.properties, prop)) {
|
||||
const result = createProperty(state, prop, node.properties[prop])
|
||||
|
||||
if (result) {
|
||||
const [key, value] = result
|
||||
|
||||
if (
|
||||
state.tableCellAlignToStyle &&
|
||||
key === 'align' &&
|
||||
typeof value === 'string' &&
|
||||
tableCellElement.has(node.tagName)
|
||||
) {
|
||||
alignValue = value
|
||||
} else {
|
||||
props[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alignValue) {
|
||||
// Assume style is an object.
|
||||
const style = /** @type {Style} */ (props.style || (props.style = {}))
|
||||
style[state.stylePropertyNameCase === 'css' ? 'text-align' : 'textAlign'] =
|
||||
alignValue
|
||||
}
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
/**
|
||||
* Create props from a JSX element.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {MdxJsxFlowElementHast | MdxJsxTextElementHast} node
|
||||
* Current JSX element.
|
||||
* @returns {Props}
|
||||
* Props.
|
||||
*/
|
||||
function createJsxElementProps(state, node) {
|
||||
/** @type {Props} */
|
||||
const props = {}
|
||||
|
||||
for (const attribute of node.attributes) {
|
||||
if (attribute.type === 'mdxJsxExpressionAttribute') {
|
||||
if (attribute.data && attribute.data.estree && state.evaluater) {
|
||||
const program = attribute.data.estree
|
||||
const expression = program.body[0]
|
||||
assert(expression.type === 'ExpressionStatement')
|
||||
const objectExpression = expression.expression
|
||||
assert(objectExpression.type === 'ObjectExpression')
|
||||
const property = objectExpression.properties[0]
|
||||
assert(property.type === 'SpreadElement')
|
||||
|
||||
Object.assign(
|
||||
props,
|
||||
state.evaluater.evaluateExpression(property.argument)
|
||||
)
|
||||
} else {
|
||||
crashEstree(state, node.position)
|
||||
}
|
||||
} else {
|
||||
// For JSX, the author is responsible of passing in the correct values.
|
||||
const name = attribute.name
|
||||
/** @type {unknown} */
|
||||
let value
|
||||
|
||||
if (attribute.value && typeof attribute.value === 'object') {
|
||||
if (
|
||||
attribute.value.data &&
|
||||
attribute.value.data.estree &&
|
||||
state.evaluater
|
||||
) {
|
||||
const program = attribute.value.data.estree
|
||||
const expression = program.body[0]
|
||||
assert(expression.type === 'ExpressionStatement')
|
||||
value = state.evaluater.evaluateExpression(expression.expression)
|
||||
} else {
|
||||
crashEstree(state, node.position)
|
||||
}
|
||||
} else {
|
||||
value = attribute.value === null ? true : attribute.value
|
||||
}
|
||||
|
||||
// Assume a prop.
|
||||
props[name] = /** @type {Props[keyof Props]} */ (value)
|
||||
}
|
||||
}
|
||||
|
||||
return props
|
||||
}
|
||||
|
||||
/**
|
||||
* Create children.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {Parents} node
|
||||
* Current element.
|
||||
* @returns {Array<Child>}
|
||||
* Children.
|
||||
*/
|
||||
function createChildren(state, node) {
|
||||
/** @type {Array<Child>} */
|
||||
const children = []
|
||||
let index = -1
|
||||
/** @type {Map<string, number>} */
|
||||
// Note: test this when Solid doesn’t want to merge my upcoming PR.
|
||||
/* c8 ignore next */
|
||||
const countsByName = state.passKeys ? new Map() : emptyMap
|
||||
|
||||
while (++index < node.children.length) {
|
||||
const child = node.children[index]
|
||||
/** @type {string | undefined} */
|
||||
let key
|
||||
|
||||
if (state.passKeys) {
|
||||
const name =
|
||||
child.type === 'element'
|
||||
? child.tagName
|
||||
: child.type === 'mdxJsxFlowElement' ||
|
||||
child.type === 'mdxJsxTextElement'
|
||||
? child.name
|
||||
: undefined
|
||||
|
||||
if (name) {
|
||||
const count = countsByName.get(name) || 0
|
||||
key = name + '-' + count
|
||||
countsByName.set(name, count + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const result = one(state, child, key)
|
||||
if (result !== undefined) children.push(result)
|
||||
}
|
||||
|
||||
return children
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a property.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {string} prop
|
||||
* Key.
|
||||
* @param {Array<number | string> | boolean | number | string | null | undefined} value
|
||||
* hast property value.
|
||||
* @returns {Field | undefined}
|
||||
* Field for runtime, optional.
|
||||
*/
|
||||
function createProperty(state, prop, value) {
|
||||
const info = find(state.schema, prop)
|
||||
|
||||
// Ignore nullish and `NaN` values.
|
||||
if (
|
||||
value === null ||
|
||||
value === undefined ||
|
||||
(typeof value === 'number' && Number.isNaN(value))
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// Accept `array`.
|
||||
// Most props are space-separated.
|
||||
value = info.commaSeparated ? commas(value) : spaces(value)
|
||||
}
|
||||
|
||||
// React only accepts `style` as object.
|
||||
if (info.property === 'style') {
|
||||
let styleObject =
|
||||
typeof value === 'object' ? value : parseStyle(state, String(value))
|
||||
|
||||
if (state.stylePropertyNameCase === 'css') {
|
||||
styleObject = transformStylesToCssCasing(styleObject)
|
||||
}
|
||||
|
||||
return ['style', styleObject]
|
||||
}
|
||||
|
||||
return [
|
||||
state.elementAttributeNameCase === 'react' && info.space
|
||||
? hastToReact[info.property] || info.property
|
||||
: info.attribute,
|
||||
value
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a CSS declaration to an object.
|
||||
*
|
||||
* @param {State} state
|
||||
* Info passed around.
|
||||
* @param {string} value
|
||||
* CSS declarations.
|
||||
* @returns {Style}
|
||||
* Properties.
|
||||
* @throws
|
||||
* Throws `VFileMessage` when CSS cannot be parsed.
|
||||
*/
|
||||
function parseStyle(state, value) {
|
||||
try {
|
||||
return styleToJs(value, {reactCompat: true})
|
||||
} catch (error) {
|
||||
if (state.ignoreInvalidStyle) {
|
||||
return {}
|
||||
}
|
||||
|
||||
const cause = /** @type {Error} */ (error)
|
||||
const message = new VFileMessage('Cannot parse `style` attribute', {
|
||||
ancestors: state.ancestors,
|
||||
cause,
|
||||
ruleId: 'style',
|
||||
source: 'hast-util-to-jsx-runtime'
|
||||
})
|
||||
message.file = state.filePath || undefined
|
||||
message.url = docs + '#cannot-parse-style-attribute'
|
||||
|
||||
throw message
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JSX name from a string.
|
||||
*
|
||||
* @param {State} state
|
||||
* To do.
|
||||
* @param {string} name
|
||||
* Name.
|
||||
* @param {boolean} allowExpression
|
||||
* Allow member expressions and identifiers.
|
||||
* @returns {unknown}
|
||||
* To do.
|
||||
*/
|
||||
function findComponentFromName(state, name, allowExpression) {
|
||||
/** @type {Identifier | Literal | MemberExpression} */
|
||||
let result
|
||||
|
||||
if (!allowExpression) {
|
||||
result = {type: 'Literal', value: name}
|
||||
} else if (name.includes('.')) {
|
||||
const identifiers = name.split('.')
|
||||
let index = -1
|
||||
/** @type {Identifier | Literal | MemberExpression | undefined} */
|
||||
let node
|
||||
|
||||
while (++index < identifiers.length) {
|
||||
/** @type {Identifier | Literal} */
|
||||
const prop = isIdentifierName(identifiers[index])
|
||||
? {type: 'Identifier', name: identifiers[index]}
|
||||
: {type: 'Literal', value: identifiers[index]}
|
||||
node = node
|
||||
? {
|
||||
type: 'MemberExpression',
|
||||
object: node,
|
||||
property: prop,
|
||||
computed: Boolean(index && prop.type === 'Literal'),
|
||||
optional: false
|
||||
}
|
||||
: prop
|
||||
}
|
||||
|
||||
assert(node, 'always a result')
|
||||
result = node
|
||||
} else {
|
||||
result =
|
||||
isIdentifierName(name) && !/^[a-z]/.test(name)
|
||||
? {type: 'Identifier', name}
|
||||
: {type: 'Literal', value: name}
|
||||
}
|
||||
|
||||
// Only literals can be passed in `components` currently.
|
||||
// No identifiers / member expressions.
|
||||
if (result.type === 'Literal') {
|
||||
const name = /** @type {string | number} */ (result.value)
|
||||
return own.call(state.components, name) ? state.components[name] : name
|
||||
}
|
||||
|
||||
// Assume component.
|
||||
if (state.evaluater) {
|
||||
return state.evaluater.evaluateExpression(result)
|
||||
}
|
||||
|
||||
crashEstree(state)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {State} state
|
||||
* @param {Position | undefined} [place]
|
||||
* @returns {never}
|
||||
*/
|
||||
function crashEstree(state, place) {
|
||||
const message = new VFileMessage(
|
||||
'Cannot handle MDX estrees without `createEvaluater`',
|
||||
{
|
||||
ancestors: state.ancestors,
|
||||
place,
|
||||
ruleId: 'mdx-estree',
|
||||
source: 'hast-util-to-jsx-runtime'
|
||||
}
|
||||
)
|
||||
message.file = state.filePath || undefined
|
||||
message.url = docs + '#cannot-handle-mdx-estrees-without-createevaluater'
|
||||
|
||||
throw message
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a DOM casing style object to a CSS casing style object.
|
||||
*
|
||||
* @param {Style} domCasing
|
||||
* @returns {Style}
|
||||
*/
|
||||
function transformStylesToCssCasing(domCasing) {
|
||||
/** @type {Style} */
|
||||
const cssCasing = {}
|
||||
/** @type {string} */
|
||||
let from
|
||||
|
||||
for (from in domCasing) {
|
||||
if (own.call(domCasing, from)) {
|
||||
cssCasing[transformStyleToCssCasing(from)] = domCasing[from]
|
||||
}
|
||||
}
|
||||
|
||||
return cssCasing
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a DOM casing style field to a CSS casing style field.
|
||||
*
|
||||
* @param {string} from
|
||||
* @returns {string}
|
||||
*/
|
||||
function transformStyleToCssCasing(from) {
|
||||
let to = from.replace(cap, toDash)
|
||||
// Handle `ms-xxx` -> `-ms-xxx`.
|
||||
if (to.slice(0, 3) === 'ms-') to = '-' + to
|
||||
return to
|
||||
}
|
||||
|
||||
/**
|
||||
* Make `$0` dash cased.
|
||||
*
|
||||
* @param {string} $0
|
||||
* Capitalized ASCII leter.
|
||||
* @returns {string}
|
||||
* Dash and lower letter.
|
||||
*/
|
||||
function toDash($0) {
|
||||
return '-' + $0.toLowerCase()
|
||||
}
|
||||
Generated
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @typedef {import('hast').Nodes} Nodes
|
||||
*/
|
||||
|
||||
// HTML whitespace expression.
|
||||
// See <https://infra.spec.whatwg.org/#ascii-whitespace>.
|
||||
const re = /[ \t\n\f\r]/g
|
||||
|
||||
/**
|
||||
* Check if the given value is *inter-element whitespace*.
|
||||
*
|
||||
* @param {Nodes | string} thing
|
||||
* Thing to check (`Node` or `string`).
|
||||
* @returns {boolean}
|
||||
* Whether the `value` is inter-element whitespace (`boolean`): consisting of
|
||||
* zero or more of space, tab (`\t`), line feed (`\n`), carriage return
|
||||
* (`\r`), or form feed (`\f`); if a node is passed it must be a `Text` node,
|
||||
* whose `value` field is checked.
|
||||
*/
|
||||
export function whitespace(thing) {
|
||||
return typeof thing === 'object'
|
||||
? thing.type === 'text'
|
||||
? empty(thing.value)
|
||||
: false
|
||||
: empty(thing)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function empty(value) {
|
||||
return value.replace(re, '') === ''
|
||||
}
|
||||
Generated
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
// Note: types exposed from `index.d.ts`.
|
||||
import {merge} from './lib/util/merge.js'
|
||||
import {aria} from './lib/aria.js'
|
||||
import {html as htmlBase} from './lib/html.js'
|
||||
import {svg as svgBase} from './lib/svg.js'
|
||||
import {xlink} from './lib/xlink.js'
|
||||
import {xmlns} from './lib/xmlns.js'
|
||||
import {xml} from './lib/xml.js'
|
||||
|
||||
export {hastToReact} from './lib/hast-to-react.js'
|
||||
|
||||
export const html = merge([aria, htmlBase, xlink, xmlns, xml], 'html')
|
||||
|
||||
export {find} from './lib/find.js'
|
||||
export {normalize} from './lib/normalize.js'
|
||||
|
||||
export const svg = merge([aria, svgBase, xlink, xmlns, xml], 'svg')
|
||||
Generated
Vendored
+61
@@ -0,0 +1,61 @@
|
||||
import {create} from './util/create.js'
|
||||
import {booleanish, number, spaceSeparated} from './util/types.js'
|
||||
|
||||
export const aria = create({
|
||||
properties: {
|
||||
ariaActiveDescendant: null,
|
||||
ariaAtomic: booleanish,
|
||||
ariaAutoComplete: null,
|
||||
ariaBusy: booleanish,
|
||||
ariaChecked: booleanish,
|
||||
ariaColCount: number,
|
||||
ariaColIndex: number,
|
||||
ariaColSpan: number,
|
||||
ariaControls: spaceSeparated,
|
||||
ariaCurrent: null,
|
||||
ariaDescribedBy: spaceSeparated,
|
||||
ariaDetails: null,
|
||||
ariaDisabled: booleanish,
|
||||
ariaDropEffect: spaceSeparated,
|
||||
ariaErrorMessage: null,
|
||||
ariaExpanded: booleanish,
|
||||
ariaFlowTo: spaceSeparated,
|
||||
ariaGrabbed: booleanish,
|
||||
ariaHasPopup: null,
|
||||
ariaHidden: booleanish,
|
||||
ariaInvalid: null,
|
||||
ariaKeyShortcuts: null,
|
||||
ariaLabel: null,
|
||||
ariaLabelledBy: spaceSeparated,
|
||||
ariaLevel: number,
|
||||
ariaLive: null,
|
||||
ariaModal: booleanish,
|
||||
ariaMultiLine: booleanish,
|
||||
ariaMultiSelectable: booleanish,
|
||||
ariaOrientation: null,
|
||||
ariaOwns: spaceSeparated,
|
||||
ariaPlaceholder: null,
|
||||
ariaPosInSet: number,
|
||||
ariaPressed: booleanish,
|
||||
ariaReadOnly: booleanish,
|
||||
ariaRelevant: null,
|
||||
ariaRequired: booleanish,
|
||||
ariaRoleDescription: spaceSeparated,
|
||||
ariaRowCount: number,
|
||||
ariaRowIndex: number,
|
||||
ariaRowSpan: number,
|
||||
ariaSelected: booleanish,
|
||||
ariaSetSize: number,
|
||||
ariaSort: null,
|
||||
ariaValueMax: number,
|
||||
ariaValueMin: number,
|
||||
ariaValueNow: number,
|
||||
ariaValueText: null,
|
||||
role: null
|
||||
},
|
||||
transform(_, property) {
|
||||
return property === 'role'
|
||||
? property
|
||||
: 'aria-' + property.slice(4).toLowerCase()
|
||||
}
|
||||
})
|
||||
Generated
Vendored
+97
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @import {Schema} from 'property-information'
|
||||
*/
|
||||
|
||||
import {DefinedInfo} from './util/defined-info.js'
|
||||
import {Info} from './util/info.js'
|
||||
import {normalize} from './normalize.js'
|
||||
|
||||
const cap = /[A-Z]/g
|
||||
const dash = /-[a-z]/g
|
||||
const valid = /^data[-\w.:]+$/i
|
||||
|
||||
/**
|
||||
* Look up info on a property.
|
||||
*
|
||||
* In most cases the given `schema` contains info on the property.
|
||||
* All standard,
|
||||
* most legacy,
|
||||
* and some non-standard properties are supported.
|
||||
* For these cases,
|
||||
* the returned `Info` has hints about the value of the property.
|
||||
*
|
||||
* `name` can also be a valid data attribute or property,
|
||||
* in which case an `Info` object with the correctly cased `attribute` and
|
||||
* `property` is returned.
|
||||
*
|
||||
* `name` can be an unknown attribute,
|
||||
* in which case an `Info` object with `attribute` and `property` set to the
|
||||
* given name is returned.
|
||||
* It is not recommended to provide unsupported legacy or recently specced
|
||||
* properties.
|
||||
*
|
||||
*
|
||||
* @param {Schema} schema
|
||||
* Schema;
|
||||
* either the `html` or `svg` export.
|
||||
* @param {string} value
|
||||
* An attribute-like or property-like name;
|
||||
* it will be passed through `normalize` to hopefully find the correct info.
|
||||
* @returns {Info}
|
||||
* Info.
|
||||
*/
|
||||
export function find(schema, value) {
|
||||
const normal = normalize(value)
|
||||
let property = value
|
||||
let Type = Info
|
||||
|
||||
if (normal in schema.normal) {
|
||||
return schema.property[schema.normal[normal]]
|
||||
}
|
||||
|
||||
if (normal.length > 4 && normal.slice(0, 4) === 'data' && valid.test(value)) {
|
||||
// Attribute or property.
|
||||
if (value.charAt(4) === '-') {
|
||||
// Turn it into a property.
|
||||
const rest = value.slice(5).replace(dash, camelcase)
|
||||
property = 'data' + rest.charAt(0).toUpperCase() + rest.slice(1)
|
||||
} else {
|
||||
// Turn it into an attribute.
|
||||
const rest = value.slice(4)
|
||||
|
||||
if (!dash.test(rest)) {
|
||||
let dashes = rest.replace(cap, kebab)
|
||||
|
||||
if (dashes.charAt(0) !== '-') {
|
||||
dashes = '-' + dashes
|
||||
}
|
||||
|
||||
value = 'data' + dashes
|
||||
}
|
||||
}
|
||||
|
||||
Type = DefinedInfo
|
||||
}
|
||||
|
||||
return new Type(property, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} $0
|
||||
* Value.
|
||||
* @returns {string}
|
||||
* Kebab.
|
||||
*/
|
||||
function kebab($0) {
|
||||
return '-' + $0.toLowerCase()
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} $0
|
||||
* Value.
|
||||
* @returns {string}
|
||||
* Camel.
|
||||
*/
|
||||
function camelcase($0) {
|
||||
return $0.charAt(1).toUpperCase()
|
||||
}
|
||||
Generated
Vendored
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Special cases for React (`Record<string, string>`).
|
||||
*
|
||||
* `hast` is close to `React` but differs in a couple of cases.
|
||||
* To get a React property from a hast property,
|
||||
* check if it is in `hastToReact`.
|
||||
* If it is, use the corresponding value;
|
||||
* otherwise, use the hast property.
|
||||
*
|
||||
* @type {Record<string, string>}
|
||||
*/
|
||||
export const hastToReact = {
|
||||
classId: 'classID',
|
||||
dataType: 'datatype',
|
||||
itemId: 'itemID',
|
||||
strokeDashArray: 'strokeDasharray',
|
||||
strokeDashOffset: 'strokeDashoffset',
|
||||
strokeLineCap: 'strokeLinecap',
|
||||
strokeLineJoin: 'strokeLinejoin',
|
||||
strokeMiterLimit: 'strokeMiterlimit',
|
||||
typeOf: 'typeof',
|
||||
xLinkActuate: 'xlinkActuate',
|
||||
xLinkArcRole: 'xlinkArcrole',
|
||||
xLinkHref: 'xlinkHref',
|
||||
xLinkRole: 'xlinkRole',
|
||||
xLinkShow: 'xlinkShow',
|
||||
xLinkTitle: 'xlinkTitle',
|
||||
xLinkType: 'xlinkType',
|
||||
xmlnsXLink: 'xmlnsXlink'
|
||||
}
|
||||
Generated
Vendored
+332
@@ -0,0 +1,332 @@
|
||||
import {caseInsensitiveTransform} from './util/case-insensitive-transform.js'
|
||||
import {create} from './util/create.js'
|
||||
import {
|
||||
booleanish,
|
||||
boolean,
|
||||
commaSeparated,
|
||||
number,
|
||||
overloadedBoolean,
|
||||
spaceSeparated
|
||||
} from './util/types.js'
|
||||
|
||||
export const html = create({
|
||||
attributes: {
|
||||
acceptcharset: 'accept-charset',
|
||||
classname: 'class',
|
||||
htmlfor: 'for',
|
||||
httpequiv: 'http-equiv'
|
||||
},
|
||||
mustUseProperty: ['checked', 'multiple', 'muted', 'selected'],
|
||||
properties: {
|
||||
// Standard Properties.
|
||||
abbr: null,
|
||||
accept: commaSeparated,
|
||||
acceptCharset: spaceSeparated,
|
||||
accessKey: spaceSeparated,
|
||||
action: null,
|
||||
allow: null,
|
||||
allowFullScreen: boolean,
|
||||
allowPaymentRequest: boolean,
|
||||
allowUserMedia: boolean,
|
||||
alpha: boolean,
|
||||
alt: null,
|
||||
as: null,
|
||||
async: boolean,
|
||||
autoCapitalize: null,
|
||||
autoComplete: spaceSeparated,
|
||||
autoFocus: boolean,
|
||||
autoPlay: boolean,
|
||||
blocking: spaceSeparated,
|
||||
capture: null,
|
||||
charSet: null,
|
||||
checked: boolean,
|
||||
cite: null,
|
||||
className: spaceSeparated,
|
||||
closedBy: null,
|
||||
colorSpace: null,
|
||||
cols: number,
|
||||
colSpan: number,
|
||||
command: null,
|
||||
commandFor: null,
|
||||
content: null,
|
||||
contentEditable: booleanish,
|
||||
controls: boolean,
|
||||
controlsList: spaceSeparated,
|
||||
coords: number | commaSeparated,
|
||||
crossOrigin: null,
|
||||
data: null,
|
||||
dateTime: null,
|
||||
decoding: null,
|
||||
default: boolean,
|
||||
defer: boolean,
|
||||
dir: null,
|
||||
dirName: null,
|
||||
disabled: boolean,
|
||||
download: overloadedBoolean,
|
||||
draggable: booleanish,
|
||||
encType: null,
|
||||
enterKeyHint: null,
|
||||
fetchPriority: null,
|
||||
form: null,
|
||||
formAction: null,
|
||||
formEncType: null,
|
||||
formMethod: null,
|
||||
formNoValidate: boolean,
|
||||
formTarget: null,
|
||||
headers: spaceSeparated,
|
||||
height: number,
|
||||
hidden: overloadedBoolean,
|
||||
high: number,
|
||||
href: null,
|
||||
hrefLang: null,
|
||||
htmlFor: spaceSeparated,
|
||||
httpEquiv: spaceSeparated,
|
||||
id: null,
|
||||
imageSizes: null,
|
||||
imageSrcSet: null,
|
||||
inert: boolean,
|
||||
inputMode: null,
|
||||
integrity: null,
|
||||
is: null,
|
||||
isMap: boolean,
|
||||
itemId: null,
|
||||
itemProp: spaceSeparated,
|
||||
itemRef: spaceSeparated,
|
||||
itemScope: boolean,
|
||||
itemType: spaceSeparated,
|
||||
kind: null,
|
||||
label: null,
|
||||
lang: null,
|
||||
language: null,
|
||||
list: null,
|
||||
loading: null,
|
||||
loop: boolean,
|
||||
low: number,
|
||||
manifest: null,
|
||||
max: null,
|
||||
maxLength: number,
|
||||
media: null,
|
||||
method: null,
|
||||
min: null,
|
||||
minLength: number,
|
||||
multiple: boolean,
|
||||
muted: boolean,
|
||||
name: null,
|
||||
nonce: null,
|
||||
noModule: boolean,
|
||||
noValidate: boolean,
|
||||
onAbort: null,
|
||||
onAfterPrint: null,
|
||||
onAuxClick: null,
|
||||
onBeforeMatch: null,
|
||||
onBeforePrint: null,
|
||||
onBeforeToggle: null,
|
||||
onBeforeUnload: null,
|
||||
onBlur: null,
|
||||
onCancel: null,
|
||||
onCanPlay: null,
|
||||
onCanPlayThrough: null,
|
||||
onChange: null,
|
||||
onClick: null,
|
||||
onClose: null,
|
||||
onContextLost: null,
|
||||
onContextMenu: null,
|
||||
onContextRestored: null,
|
||||
onCopy: null,
|
||||
onCueChange: null,
|
||||
onCut: null,
|
||||
onDblClick: null,
|
||||
onDrag: null,
|
||||
onDragEnd: null,
|
||||
onDragEnter: null,
|
||||
onDragExit: null,
|
||||
onDragLeave: null,
|
||||
onDragOver: null,
|
||||
onDragStart: null,
|
||||
onDrop: null,
|
||||
onDurationChange: null,
|
||||
onEmptied: null,
|
||||
onEnded: null,
|
||||
onError: null,
|
||||
onFocus: null,
|
||||
onFormData: null,
|
||||
onHashChange: null,
|
||||
onInput: null,
|
||||
onInvalid: null,
|
||||
onKeyDown: null,
|
||||
onKeyPress: null,
|
||||
onKeyUp: null,
|
||||
onLanguageChange: null,
|
||||
onLoad: null,
|
||||
onLoadedData: null,
|
||||
onLoadedMetadata: null,
|
||||
onLoadEnd: null,
|
||||
onLoadStart: null,
|
||||
onMessage: null,
|
||||
onMessageError: null,
|
||||
onMouseDown: null,
|
||||
onMouseEnter: null,
|
||||
onMouseLeave: null,
|
||||
onMouseMove: null,
|
||||
onMouseOut: null,
|
||||
onMouseOver: null,
|
||||
onMouseUp: null,
|
||||
onOffline: null,
|
||||
onOnline: null,
|
||||
onPageHide: null,
|
||||
onPageShow: null,
|
||||
onPaste: null,
|
||||
onPause: null,
|
||||
onPlay: null,
|
||||
onPlaying: null,
|
||||
onPopState: null,
|
||||
onProgress: null,
|
||||
onRateChange: null,
|
||||
onRejectionHandled: null,
|
||||
onReset: null,
|
||||
onResize: null,
|
||||
onScroll: null,
|
||||
onScrollEnd: null,
|
||||
onSecurityPolicyViolation: null,
|
||||
onSeeked: null,
|
||||
onSeeking: null,
|
||||
onSelect: null,
|
||||
onSlotChange: null,
|
||||
onStalled: null,
|
||||
onStorage: null,
|
||||
onSubmit: null,
|
||||
onSuspend: null,
|
||||
onTimeUpdate: null,
|
||||
onToggle: null,
|
||||
onUnhandledRejection: null,
|
||||
onUnload: null,
|
||||
onVolumeChange: null,
|
||||
onWaiting: null,
|
||||
onWheel: null,
|
||||
open: boolean,
|
||||
optimum: number,
|
||||
pattern: null,
|
||||
ping: spaceSeparated,
|
||||
placeholder: null,
|
||||
playsInline: boolean,
|
||||
popover: null,
|
||||
popoverTarget: null,
|
||||
popoverTargetAction: null,
|
||||
poster: null,
|
||||
preload: null,
|
||||
readOnly: boolean,
|
||||
referrerPolicy: null,
|
||||
rel: spaceSeparated,
|
||||
required: boolean,
|
||||
reversed: boolean,
|
||||
rows: number,
|
||||
rowSpan: number,
|
||||
sandbox: spaceSeparated,
|
||||
scope: null,
|
||||
scoped: boolean,
|
||||
seamless: boolean,
|
||||
selected: boolean,
|
||||
shadowRootClonable: boolean,
|
||||
shadowRootCustomElementRegistry: boolean,
|
||||
shadowRootDelegatesFocus: boolean,
|
||||
shadowRootMode: null,
|
||||
shadowRootSerializable: boolean,
|
||||
shape: null,
|
||||
size: number,
|
||||
sizes: null,
|
||||
slot: null,
|
||||
span: number,
|
||||
spellCheck: booleanish,
|
||||
src: null,
|
||||
srcDoc: null,
|
||||
srcLang: null,
|
||||
srcSet: null,
|
||||
start: number,
|
||||
step: null,
|
||||
style: null,
|
||||
tabIndex: number,
|
||||
target: null,
|
||||
title: null,
|
||||
translate: null,
|
||||
type: null,
|
||||
typeMustMatch: boolean,
|
||||
useMap: null,
|
||||
value: booleanish,
|
||||
width: number,
|
||||
wrap: null,
|
||||
writingSuggestions: null,
|
||||
|
||||
// Legacy.
|
||||
// See: https://html.spec.whatwg.org/#other-elements,-attributes-and-apis
|
||||
align: null, // Several. Use CSS `text-align` instead,
|
||||
aLink: null, // `<body>`. Use CSS `a:active {color}` instead
|
||||
archive: spaceSeparated, // `<object>`. List of URIs to archives
|
||||
axis: null, // `<td>` and `<th>`. Use `scope` on `<th>`
|
||||
background: null, // `<body>`. Use CSS `background-image` instead
|
||||
bgColor: null, // `<body>` and table elements. Use CSS `background-color` instead
|
||||
border: number, // `<table>`. Use CSS `border-width` instead,
|
||||
borderColor: null, // `<table>`. Use CSS `border-color` instead,
|
||||
bottomMargin: number, // `<body>`
|
||||
cellPadding: null, // `<table>`
|
||||
cellSpacing: null, // `<table>`
|
||||
char: null, // Several table elements. When `align=char`, sets the character to align on
|
||||
charOff: null, // Several table elements. When `char`, offsets the alignment
|
||||
classId: null, // `<object>`
|
||||
clear: null, // `<br>`. Use CSS `clear` instead
|
||||
code: null, // `<object>`
|
||||
codeBase: null, // `<object>`
|
||||
codeType: null, // `<object>`
|
||||
color: null, // `<font>` and `<hr>`. Use CSS instead
|
||||
compact: boolean, // Lists. Use CSS to reduce space between items instead
|
||||
declare: boolean, // `<object>`
|
||||
event: null, // `<script>`
|
||||
face: null, // `<font>`. Use CSS instead
|
||||
frame: null, // `<table>`
|
||||
frameBorder: null, // `<iframe>`. Use CSS `border` instead
|
||||
hSpace: number, // `<img>` and `<object>`
|
||||
leftMargin: number, // `<body>`
|
||||
link: null, // `<body>`. Use CSS `a:link {color: *}` instead
|
||||
longDesc: null, // `<frame>`, `<iframe>`, and `<img>`. Use an `<a>`
|
||||
lowSrc: null, // `<img>`. Use a `<picture>`
|
||||
marginHeight: number, // `<body>`
|
||||
marginWidth: number, // `<body>`
|
||||
noResize: boolean, // `<frame>`
|
||||
noHref: boolean, // `<area>`. Use no href instead of an explicit `nohref`
|
||||
noShade: boolean, // `<hr>`. Use background-color and height instead of borders
|
||||
noWrap: boolean, // `<td>` and `<th>`
|
||||
object: null, // `<applet>`
|
||||
profile: null, // `<head>`
|
||||
prompt: null, // `<isindex>`
|
||||
rev: null, // `<link>`
|
||||
rightMargin: number, // `<body>`
|
||||
rules: null, // `<table>`
|
||||
scheme: null, // `<meta>`
|
||||
scrolling: booleanish, // `<frame>`. Use overflow in the child context
|
||||
standby: null, // `<object>`
|
||||
summary: null, // `<table>`
|
||||
text: null, // `<body>`. Use CSS `color` instead
|
||||
topMargin: number, // `<body>`
|
||||
valueType: null, // `<param>`
|
||||
version: null, // `<html>`. Use a doctype.
|
||||
vAlign: null, // Several. Use CSS `vertical-align` instead
|
||||
vLink: null, // `<body>`. Use CSS `a:visited {color}` instead
|
||||
vSpace: number, // `<img>` and `<object>`
|
||||
|
||||
// Non-standard Properties.
|
||||
allowTransparency: null,
|
||||
autoCorrect: null,
|
||||
autoSave: null,
|
||||
credentialless: boolean,
|
||||
disablePictureInPicture: boolean,
|
||||
disableRemotePlayback: boolean,
|
||||
exportParts: commaSeparated,
|
||||
part: spaceSeparated,
|
||||
prefix: null,
|
||||
property: null,
|
||||
results: number,
|
||||
security: null,
|
||||
unselectable: null
|
||||
},
|
||||
space: 'html',
|
||||
transform: caseInsensitiveTransform
|
||||
})
|
||||
Generated
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Get the cleaned case insensitive form of an attribute or property.
|
||||
*
|
||||
* @param {string} value
|
||||
* An attribute-like or property-like name.
|
||||
* @returns {string}
|
||||
* Value that can be used to look up the properly cased property on a
|
||||
* `Schema`.
|
||||
*/
|
||||
export function normalize(value) {
|
||||
return value.toLowerCase()
|
||||
}
|
||||
Generated
Vendored
+569
@@ -0,0 +1,569 @@
|
||||
import {caseSensitiveTransform} from './util/case-sensitive-transform.js'
|
||||
import {create} from './util/create.js'
|
||||
import {
|
||||
boolean,
|
||||
commaOrSpaceSeparated,
|
||||
commaSeparated,
|
||||
number,
|
||||
spaceSeparated
|
||||
} from './util/types.js'
|
||||
|
||||
export const svg = create({
|
||||
attributes: {
|
||||
accentHeight: 'accent-height',
|
||||
alignmentBaseline: 'alignment-baseline',
|
||||
arabicForm: 'arabic-form',
|
||||
baselineShift: 'baseline-shift',
|
||||
capHeight: 'cap-height',
|
||||
className: 'class',
|
||||
clipPath: 'clip-path',
|
||||
clipRule: 'clip-rule',
|
||||
colorInterpolation: 'color-interpolation',
|
||||
colorInterpolationFilters: 'color-interpolation-filters',
|
||||
colorProfile: 'color-profile',
|
||||
colorRendering: 'color-rendering',
|
||||
crossOrigin: 'crossorigin',
|
||||
dataType: 'datatype',
|
||||
dominantBaseline: 'dominant-baseline',
|
||||
enableBackground: 'enable-background',
|
||||
fillOpacity: 'fill-opacity',
|
||||
fillRule: 'fill-rule',
|
||||
floodColor: 'flood-color',
|
||||
floodOpacity: 'flood-opacity',
|
||||
fontFamily: 'font-family',
|
||||
fontSize: 'font-size',
|
||||
fontSizeAdjust: 'font-size-adjust',
|
||||
fontStretch: 'font-stretch',
|
||||
fontStyle: 'font-style',
|
||||
fontVariant: 'font-variant',
|
||||
fontWeight: 'font-weight',
|
||||
glyphName: 'glyph-name',
|
||||
glyphOrientationHorizontal: 'glyph-orientation-horizontal',
|
||||
glyphOrientationVertical: 'glyph-orientation-vertical',
|
||||
hrefLang: 'hreflang',
|
||||
horizAdvX: 'horiz-adv-x',
|
||||
horizOriginX: 'horiz-origin-x',
|
||||
horizOriginY: 'horiz-origin-y',
|
||||
imageRendering: 'image-rendering',
|
||||
letterSpacing: 'letter-spacing',
|
||||
lightingColor: 'lighting-color',
|
||||
markerEnd: 'marker-end',
|
||||
markerMid: 'marker-mid',
|
||||
markerStart: 'marker-start',
|
||||
maskType: 'mask-type',
|
||||
navDown: 'nav-down',
|
||||
navDownLeft: 'nav-down-left',
|
||||
navDownRight: 'nav-down-right',
|
||||
navLeft: 'nav-left',
|
||||
navNext: 'nav-next',
|
||||
navPrev: 'nav-prev',
|
||||
navRight: 'nav-right',
|
||||
navUp: 'nav-up',
|
||||
navUpLeft: 'nav-up-left',
|
||||
navUpRight: 'nav-up-right',
|
||||
onAbort: 'onabort',
|
||||
onActivate: 'onactivate',
|
||||
onAfterPrint: 'onafterprint',
|
||||
onBeforePrint: 'onbeforeprint',
|
||||
onBegin: 'onbegin',
|
||||
onCancel: 'oncancel',
|
||||
onCanPlay: 'oncanplay',
|
||||
onCanPlayThrough: 'oncanplaythrough',
|
||||
onChange: 'onchange',
|
||||
onClick: 'onclick',
|
||||
onClose: 'onclose',
|
||||
onCopy: 'oncopy',
|
||||
onCueChange: 'oncuechange',
|
||||
onCut: 'oncut',
|
||||
onDblClick: 'ondblclick',
|
||||
onDrag: 'ondrag',
|
||||
onDragEnd: 'ondragend',
|
||||
onDragEnter: 'ondragenter',
|
||||
onDragExit: 'ondragexit',
|
||||
onDragLeave: 'ondragleave',
|
||||
onDragOver: 'ondragover',
|
||||
onDragStart: 'ondragstart',
|
||||
onDrop: 'ondrop',
|
||||
onDurationChange: 'ondurationchange',
|
||||
onEmptied: 'onemptied',
|
||||
onEnd: 'onend',
|
||||
onEnded: 'onended',
|
||||
onError: 'onerror',
|
||||
onFocus: 'onfocus',
|
||||
onFocusIn: 'onfocusin',
|
||||
onFocusOut: 'onfocusout',
|
||||
onHashChange: 'onhashchange',
|
||||
onInput: 'oninput',
|
||||
onInvalid: 'oninvalid',
|
||||
onKeyDown: 'onkeydown',
|
||||
onKeyPress: 'onkeypress',
|
||||
onKeyUp: 'onkeyup',
|
||||
onLoad: 'onload',
|
||||
onLoadedData: 'onloadeddata',
|
||||
onLoadedMetadata: 'onloadedmetadata',
|
||||
onLoadStart: 'onloadstart',
|
||||
onMessage: 'onmessage',
|
||||
onMouseDown: 'onmousedown',
|
||||
onMouseEnter: 'onmouseenter',
|
||||
onMouseLeave: 'onmouseleave',
|
||||
onMouseMove: 'onmousemove',
|
||||
onMouseOut: 'onmouseout',
|
||||
onMouseOver: 'onmouseover',
|
||||
onMouseUp: 'onmouseup',
|
||||
onMouseWheel: 'onmousewheel',
|
||||
onOffline: 'onoffline',
|
||||
onOnline: 'ononline',
|
||||
onPageHide: 'onpagehide',
|
||||
onPageShow: 'onpageshow',
|
||||
onPaste: 'onpaste',
|
||||
onPause: 'onpause',
|
||||
onPlay: 'onplay',
|
||||
onPlaying: 'onplaying',
|
||||
onPopState: 'onpopstate',
|
||||
onProgress: 'onprogress',
|
||||
onRateChange: 'onratechange',
|
||||
onRepeat: 'onrepeat',
|
||||
onReset: 'onreset',
|
||||
onResize: 'onresize',
|
||||
onScroll: 'onscroll',
|
||||
onSeeked: 'onseeked',
|
||||
onSeeking: 'onseeking',
|
||||
onSelect: 'onselect',
|
||||
onShow: 'onshow',
|
||||
onStalled: 'onstalled',
|
||||
onStorage: 'onstorage',
|
||||
onSubmit: 'onsubmit',
|
||||
onSuspend: 'onsuspend',
|
||||
onTimeUpdate: 'ontimeupdate',
|
||||
onToggle: 'ontoggle',
|
||||
onUnload: 'onunload',
|
||||
onVolumeChange: 'onvolumechange',
|
||||
onWaiting: 'onwaiting',
|
||||
onZoom: 'onzoom',
|
||||
overlinePosition: 'overline-position',
|
||||
overlineThickness: 'overline-thickness',
|
||||
paintOrder: 'paint-order',
|
||||
panose1: 'panose-1',
|
||||
pointerEvents: 'pointer-events',
|
||||
referrerPolicy: 'referrerpolicy',
|
||||
renderingIntent: 'rendering-intent',
|
||||
shapeRendering: 'shape-rendering',
|
||||
stopColor: 'stop-color',
|
||||
stopOpacity: 'stop-opacity',
|
||||
strikethroughPosition: 'strikethrough-position',
|
||||
strikethroughThickness: 'strikethrough-thickness',
|
||||
strokeDashArray: 'stroke-dasharray',
|
||||
strokeDashOffset: 'stroke-dashoffset',
|
||||
strokeLineCap: 'stroke-linecap',
|
||||
strokeLineJoin: 'stroke-linejoin',
|
||||
strokeMiterLimit: 'stroke-miterlimit',
|
||||
strokeOpacity: 'stroke-opacity',
|
||||
strokeWidth: 'stroke-width',
|
||||
tabIndex: 'tabindex',
|
||||
textAnchor: 'text-anchor',
|
||||
textDecoration: 'text-decoration',
|
||||
textRendering: 'text-rendering',
|
||||
transformOrigin: 'transform-origin',
|
||||
typeOf: 'typeof',
|
||||
underlinePosition: 'underline-position',
|
||||
underlineThickness: 'underline-thickness',
|
||||
unicodeBidi: 'unicode-bidi',
|
||||
unicodeRange: 'unicode-range',
|
||||
unitsPerEm: 'units-per-em',
|
||||
vAlphabetic: 'v-alphabetic',
|
||||
vHanging: 'v-hanging',
|
||||
vIdeographic: 'v-ideographic',
|
||||
vMathematical: 'v-mathematical',
|
||||
vectorEffect: 'vector-effect',
|
||||
vertAdvY: 'vert-adv-y',
|
||||
vertOriginX: 'vert-origin-x',
|
||||
vertOriginY: 'vert-origin-y',
|
||||
wordSpacing: 'word-spacing',
|
||||
writingMode: 'writing-mode',
|
||||
xHeight: 'x-height',
|
||||
// These were camelcased in Tiny. Now lowercased in SVG 2
|
||||
playbackOrder: 'playbackorder',
|
||||
timelineBegin: 'timelinebegin'
|
||||
},
|
||||
properties: {
|
||||
about: commaOrSpaceSeparated,
|
||||
accentHeight: number,
|
||||
accumulate: null,
|
||||
additive: null,
|
||||
alignmentBaseline: null,
|
||||
alphabetic: number,
|
||||
amplitude: number,
|
||||
arabicForm: null,
|
||||
ascent: number,
|
||||
attributeName: null,
|
||||
attributeType: null,
|
||||
azimuth: number,
|
||||
bandwidth: null,
|
||||
baselineShift: null,
|
||||
baseFrequency: null,
|
||||
baseProfile: null,
|
||||
bbox: null,
|
||||
begin: null,
|
||||
bias: number,
|
||||
by: null,
|
||||
calcMode: null,
|
||||
capHeight: number,
|
||||
className: spaceSeparated,
|
||||
clip: null,
|
||||
clipPath: null,
|
||||
clipPathUnits: null,
|
||||
clipRule: null,
|
||||
color: null,
|
||||
colorInterpolation: null,
|
||||
colorInterpolationFilters: null,
|
||||
colorProfile: null,
|
||||
colorRendering: null,
|
||||
content: null,
|
||||
contentScriptType: null,
|
||||
contentStyleType: null,
|
||||
crossOrigin: null,
|
||||
cursor: null,
|
||||
cx: null,
|
||||
cy: null,
|
||||
d: null,
|
||||
dataType: null,
|
||||
defaultAction: null,
|
||||
descent: number,
|
||||
diffuseConstant: number,
|
||||
direction: null,
|
||||
display: null,
|
||||
dur: null,
|
||||
divisor: number,
|
||||
dominantBaseline: null,
|
||||
download: boolean,
|
||||
dx: null,
|
||||
dy: null,
|
||||
edgeMode: null,
|
||||
editable: null,
|
||||
elevation: number,
|
||||
enableBackground: null,
|
||||
end: null,
|
||||
event: null,
|
||||
exponent: number,
|
||||
externalResourcesRequired: null,
|
||||
fill: null,
|
||||
fillOpacity: number,
|
||||
fillRule: null,
|
||||
filter: null,
|
||||
filterRes: null,
|
||||
filterUnits: null,
|
||||
floodColor: null,
|
||||
floodOpacity: null,
|
||||
focusable: null,
|
||||
focusHighlight: null,
|
||||
fontFamily: null,
|
||||
fontSize: null,
|
||||
fontSizeAdjust: null,
|
||||
fontStretch: null,
|
||||
fontStyle: null,
|
||||
fontVariant: null,
|
||||
fontWeight: null,
|
||||
format: null,
|
||||
fr: null,
|
||||
from: null,
|
||||
fx: null,
|
||||
fy: null,
|
||||
g1: commaSeparated,
|
||||
g2: commaSeparated,
|
||||
glyphName: commaSeparated,
|
||||
glyphOrientationHorizontal: null,
|
||||
glyphOrientationVertical: null,
|
||||
glyphRef: null,
|
||||
gradientTransform: null,
|
||||
gradientUnits: null,
|
||||
handler: null,
|
||||
hanging: number,
|
||||
hatchContentUnits: null,
|
||||
hatchUnits: null,
|
||||
height: null,
|
||||
href: null,
|
||||
hrefLang: null,
|
||||
horizAdvX: number,
|
||||
horizOriginX: number,
|
||||
horizOriginY: number,
|
||||
id: null,
|
||||
ideographic: number,
|
||||
imageRendering: null,
|
||||
initialVisibility: null,
|
||||
in: null,
|
||||
in2: null,
|
||||
intercept: number,
|
||||
k: number,
|
||||
k1: number,
|
||||
k2: number,
|
||||
k3: number,
|
||||
k4: number,
|
||||
kernelMatrix: commaOrSpaceSeparated,
|
||||
kernelUnitLength: null,
|
||||
keyPoints: null, // SEMI_COLON_SEPARATED
|
||||
keySplines: null, // SEMI_COLON_SEPARATED
|
||||
keyTimes: null, // SEMI_COLON_SEPARATED
|
||||
kerning: null,
|
||||
lang: null,
|
||||
lengthAdjust: null,
|
||||
letterSpacing: null,
|
||||
lightingColor: null,
|
||||
limitingConeAngle: number,
|
||||
local: null,
|
||||
markerEnd: null,
|
||||
markerMid: null,
|
||||
markerStart: null,
|
||||
markerHeight: null,
|
||||
markerUnits: null,
|
||||
markerWidth: null,
|
||||
mask: null,
|
||||
maskContentUnits: null,
|
||||
maskType: null,
|
||||
maskUnits: null,
|
||||
mathematical: null,
|
||||
max: null,
|
||||
media: null,
|
||||
mediaCharacterEncoding: null,
|
||||
mediaContentEncodings: null,
|
||||
mediaSize: number,
|
||||
mediaTime: null,
|
||||
method: null,
|
||||
min: null,
|
||||
mode: null,
|
||||
name: null,
|
||||
navDown: null,
|
||||
navDownLeft: null,
|
||||
navDownRight: null,
|
||||
navLeft: null,
|
||||
navNext: null,
|
||||
navPrev: null,
|
||||
navRight: null,
|
||||
navUp: null,
|
||||
navUpLeft: null,
|
||||
navUpRight: null,
|
||||
numOctaves: null,
|
||||
observer: null,
|
||||
offset: null,
|
||||
onAbort: null,
|
||||
onActivate: null,
|
||||
onAfterPrint: null,
|
||||
onBeforePrint: null,
|
||||
onBegin: null,
|
||||
onCancel: null,
|
||||
onCanPlay: null,
|
||||
onCanPlayThrough: null,
|
||||
onChange: null,
|
||||
onClick: null,
|
||||
onClose: null,
|
||||
onCopy: null,
|
||||
onCueChange: null,
|
||||
onCut: null,
|
||||
onDblClick: null,
|
||||
onDrag: null,
|
||||
onDragEnd: null,
|
||||
onDragEnter: null,
|
||||
onDragExit: null,
|
||||
onDragLeave: null,
|
||||
onDragOver: null,
|
||||
onDragStart: null,
|
||||
onDrop: null,
|
||||
onDurationChange: null,
|
||||
onEmptied: null,
|
||||
onEnd: null,
|
||||
onEnded: null,
|
||||
onError: null,
|
||||
onFocus: null,
|
||||
onFocusIn: null,
|
||||
onFocusOut: null,
|
||||
onHashChange: null,
|
||||
onInput: null,
|
||||
onInvalid: null,
|
||||
onKeyDown: null,
|
||||
onKeyPress: null,
|
||||
onKeyUp: null,
|
||||
onLoad: null,
|
||||
onLoadedData: null,
|
||||
onLoadedMetadata: null,
|
||||
onLoadStart: null,
|
||||
onMessage: null,
|
||||
onMouseDown: null,
|
||||
onMouseEnter: null,
|
||||
onMouseLeave: null,
|
||||
onMouseMove: null,
|
||||
onMouseOut: null,
|
||||
onMouseOver: null,
|
||||
onMouseUp: null,
|
||||
onMouseWheel: null,
|
||||
onOffline: null,
|
||||
onOnline: null,
|
||||
onPageHide: null,
|
||||
onPageShow: null,
|
||||
onPaste: null,
|
||||
onPause: null,
|
||||
onPlay: null,
|
||||
onPlaying: null,
|
||||
onPopState: null,
|
||||
onProgress: null,
|
||||
onRateChange: null,
|
||||
onRepeat: null,
|
||||
onReset: null,
|
||||
onResize: null,
|
||||
onScroll: null,
|
||||
onSeeked: null,
|
||||
onSeeking: null,
|
||||
onSelect: null,
|
||||
onShow: null,
|
||||
onStalled: null,
|
||||
onStorage: null,
|
||||
onSubmit: null,
|
||||
onSuspend: null,
|
||||
onTimeUpdate: null,
|
||||
onToggle: null,
|
||||
onUnload: null,
|
||||
onVolumeChange: null,
|
||||
onWaiting: null,
|
||||
onZoom: null,
|
||||
opacity: null,
|
||||
operator: null,
|
||||
order: null,
|
||||
orient: null,
|
||||
orientation: null,
|
||||
origin: null,
|
||||
overflow: null,
|
||||
overlay: null,
|
||||
overlinePosition: number,
|
||||
overlineThickness: number,
|
||||
paintOrder: null,
|
||||
panose1: null,
|
||||
path: null,
|
||||
pathLength: number,
|
||||
patternContentUnits: null,
|
||||
patternTransform: null,
|
||||
patternUnits: null,
|
||||
phase: null,
|
||||
ping: spaceSeparated,
|
||||
pitch: null,
|
||||
playbackOrder: null,
|
||||
pointerEvents: null,
|
||||
points: null,
|
||||
pointsAtX: number,
|
||||
pointsAtY: number,
|
||||
pointsAtZ: number,
|
||||
preserveAlpha: null,
|
||||
preserveAspectRatio: null,
|
||||
primitiveUnits: null,
|
||||
propagate: null,
|
||||
property: commaOrSpaceSeparated,
|
||||
r: null,
|
||||
radius: null,
|
||||
referrerPolicy: null,
|
||||
refX: null,
|
||||
refY: null,
|
||||
rel: commaOrSpaceSeparated,
|
||||
rev: commaOrSpaceSeparated,
|
||||
renderingIntent: null,
|
||||
repeatCount: null,
|
||||
repeatDur: null,
|
||||
requiredExtensions: commaOrSpaceSeparated,
|
||||
requiredFeatures: commaOrSpaceSeparated,
|
||||
requiredFonts: commaOrSpaceSeparated,
|
||||
requiredFormats: commaOrSpaceSeparated,
|
||||
resource: null,
|
||||
restart: null,
|
||||
result: null,
|
||||
rotate: null,
|
||||
rx: null,
|
||||
ry: null,
|
||||
scale: null,
|
||||
seed: null,
|
||||
shapeRendering: null,
|
||||
side: null,
|
||||
slope: null,
|
||||
snapshotTime: null,
|
||||
specularConstant: number,
|
||||
specularExponent: number,
|
||||
spreadMethod: null,
|
||||
spacing: null,
|
||||
startOffset: null,
|
||||
stdDeviation: null,
|
||||
stemh: null,
|
||||
stemv: null,
|
||||
stitchTiles: null,
|
||||
stopColor: null,
|
||||
stopOpacity: null,
|
||||
strikethroughPosition: number,
|
||||
strikethroughThickness: number,
|
||||
string: null,
|
||||
stroke: null,
|
||||
strokeDashArray: commaOrSpaceSeparated,
|
||||
strokeDashOffset: null,
|
||||
strokeLineCap: null,
|
||||
strokeLineJoin: null,
|
||||
strokeMiterLimit: number,
|
||||
strokeOpacity: number,
|
||||
strokeWidth: null,
|
||||
style: null,
|
||||
surfaceScale: number,
|
||||
syncBehavior: null,
|
||||
syncBehaviorDefault: null,
|
||||
syncMaster: null,
|
||||
syncTolerance: null,
|
||||
syncToleranceDefault: null,
|
||||
systemLanguage: commaOrSpaceSeparated,
|
||||
tabIndex: number,
|
||||
tableValues: null,
|
||||
target: null,
|
||||
targetX: number,
|
||||
targetY: number,
|
||||
textAnchor: null,
|
||||
textDecoration: null,
|
||||
textRendering: null,
|
||||
textLength: null,
|
||||
timelineBegin: null,
|
||||
title: null,
|
||||
transformBehavior: null,
|
||||
type: null,
|
||||
typeOf: commaOrSpaceSeparated,
|
||||
to: null,
|
||||
transform: null,
|
||||
transformOrigin: null,
|
||||
u1: null,
|
||||
u2: null,
|
||||
underlinePosition: number,
|
||||
underlineThickness: number,
|
||||
unicode: null,
|
||||
unicodeBidi: null,
|
||||
unicodeRange: null,
|
||||
unitsPerEm: number,
|
||||
values: null,
|
||||
vAlphabetic: number,
|
||||
vMathematical: number,
|
||||
vectorEffect: null,
|
||||
vHanging: number,
|
||||
vIdeographic: number,
|
||||
version: null,
|
||||
vertAdvY: number,
|
||||
vertOriginX: number,
|
||||
vertOriginY: number,
|
||||
viewBox: null,
|
||||
viewTarget: null,
|
||||
visibility: null,
|
||||
width: null,
|
||||
widths: null,
|
||||
wordSpacing: null,
|
||||
writingMode: null,
|
||||
x: null,
|
||||
x1: null,
|
||||
x2: null,
|
||||
xChannelSelector: null,
|
||||
xHeight: number,
|
||||
y: null,
|
||||
y1: null,
|
||||
y2: null,
|
||||
yChannelSelector: null,
|
||||
z: null,
|
||||
zoomAndPan: null
|
||||
},
|
||||
space: 'svg',
|
||||
transform: caseSensitiveTransform
|
||||
})
|
||||
Generated
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
import {caseSensitiveTransform} from './case-sensitive-transform.js'
|
||||
|
||||
/**
|
||||
* @param {Record<string, string>} attributes
|
||||
* Attributes.
|
||||
* @param {string} property
|
||||
* Property.
|
||||
* @returns {string}
|
||||
* Transformed property.
|
||||
*/
|
||||
export function caseInsensitiveTransform(attributes, property) {
|
||||
return caseSensitiveTransform(attributes, property.toLowerCase())
|
||||
}
|
||||
Generated
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @param {Record<string, string>} attributes
|
||||
* Attributes.
|
||||
* @param {string} attribute
|
||||
* Attribute.
|
||||
* @returns {string}
|
||||
* Transformed attribute.
|
||||
*/
|
||||
export function caseSensitiveTransform(attributes, attribute) {
|
||||
return attribute in attributes ? attributes[attribute] : attribute
|
||||
}
|
||||
Generated
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @import {Info, Space} from 'property-information'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Definition
|
||||
* Definition of a schema.
|
||||
* @property {Record<string, string> | undefined} [attributes]
|
||||
* Normalzed names to special attribute case.
|
||||
* @property {ReadonlyArray<string> | undefined} [mustUseProperty]
|
||||
* Normalized names that must be set as properties.
|
||||
* @property {Record<string, number | null>} properties
|
||||
* Property names to their types.
|
||||
* @property {Space | undefined} [space]
|
||||
* Space.
|
||||
* @property {Transform} transform
|
||||
* Transform a property name.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback Transform
|
||||
* Transform.
|
||||
* @param {Record<string, string>} attributes
|
||||
* Attributes.
|
||||
* @param {string} property
|
||||
* Property.
|
||||
* @returns {string}
|
||||
* Attribute.
|
||||
*/
|
||||
|
||||
import {normalize} from '../normalize.js'
|
||||
import {DefinedInfo} from './defined-info.js'
|
||||
import {Schema} from './schema.js'
|
||||
|
||||
/**
|
||||
* @param {Definition} definition
|
||||
* Definition.
|
||||
* @returns {Schema}
|
||||
* Schema.
|
||||
*/
|
||||
export function create(definition) {
|
||||
/** @type {Record<string, Info>} */
|
||||
const properties = {}
|
||||
/** @type {Record<string, string>} */
|
||||
const normals = {}
|
||||
|
||||
for (const [property, value] of Object.entries(definition.properties)) {
|
||||
const info = new DefinedInfo(
|
||||
property,
|
||||
definition.transform(definition.attributes || {}, property),
|
||||
value,
|
||||
definition.space
|
||||
)
|
||||
|
||||
if (
|
||||
definition.mustUseProperty &&
|
||||
definition.mustUseProperty.includes(property)
|
||||
) {
|
||||
info.mustUseProperty = true
|
||||
}
|
||||
|
||||
properties[property] = info
|
||||
|
||||
normals[normalize(property)] = property
|
||||
normals[normalize(info.attribute)] = property
|
||||
}
|
||||
|
||||
return new Schema(properties, normals, definition.space)
|
||||
}
|
||||
Generated
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @import {Space} from 'property-information'
|
||||
*/
|
||||
|
||||
import {Info} from './info.js'
|
||||
import * as types from './types.js'
|
||||
|
||||
const checks = /** @type {ReadonlyArray<keyof typeof types>} */ (
|
||||
Object.keys(types)
|
||||
)
|
||||
|
||||
export class DefinedInfo extends Info {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {string} property
|
||||
* Property.
|
||||
* @param {string} attribute
|
||||
* Attribute.
|
||||
* @param {number | null | undefined} [mask]
|
||||
* Mask.
|
||||
* @param {Space | undefined} [space]
|
||||
* Space.
|
||||
* @returns
|
||||
* Info.
|
||||
*/
|
||||
constructor(property, attribute, mask, space) {
|
||||
let index = -1
|
||||
|
||||
super(property, attribute)
|
||||
|
||||
mark(this, 'space', space)
|
||||
|
||||
if (typeof mask === 'number') {
|
||||
while (++index < checks.length) {
|
||||
const check = checks[index]
|
||||
mark(this, checks[index], (mask & types[check]) === types[check])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DefinedInfo.prototype.defined = true
|
||||
|
||||
/**
|
||||
* @template {keyof DefinedInfo} Key
|
||||
* Key type.
|
||||
* @param {DefinedInfo} values
|
||||
* Info.
|
||||
* @param {Key} key
|
||||
* Key.
|
||||
* @param {DefinedInfo[Key]} value
|
||||
* Value.
|
||||
* @returns {undefined}
|
||||
* Nothing.
|
||||
*/
|
||||
function mark(values, key, value) {
|
||||
if (value) {
|
||||
values[key] = value
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @import {Info as InfoType} from 'property-information'
|
||||
*/
|
||||
|
||||
/** @type {InfoType} */
|
||||
export class Info {
|
||||
/**
|
||||
* @param {string} property
|
||||
* Property.
|
||||
* @param {string} attribute
|
||||
* Attribute.
|
||||
* @returns
|
||||
* Info.
|
||||
*/
|
||||
constructor(property, attribute) {
|
||||
this.attribute = attribute
|
||||
this.property = property
|
||||
}
|
||||
}
|
||||
|
||||
Info.prototype.attribute = ''
|
||||
Info.prototype.booleanish = false
|
||||
Info.prototype.boolean = false
|
||||
Info.prototype.commaOrSpaceSeparated = false
|
||||
Info.prototype.commaSeparated = false
|
||||
Info.prototype.defined = false
|
||||
Info.prototype.mustUseProperty = false
|
||||
Info.prototype.number = false
|
||||
Info.prototype.overloadedBoolean = false
|
||||
Info.prototype.property = ''
|
||||
Info.prototype.spaceSeparated = false
|
||||
Info.prototype.space = undefined
|
||||
Generated
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @import {Info, Space} from 'property-information'
|
||||
*/
|
||||
|
||||
import {Schema} from './schema.js'
|
||||
|
||||
/**
|
||||
* @param {ReadonlyArray<Schema>} definitions
|
||||
* Definitions.
|
||||
* @param {Space | undefined} [space]
|
||||
* Space.
|
||||
* @returns {Schema}
|
||||
* Schema.
|
||||
*/
|
||||
export function merge(definitions, space) {
|
||||
/** @type {Record<string, Info>} */
|
||||
const property = {}
|
||||
/** @type {Record<string, string>} */
|
||||
const normal = {}
|
||||
|
||||
for (const definition of definitions) {
|
||||
Object.assign(property, definition.property)
|
||||
Object.assign(normal, definition.normal)
|
||||
}
|
||||
|
||||
return new Schema(property, normal, space)
|
||||
}
|
||||
Generated
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @import {Schema as SchemaType, Space} from 'property-information'
|
||||
*/
|
||||
|
||||
/** @type {SchemaType} */
|
||||
export class Schema {
|
||||
/**
|
||||
* @param {SchemaType['property']} property
|
||||
* Property.
|
||||
* @param {SchemaType['normal']} normal
|
||||
* Normal.
|
||||
* @param {Space | undefined} [space]
|
||||
* Space.
|
||||
* @returns
|
||||
* Schema.
|
||||
*/
|
||||
constructor(property, normal, space) {
|
||||
this.normal = normal
|
||||
this.property = property
|
||||
|
||||
if (space) {
|
||||
this.space = space
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Schema.prototype.normal = {}
|
||||
Schema.prototype.property = {}
|
||||
Schema.prototype.space = undefined
|
||||
Generated
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
let powers = 0
|
||||
|
||||
export const boolean = increment()
|
||||
export const booleanish = increment()
|
||||
export const overloadedBoolean = increment()
|
||||
export const number = increment()
|
||||
export const spaceSeparated = increment()
|
||||
export const commaSeparated = increment()
|
||||
export const commaOrSpaceSeparated = increment()
|
||||
|
||||
function increment() {
|
||||
return 2 ** ++powers
|
||||
}
|
||||
Generated
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
import {create} from './util/create.js'
|
||||
|
||||
export const xlink = create({
|
||||
properties: {
|
||||
xLinkActuate: null,
|
||||
xLinkArcRole: null,
|
||||
xLinkHref: null,
|
||||
xLinkRole: null,
|
||||
xLinkShow: null,
|
||||
xLinkTitle: null,
|
||||
xLinkType: null
|
||||
},
|
||||
space: 'xlink',
|
||||
transform(_, property) {
|
||||
return 'xlink:' + property.slice(5).toLowerCase()
|
||||
}
|
||||
})
|
||||
Generated
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
import {create} from './util/create.js'
|
||||
|
||||
export const xml = create({
|
||||
properties: {xmlBase: null, xmlLang: null, xmlSpace: null},
|
||||
space: 'xml',
|
||||
transform(_, property) {
|
||||
return 'xml:' + property.slice(3).toLowerCase()
|
||||
}
|
||||
})
|
||||
Generated
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
import {create} from './util/create.js'
|
||||
import {caseInsensitiveTransform} from './util/case-insensitive-transform.js'
|
||||
|
||||
export const xmlns = create({
|
||||
attributes: {xmlnsxlink: 'xmlns:xlink'},
|
||||
properties: {xmlnsXLink: null, xmlns: null},
|
||||
space: 'xmlns',
|
||||
transform: caseInsensitiveTransform
|
||||
})
|
||||
Generated
Vendored
+95
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* @typedef {import('unist').Node} Node
|
||||
* @typedef {import('unist').Point} Point
|
||||
* @typedef {import('unist').Position} Position
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef NodeLike
|
||||
* @property {string} type
|
||||
* @property {PositionLike | null | undefined} [position]
|
||||
*
|
||||
* @typedef PositionLike
|
||||
* @property {PointLike | null | undefined} [start]
|
||||
* @property {PointLike | null | undefined} [end]
|
||||
*
|
||||
* @typedef PointLike
|
||||
* @property {number | null | undefined} [line]
|
||||
* @property {number | null | undefined} [column]
|
||||
* @property {number | null | undefined} [offset]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the ending point of `node`.
|
||||
*
|
||||
* @param node
|
||||
* Node.
|
||||
* @returns
|
||||
* Point.
|
||||
*/
|
||||
export const pointEnd = point('end')
|
||||
|
||||
/**
|
||||
* Get the starting point of `node`.
|
||||
*
|
||||
* @param node
|
||||
* Node.
|
||||
* @returns
|
||||
* Point.
|
||||
*/
|
||||
export const pointStart = point('start')
|
||||
|
||||
/**
|
||||
* Get the positional info of `node`.
|
||||
*
|
||||
* @param {'end' | 'start'} type
|
||||
* Side.
|
||||
* @returns
|
||||
* Getter.
|
||||
*/
|
||||
function point(type) {
|
||||
return point
|
||||
|
||||
/**
|
||||
* Get the point info of `node` at a bound side.
|
||||
*
|
||||
* @param {Node | NodeLike | null | undefined} [node]
|
||||
* @returns {Point | undefined}
|
||||
*/
|
||||
function point(node) {
|
||||
const point = (node && node.position && node.position[type]) || {}
|
||||
|
||||
if (
|
||||
typeof point.line === 'number' &&
|
||||
point.line > 0 &&
|
||||
typeof point.column === 'number' &&
|
||||
point.column > 0
|
||||
) {
|
||||
return {
|
||||
line: point.line,
|
||||
column: point.column,
|
||||
offset:
|
||||
typeof point.offset === 'number' && point.offset > -1
|
||||
? point.offset
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the positional info of `node`.
|
||||
*
|
||||
* @param {Node | NodeLike | null | undefined} [node]
|
||||
* Node.
|
||||
* @returns {Position | undefined}
|
||||
* Position.
|
||||
*/
|
||||
export function position(node) {
|
||||
const start = pointStart(node)
|
||||
const end = pointEnd(node)
|
||||
|
||||
if (start && end) {
|
||||
return {start, end}
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+84
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @typedef {import('unist').Node} Node
|
||||
* @typedef {import('unist').Point} Point
|
||||
* @typedef {import('unist').Position} Position
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef NodeLike
|
||||
* @property {string} type
|
||||
* @property {PositionLike | null | undefined} [position]
|
||||
*
|
||||
* @typedef PointLike
|
||||
* @property {number | null | undefined} [line]
|
||||
* @property {number | null | undefined} [column]
|
||||
* @property {number | null | undefined} [offset]
|
||||
*
|
||||
* @typedef PositionLike
|
||||
* @property {PointLike | null | undefined} [start]
|
||||
* @property {PointLike | null | undefined} [end]
|
||||
*/
|
||||
|
||||
/**
|
||||
* Serialize the positional info of a point, position (start and end points),
|
||||
* or node.
|
||||
*
|
||||
* @param {Node | NodeLike | Point | PointLike | Position | PositionLike | null | undefined} [value]
|
||||
* Node, position, or point.
|
||||
* @returns {string}
|
||||
* Pretty printed positional info of a node (`string`).
|
||||
*
|
||||
* In the format of a range `ls:cs-le:ce` (when given `node` or `position`)
|
||||
* or a point `l:c` (when given `point`), where `l` stands for line, `c` for
|
||||
* column, `s` for `start`, and `e` for end.
|
||||
* An empty string (`''`) is returned if the given value is neither `node`,
|
||||
* `position`, nor `point`.
|
||||
*/
|
||||
export function stringifyPosition(value) {
|
||||
// Nothing.
|
||||
if (!value || typeof value !== 'object') {
|
||||
return ''
|
||||
}
|
||||
|
||||
// Node.
|
||||
if ('position' in value || 'type' in value) {
|
||||
return position(value.position)
|
||||
}
|
||||
|
||||
// Position.
|
||||
if ('start' in value || 'end' in value) {
|
||||
return position(value)
|
||||
}
|
||||
|
||||
// Point.
|
||||
if ('line' in value || 'column' in value) {
|
||||
return point(value)
|
||||
}
|
||||
|
||||
// ?
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Point | PointLike | null | undefined} point
|
||||
* @returns {string}
|
||||
*/
|
||||
function point(point) {
|
||||
return index(point && point.line) + ':' + index(point && point.column)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Position | PositionLike | null | undefined} pos
|
||||
* @returns {string}
|
||||
*/
|
||||
function position(pos) {
|
||||
return point(pos && pos.start) + '-' + point(pos && pos.end)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number | null | undefined} value
|
||||
* @returns {number}
|
||||
*/
|
||||
function index(value) {
|
||||
return value && typeof value === 'number' ? value : 1
|
||||
}
|
||||
Generated
Vendored
+314
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* @import {Node, Point, Position} from 'unist'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object & {type: string, position?: Position | undefined}} NodeLike
|
||||
*
|
||||
* @typedef Options
|
||||
* Configuration.
|
||||
* @property {Array<Node> | null | undefined} [ancestors]
|
||||
* Stack of (inclusive) ancestor nodes surrounding the message (optional).
|
||||
* @property {Error | null | undefined} [cause]
|
||||
* Original error cause of the message (optional).
|
||||
* @property {Point | Position | null | undefined} [place]
|
||||
* Place of message (optional).
|
||||
* @property {string | null | undefined} [ruleId]
|
||||
* Category of message (optional, example: `'my-rule'`).
|
||||
* @property {string | null | undefined} [source]
|
||||
* Namespace of who sent the message (optional, example: `'my-package'`).
|
||||
*/
|
||||
|
||||
import {stringifyPosition} from 'unist-util-stringify-position'
|
||||
|
||||
/**
|
||||
* Message.
|
||||
*/
|
||||
export class VFileMessage extends Error {
|
||||
/**
|
||||
* Create a message for `reason`.
|
||||
*
|
||||
* > 🪦 **Note**: also has obsolete signatures.
|
||||
*
|
||||
* @overload
|
||||
* @param {string} reason
|
||||
* @param {Options | null | undefined} [options]
|
||||
* @returns
|
||||
*
|
||||
* @overload
|
||||
* @param {string} reason
|
||||
* @param {Node | NodeLike | null | undefined} parent
|
||||
* @param {string | null | undefined} [origin]
|
||||
* @returns
|
||||
*
|
||||
* @overload
|
||||
* @param {string} reason
|
||||
* @param {Point | Position | null | undefined} place
|
||||
* @param {string | null | undefined} [origin]
|
||||
* @returns
|
||||
*
|
||||
* @overload
|
||||
* @param {string} reason
|
||||
* @param {string | null | undefined} [origin]
|
||||
* @returns
|
||||
*
|
||||
* @overload
|
||||
* @param {Error | VFileMessage} cause
|
||||
* @param {Node | NodeLike | null | undefined} parent
|
||||
* @param {string | null | undefined} [origin]
|
||||
* @returns
|
||||
*
|
||||
* @overload
|
||||
* @param {Error | VFileMessage} cause
|
||||
* @param {Point | Position | null | undefined} place
|
||||
* @param {string | null | undefined} [origin]
|
||||
* @returns
|
||||
*
|
||||
* @overload
|
||||
* @param {Error | VFileMessage} cause
|
||||
* @param {string | null | undefined} [origin]
|
||||
* @returns
|
||||
*
|
||||
* @param {Error | VFileMessage | string} causeOrReason
|
||||
* Reason for message, should use markdown.
|
||||
* @param {Node | NodeLike | Options | Point | Position | string | null | undefined} [optionsOrParentOrPlace]
|
||||
* Configuration (optional).
|
||||
* @param {string | null | undefined} [origin]
|
||||
* Place in code where the message originates (example:
|
||||
* `'my-package:my-rule'` or `'my-rule'`).
|
||||
* @returns
|
||||
* Instance of `VFileMessage`.
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
constructor(causeOrReason, optionsOrParentOrPlace, origin) {
|
||||
super()
|
||||
|
||||
if (typeof optionsOrParentOrPlace === 'string') {
|
||||
origin = optionsOrParentOrPlace
|
||||
optionsOrParentOrPlace = undefined
|
||||
}
|
||||
|
||||
/** @type {string} */
|
||||
let reason = ''
|
||||
/** @type {Options} */
|
||||
let options = {}
|
||||
let legacyCause = false
|
||||
|
||||
if (optionsOrParentOrPlace) {
|
||||
// Point.
|
||||
if (
|
||||
'line' in optionsOrParentOrPlace &&
|
||||
'column' in optionsOrParentOrPlace
|
||||
) {
|
||||
options = {place: optionsOrParentOrPlace}
|
||||
}
|
||||
// Position.
|
||||
else if (
|
||||
'start' in optionsOrParentOrPlace &&
|
||||
'end' in optionsOrParentOrPlace
|
||||
) {
|
||||
options = {place: optionsOrParentOrPlace}
|
||||
}
|
||||
// Node.
|
||||
else if ('type' in optionsOrParentOrPlace) {
|
||||
options = {
|
||||
ancestors: [optionsOrParentOrPlace],
|
||||
place: optionsOrParentOrPlace.position
|
||||
}
|
||||
}
|
||||
// Options.
|
||||
else {
|
||||
options = {...optionsOrParentOrPlace}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof causeOrReason === 'string') {
|
||||
reason = causeOrReason
|
||||
}
|
||||
// Error.
|
||||
else if (!options.cause && causeOrReason) {
|
||||
legacyCause = true
|
||||
reason = causeOrReason.message
|
||||
options.cause = causeOrReason
|
||||
}
|
||||
|
||||
if (!options.ruleId && !options.source && typeof origin === 'string') {
|
||||
const index = origin.indexOf(':')
|
||||
|
||||
if (index === -1) {
|
||||
options.ruleId = origin
|
||||
} else {
|
||||
options.source = origin.slice(0, index)
|
||||
options.ruleId = origin.slice(index + 1)
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.place && options.ancestors && options.ancestors) {
|
||||
const parent = options.ancestors[options.ancestors.length - 1]
|
||||
|
||||
if (parent) {
|
||||
options.place = parent.position
|
||||
}
|
||||
}
|
||||
|
||||
const start =
|
||||
options.place && 'start' in options.place
|
||||
? options.place.start
|
||||
: options.place
|
||||
|
||||
/**
|
||||
* Stack of ancestor nodes surrounding the message.
|
||||
*
|
||||
* @type {Array<Node> | undefined}
|
||||
*/
|
||||
this.ancestors = options.ancestors || undefined
|
||||
|
||||
/**
|
||||
* Original error cause of the message.
|
||||
*
|
||||
* @type {Error | undefined}
|
||||
*/
|
||||
this.cause = options.cause || undefined
|
||||
|
||||
/**
|
||||
* Starting column of message.
|
||||
*
|
||||
* @type {number | undefined}
|
||||
*/
|
||||
this.column = start ? start.column : undefined
|
||||
|
||||
/**
|
||||
* State of problem.
|
||||
*
|
||||
* * `true` — error, file not usable
|
||||
* * `false` — warning, change may be needed
|
||||
* * `undefined` — change likely not needed
|
||||
*
|
||||
* @type {boolean | null | undefined}
|
||||
*/
|
||||
this.fatal = undefined
|
||||
|
||||
/**
|
||||
* Path of a file (used throughout the `VFile` ecosystem).
|
||||
*
|
||||
* @type {string | undefined}
|
||||
*/
|
||||
this.file = ''
|
||||
|
||||
// Field from `Error`.
|
||||
/**
|
||||
* Reason for message.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.message = reason
|
||||
|
||||
/**
|
||||
* Starting line of error.
|
||||
*
|
||||
* @type {number | undefined}
|
||||
*/
|
||||
this.line = start ? start.line : undefined
|
||||
|
||||
// Field from `Error`.
|
||||
/**
|
||||
* Serialized positional info of message.
|
||||
*
|
||||
* On normal errors, this would be something like `ParseError`, buit in
|
||||
* `VFile` messages we use this space to show where an error happened.
|
||||
*/
|
||||
this.name = stringifyPosition(options.place) || '1:1'
|
||||
|
||||
/**
|
||||
* Place of message.
|
||||
*
|
||||
* @type {Point | Position | undefined}
|
||||
*/
|
||||
this.place = options.place || undefined
|
||||
|
||||
/**
|
||||
* Reason for message, should use markdown.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.reason = this.message
|
||||
|
||||
/**
|
||||
* Category of message (example: `'my-rule'`).
|
||||
*
|
||||
* @type {string | undefined}
|
||||
*/
|
||||
this.ruleId = options.ruleId || undefined
|
||||
|
||||
/**
|
||||
* Namespace of message (example: `'my-package'`).
|
||||
*
|
||||
* @type {string | undefined}
|
||||
*/
|
||||
this.source = options.source || undefined
|
||||
|
||||
// Field from `Error`.
|
||||
/**
|
||||
* Stack of message.
|
||||
*
|
||||
* This is used by normal errors to show where something happened in
|
||||
* programming code, irrelevant for `VFile` messages,
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.stack =
|
||||
legacyCause && options.cause && typeof options.cause.stack === 'string'
|
||||
? options.cause.stack
|
||||
: ''
|
||||
|
||||
// The following fields are “well known”.
|
||||
// Not standard.
|
||||
// Feel free to add other non-standard fields to your messages.
|
||||
|
||||
/**
|
||||
* Specify the source value that’s being reported, which is deemed
|
||||
* incorrect.
|
||||
*
|
||||
* @type {string | undefined}
|
||||
*/
|
||||
this.actual = undefined
|
||||
|
||||
/**
|
||||
* Suggest acceptable values that can be used instead of `actual`.
|
||||
*
|
||||
* @type {Array<string> | undefined}
|
||||
*/
|
||||
this.expected = undefined
|
||||
|
||||
/**
|
||||
* Long form description of the message (you should use markdown).
|
||||
*
|
||||
* @type {string | undefined}
|
||||
*/
|
||||
this.note = undefined
|
||||
|
||||
/**
|
||||
* Link to docs for the message.
|
||||
*
|
||||
* > 👉 **Note**: this must be an absolute URL that can be passed as `x`
|
||||
* > to `new URL(x)`.
|
||||
*
|
||||
* @type {string | undefined}
|
||||
*/
|
||||
this.url = undefined
|
||||
}
|
||||
}
|
||||
|
||||
VFileMessage.prototype.file = ''
|
||||
VFileMessage.prototype.name = ''
|
||||
VFileMessage.prototype.reason = ''
|
||||
VFileMessage.prototype.message = ''
|
||||
VFileMessage.prototype.stack = ''
|
||||
VFileMessage.prototype.column = undefined
|
||||
VFileMessage.prototype.line = undefined
|
||||
VFileMessage.prototype.ancestors = undefined
|
||||
VFileMessage.prototype.cause = undefined
|
||||
VFileMessage.prototype.fatal = undefined
|
||||
VFileMessage.prototype.place = undefined
|
||||
VFileMessage.prototype.ruleId = undefined
|
||||
VFileMessage.prototype.source = undefined
|
||||
Reference in New Issue
Block a user