Skip to content

Commit

Permalink
Add JSDoc based types
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed May 1, 2021
1 parent 20e9416 commit 21e9223
Show file tree
Hide file tree
Showing 10 changed files with 451 additions and 311 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
*.d.ts
*.log
coverage/
node_modules/
Expand Down
216 changes: 4 additions & 212 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,213 +1,5 @@
import {h, s} from 'hastscript'
import {html, svg, find} from 'property-information'
import vfileLocation from 'vfile-location'
import {webNamespaces} from 'web-namespaces'
/**
* @typedef {import('./lib/index.js').Options} Options
*/

var own = {}.hasOwnProperty

// Handlers.
var map = {
'#document': root,
'#document-fragment': root,
'#text': text,
'#comment': comment,
'#documentType': doctype
}

// Wrapper to normalise options.
export function fromParse5(ast, options) {
var settings = options || {}
var file

if (settings.messages) {
file = settings
settings = {}
} else {
file = settings.file
}

return transform(ast, {
schema: settings.space === 'svg' ? svg : html,
file,
verbose: settings.verbose
})
}

// Transform a node.
function transform(ast, config) {
var schema = config.schema
var fn = own.call(map, ast.nodeName) ? map[ast.nodeName] : element
var children
var result
var position

if (fn === element) {
config.schema = ast.namespaceURI === webNamespaces.svg ? svg : html
}

if (ast.childNodes) {
children = nodes(ast.childNodes, config)
}

result = fn(ast, children, config)

if (ast.sourceCodeLocation && config.file) {
position = location(result, ast.sourceCodeLocation, config)

if (position) {
config.location = true
result.position = position
}
}

config.schema = schema

return result
}

// Transform children.
function nodes(children, config) {
var index = -1
var result = []

while (++index < children.length) {
result[index] = transform(children[index], config)
}

return result
}

// Transform a document.
// Stores `ast.quirksMode` in `node.data.quirksMode`.
function root(ast, children, config) {
var result = {
type: 'root',
children,
data: {quirksMode: ast.mode === 'quirks' || ast.mode === 'limited-quirks'}
}
var doc
var location

if (config.file && config.location) {
doc = String(config.file)
location = vfileLocation(doc)
result.position = {
start: location.toPoint(0),
end: location.toPoint(doc.length)
}
}

return result
}

// Transform a doctype.
function doctype(ast) {
return {
type: 'doctype',
name: ast.name || '',
public: ast.publicId || null,
system: ast.systemId || null
}
}

// Transform a text.
function text(ast) {
return {type: 'text', value: ast.value}
}

// Transform a comment.
function comment(ast) {
return {type: 'comment', value: ast.data}
}

// Transform an element.
function element(ast, children, config) {
var fn = config.schema.space === 'svg' ? s : h
var props = {}
var index = -1
var result
var attribute
var pos
var start
var end

while (++index < ast.attrs.length) {
attribute = ast.attrs[index]
props[(attribute.prefix ? attribute.prefix + ':' : '') + attribute.name] =
attribute.value
}

result = fn(ast.tagName, props, children)

if (result.tagName === 'template' && 'content' in ast) {
pos = ast.sourceCodeLocation
start = pos && pos.startTag && position(pos.startTag).end
end = pos && pos.endTag && position(pos.endTag).start

result.content = transform(ast.content, config)

if ((start || end) && config.file) {
result.content.position = {start, end}
}
}

return result
}

// Create clean positional information.
function location(node, location, config) {
var result = position(location)
var tail
var key
var props

if (node.type === 'element') {
tail = node.children[node.children.length - 1]

// Bug for unclosed with children.
// See: <https://github.com/inikulin/parse5/issues/109>.
if (!location.endTag && tail && tail.position && tail.position.end) {
result.end = Object.assign({}, tail.position.end)
}

if (config.verbose) {
props = {}

for (key in location.attrs) {
if (own.call(location.attrs, key)) {
props[find(config.schema, key).property] = position(
location.attrs[key]
)
}
}

node.data = {
position: {
opening: position(location.startTag),
closing: location.endTag ? position(location.endTag) : null,
properties: props
}
}
}
}

return result
}

function position(loc) {
var start = point({
line: loc.startLine,
column: loc.startCol,
offset: loc.startOffset
})
var end = point({
line: loc.endLine,
column: loc.endCol,
offset: loc.endOffset
})
return start || end ? {start, end} : null
}

function point(point) {
return point.line && point.column ? point : null
}
export {fromParse5} from './lib/index.js'

0 comments on commit 21e9223

Please sign in to comment.