Skip to content

Commit

Permalink
convert to node imports/exports
Browse files Browse the repository at this point in the history
  • Loading branch information
AbdBarho committed Mar 16, 2019
1 parent f0b8700 commit f3430e0
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 56 deletions.
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./src/index');
14 changes: 9 additions & 5 deletions src/compat.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@
We will include our polyfill instance methods as regular functions.
*/

export function startsWith (str, searchString, position) {
function startsWith(str, searchString, position) {
return str.substr(position || 0, searchString.length) === searchString
}

export function endsWith (str, searchString, position) {
function endsWith(str, searchString, position) {
const index = (position || str.length) - searchString.length
const lastIndex = str.lastIndexOf(searchString, index)
return lastIndex !== -1 && lastIndex === index
}

export function stringIncludes (str, searchString, position) {
function stringIncludes(str, searchString, position) {
return str.indexOf(searchString, position || 0) !== -1
}

export function isRealNaN (x) {
function isRealNaN(x) {
return typeof x === 'number' && isNaN(x)
}

export function arrayIncludes (array, searchElement, position) {
function arrayIncludes(array, searchElement, position) {
const len = array.length
if (len === 0) return false

Expand All @@ -39,3 +39,7 @@ export function arrayIncludes (array, searchElement, position) {

return false
}

module.exports = {
startsWith, endsWith, stringIncludes, isRealNaN, arrayIncludes
};
13 changes: 9 additions & 4 deletions src/format.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
export function splitHead (str, sep) {
function splitHead(str, sep) {
const idx = str.indexOf(sep)
if (idx === -1) return [str]
return [str.slice(0, idx), str.slice(idx + sep.length)]
}

export function unquote (str) {
function unquote (str) {
const car = str.charAt(0)
const end = str.length - 1
const isQuoteStart = car === '"' || car === "'"
Expand All @@ -14,12 +14,13 @@ export function unquote (str) {
return str
}

export function format (nodes, options) {
function format (nodes, options) {
return nodes.map(node => {
const type = node.type
const outputNode = type === 'element'
? {
type,
//FIXME: maybe here?
tagName: node.tagName.toLowerCase(),
attributes: formatAttributes(node.attributes),
children: format(node.children, options)
Expand All @@ -32,7 +33,7 @@ export function format (nodes, options) {
})
}

export function formatAttributes (attributes) {
function formatAttributes (attributes) {
return attributes.map(attribute => {
const parts = splitHead(attribute.trim(), '=')
const key = parts[0]
Expand All @@ -42,3 +43,7 @@ export function formatAttributes (attributes) {
return {key, value}
})
}

module.exports = {
splitHead, formatAttributes, unquote, format
};
27 changes: 13 additions & 14 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
import lexer from './lexer'
import parser from './parser'
import {format} from './format'
import {toHTML} from './stringify'
import {
voidTags,
closingTags,
childlessTags,
closingTagAncestorBreakers
} from './tags'
let { parser } = require('./parser');
let { lexer } = require('./lexer');
let { format } = require('./format');
let { toHTML } = require('./stringify');
let { voidTags, closingTags, childlessTags, closingTagAncestorBreakers } = require('./tags');

export const parseDefaults = {
const parseDefaults = {
voidTags,
closingTags,
childlessTags,
closingTagAncestorBreakers,
includePositions: false
}
};

export function parse (str, options = parseDefaults) {
function parse(str, options = parseDefaults) {
const tokens = lexer(str, options)
const nodes = parser(tokens, options)
return format(nodes, options)
}

export function stringify (ast, options = parseDefaults) {
function stringify(ast, options = parseDefaults) {
return toHTML(ast, options)
}

module.exports = {
parse, stringify
};
40 changes: 20 additions & 20 deletions src/lexer.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import {
startsWith,
endsWith,
stringIncludes,
arrayIncludes
} from './compat'
let { startsWith, endsWith, stringIncludes, arrayIncludes } = require('./compat');

export function feedPosition (position, str, len) {
function feedPosition (position, str, len) {
const start = position.index
const end = position.index = start + len
for (let i = start; i < end; i++) {
Expand All @@ -19,28 +14,29 @@ export function feedPosition (position, str, len) {
}
}

export function jumpPosition (position, str, end) {
function jumpPosition (position, str, end) {
const len = end - position.index
return feedPosition(position, str, len)
}

export function makeInitialPosition () {
function makeInitialPosition () {
return {
index: 0,
column: 0,
line: 0
}
}

export function copyPosition (position) {
function copyPosition (position) {
return {
index: position.index,
line: position.line,
column: position.column
}
}

export default function lexer (str, options) {
//FIXME: export default
function lexer (str, options) {
const state = {
str,
options,
Expand All @@ -51,7 +47,7 @@ export default function lexer (str, options) {
return state.tokens
}

export function lex (state) {
function lex (state) {
const {str, options: {childlessTags}} = state
const len = str.length
while (state.position.index < len) {
Expand All @@ -73,7 +69,7 @@ export function lex (state) {
}

const alphanumeric = /[A-Za-z0-9]/
export function findTextEnd (str, index) {
function findTextEnd (str, index) {
while (true) {
const textEnd = str.indexOf('<', index)
if (textEnd === -1) {
Expand All @@ -87,7 +83,7 @@ export function findTextEnd (str, index) {
}
}

export function lexText (state) {
function lexText (state) {
const type = 'text'
const {str, position} = state
let textEnd = findTextEnd(str, position.index)
Expand All @@ -103,7 +99,7 @@ export function lexText (state) {
state.tokens.push({type, content, position: {start, end}})
}

export function lexComment (state) {
function lexComment (state) {
const {str, position} = state
const start = copyPosition(position)
feedPosition(position, str, 4) // "<!--".length
Expand All @@ -125,7 +121,7 @@ export function lexComment (state) {
})
}

export function lexTag (state) {
function lexTag (state) {
const {str, position} = state
{
const secondChar = str.charAt(position.index + 1)
Expand All @@ -148,11 +144,11 @@ export function lexTag (state) {

// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#special-white-space
const whitespace = /\s/
export function isWhitespaceChar (char) {
function isWhitespaceChar (char) {
return whitespace.test(char)
}

export function lexTagName (state) {
function lexTagName (state) {
const {str, position} = state
const len = str.length
let start = position.index
Expand Down Expand Up @@ -180,7 +176,7 @@ export function lexTagName (state) {
return tagName
}

export function lexTagAttributes (state) {
function lexTagAttributes (state) {
const {str, position, tokens} = state
let cursor = position.index
let quote = null // null, single-, or double-quote
Expand Down Expand Up @@ -271,7 +267,7 @@ export function lexTagAttributes (state) {

const push = [].push

export function lexSkipTag (tagName, state) {
function lexSkipTag (tagName, state) {
const {str, position, tokens} = state
const safeTagName = tagName.toLowerCase()
const len = str.length
Expand Down Expand Up @@ -310,3 +306,7 @@ export function lexSkipTag (tagName, state) {
break
}
}

module.exports = {
feedPosition, jumpPosition, makeInitialPosition, copyPosition, lexer, lex, findTextEnd, lexText, lexComment, lexTag, isWhitespaceChar, lexTagName, lexTagAttributes, lexSkipTag
};
15 changes: 10 additions & 5 deletions src/parser.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {arrayIncludes} from './compat'
let { arrayIncludes } = require('./compat');

export default function parser (tokens, options) {
//FIXME: export default
function parser (tokens, options) {
const root = {tagName: null, children: []}
const state = {tokens, options, cursor: 0, stack: [root]}
parse(state)
return root.children
}

export function hasTerminalParent (tagName, stack, terminals) {
function hasTerminalParent (tagName, stack, terminals) {
const tagParents = terminals[tagName]
if (tagParents) {
let currentIndex = stack.length - 1
Expand All @@ -25,15 +26,15 @@ export function hasTerminalParent (tagName, stack, terminals) {
return false
}

export function rewindStack (stack, newLength, childrenEndPosition, endPosition) {
function rewindStack (stack, newLength, childrenEndPosition, endPosition) {
stack[newLength].position.end = endPosition
for (let i = newLength + 1, len = stack.length; i < len; i++) {
stack[i].position.end = childrenEndPosition
}
stack.splice(newLength)
}

export function parse (state) {
function parse (state) {
const {tokens, options} = state
let {stack} = state
let nodes = stack[stack.length - 1].children
Expand Down Expand Up @@ -132,3 +133,7 @@ export function parse (state) {
}
state.cursor = cursor
}

module.exports = {
parser, hasTerminalParent, rewindStack, parse
};
10 changes: 6 additions & 4 deletions src/stringify.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {arrayIncludes} from './compat'
let { arrayIncludes } = require('./compat');

export function formatAttributes (attributes) {
function formatAttributes (attributes) {
return attributes.reduce((attrs, attribute) => {
const {key, value} = attribute
if (value === null) {
Expand All @@ -12,7 +12,7 @@ export function formatAttributes (attributes) {
}, '')
}

export function toHTML (tree, options) {
function toHTML (tree, options) {
return tree.map(node => {
if (node.type === 'text') {
return node.content
Expand All @@ -28,4 +28,6 @@ export function toHTML (tree, options) {
}).join('')
}

export default {toHTML}
module.exports = {
formatAttributes, toHTML
};
12 changes: 8 additions & 4 deletions src/tags.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
Tags which contain arbitary non-parsed content
For example: <script> JavaScript should not be parsed
*/
export const childlessTags = ['style', 'script', 'template']
const childlessTags = ['style', 'script', 'template']

/*
Tags which auto-close because they cannot be nested
For example: <p>Outer<p>Inner is <p>Outer</p><p>Inner</p>
*/
export const closingTags = [
const closingTags = [
'html', 'head', 'body', 'p', 'dt', 'dd', 'li', 'option',
'thead', 'th', 'tbody', 'tr', 'td', 'tfoot', 'colgroup'
]
Expand All @@ -20,7 +20,7 @@ export const closingTags = [
For example: in <li><ul><li></ul></li>,
the top-level <li> should not auto-close.
*/
export const closingTagAncestorBreakers = {
const closingTagAncestorBreakers = {
li: ['ul', 'ol', 'menu'],
dt: ['dl'],
dd: ['dl'],
Expand All @@ -35,8 +35,12 @@ export const closingTagAncestorBreakers = {
Tags which do not need the closing tag
For example: <img> does not need </img>
*/
export const voidTags = [
const voidTags = [
'!doctype', 'area', 'base', 'br', 'col', 'command',
'embed', 'hr', 'img', 'input', 'keygen', 'link',
'meta', 'param', 'source', 'track', 'wbr'
]

module.exports = {
childlessTags, closingTags, closingTagAncestorBreakers, voidTags
};

0 comments on commit f3430e0

Please sign in to comment.