Files
sgauthier 6e64e138e2
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s
planning
2024-10-14 09:15:30 +02:00

199 lines
5.0 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict'
var xtend = require('xtend')
var svg = require('property-information/svg')
var find = require('property-information/find')
var spaces = require('space-separated-tokens')
var commas = require('comma-separated-tokens')
var entities = require('stringify-entities')
var ccount = require('ccount')
var all = require('./all')
var constants = require('./constants')
module.exports = serializeElement
function serializeElement(ctx, node, index, parent) {
var schema = ctx.schema
var omit = schema.space === 'svg' ? false : ctx.omit
var parts = []
var selfClosing =
schema.space === 'svg'
? ctx.closeEmpty
: ctx.voids.indexOf(node.tagName.toLowerCase()) > -1
var attrs
var content
var last
if (schema.space === 'html' && node.tagName === 'svg') {
ctx.schema = svg
}
attrs = serializeAttributes(ctx, node.properties)
content = all(
ctx,
schema.space === 'html' && node.tagName === 'template' ? node.content : node
)
ctx.schema = schema
// If the node is categorised as void, but it has children, remove the
// categorisation.
// This enables for example `menuitem`s, which are void in W3C HTML but not
// void in WHATWG HTML, to be stringified properly.
if (content) selfClosing = false
if (attrs || !omit || !omit.opening(node, index, parent)) {
parts.push('<', node.tagName, attrs ? ' ' + attrs : '')
if (selfClosing && (schema.space === 'svg' || ctx.close)) {
last = attrs.charAt(attrs.length - 1)
if (
!ctx.tightClose ||
last === '/' ||
(schema.space === 'svg' && last && last !== '"' && last !== "'")
) {
parts.push(' ')
}
parts.push('/')
}
parts.push('>')
}
parts.push(content)
if (!selfClosing && (!omit || !omit.closing(node, index, parent))) {
parts.push('</' + node.tagName + '>')
}
return parts.join('')
}
function serializeAttributes(ctx, props) {
var values = []
var index = -1
var key
var value
var last
for (key in props) {
if (props[key] != null) {
value = serializeAttribute(ctx, key, props[key])
if (value) values.push(value)
}
}
while (++index < values.length) {
last = ctx.tight ? values[index].charAt(values[index].length - 1) : null
// In tight mode, dont add a space after quoted attributes.
if (index !== values.length - 1 && last !== '"' && last !== "'") {
values[index] += ' '
}
}
return values.join('')
}
function serializeAttribute(ctx, key, value) {
var info = find(ctx.schema, key)
var quote = ctx.quote
var result
var name
if (info.overloadedBoolean && (value === info.attribute || value === '')) {
value = true
} else if (
info.boolean ||
(info.overloadedBoolean && typeof value !== 'string')
) {
value = Boolean(value)
}
if (
value == null ||
value === false ||
(typeof value === 'number' && value !== value)
) {
return ''
}
name = entities(
info.attribute,
xtend(ctx.entities, {
// Always encode without parse errors in non-HTML.
subset:
constants.name[ctx.schema.space === 'html' ? ctx.valid : 1][ctx.safe]
})
)
// No value.
// There is currently only one boolean property in SVG: `[download]` on
// `<a>`.
// This property does not seem to work in browsers (FF, Sa, Ch), so I cant
// test if dropping the value works.
// But I assume that it should:
//
// ```html
// <!doctype html>
// <svg viewBox="0 0 100 100">
// <a href=https://example.com download>
// <circle cx=50 cy=40 r=35 />
// </a>
// </svg>
// ```
//
// See: <https://github.com/wooorm/property-information/blob/main/lib/svg.js>
if (value === true) return name
value =
typeof value === 'object' && 'length' in value
? // `spaces` doesnt accept a second argument, but its given here just to
// keep the code cleaner.
(info.commaSeparated ? commas.stringify : spaces.stringify)(value, {
padLeft: !ctx.tightLists
})
: String(value)
if (ctx.collapseEmpty && !value) return name
// Check unquoted value.
if (ctx.unquoted) {
result = entities(
value,
xtend(ctx.entities, {
subset: constants.unquoted[ctx.valid][ctx.safe],
attribute: true
})
)
}
// If we dont want unquoted, or if `value` contains character references when
// unquoted…
if (result !== value) {
// If the alternative is less common than `quote`, switch.
if (ctx.smart && ccount(value, quote) > ccount(value, ctx.alternative)) {
quote = ctx.alternative
}
result =
quote +
entities(
value,
xtend(ctx.entities, {
// Always encode without parse errors in non-HTML.
subset: (quote === "'" ? constants.single : constants.double)[
ctx.schema.space === 'html' ? ctx.valid : 1
][ctx.safe],
attribute: true
})
) +
quote
}
// Dont add a `=` for unquoted empties.
return name + (result ? '=' + result : result)
}