Comparing version 0.2.2 to 0.2.3
#!/usr/bin/env node | ||
(function () { | ||
function help () { | ||
/* | ||
Usage: himalaya [file] [dest] | ||
function help() { | ||
/* | ||
Usage: himalaya [file] [dest] | ||
(no args): pipe in HTML, pipe out JSON | ||
@@ -16,55 +16,56 @@ file: HTML file location | ||
*/ | ||
} | ||
} | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var himalaya = require('..'); | ||
var fs = require('fs') | ||
var path = require('path') | ||
var himalaya = require('..') | ||
var args = process.argv.slice(2); | ||
var root = process.cwd(); | ||
var args = process.argv.slice(2) | ||
var root = process.cwd() | ||
function toJSON(data) { | ||
return JSON.stringify(data, null, 2); | ||
} | ||
function toJSON (data) { | ||
return JSON.stringify(data, null, 2) | ||
} | ||
if(!args.length) { | ||
process.stdin.resume(); | ||
process.stdin.setEncoding('utf8'); | ||
process.stdin.on('data', function(text) { | ||
var data = himalaya.parse(text); | ||
var json = toJSON(data); | ||
process.stdout.write(json); | ||
}); | ||
process.stdin.on('end', function() { | ||
process.exit(0); | ||
}); | ||
return; | ||
} | ||
if (!args.length) { | ||
process.stdin.resume() | ||
process.stdin.setEncoding('utf8') | ||
process.stdin.on('data', function (text) { | ||
var data = himalaya.parse(text) | ||
var json = toJSON(data) | ||
process.stdout.write(json) | ||
}) | ||
process.stdin.on('end', function () { | ||
process.exit(0) | ||
}) | ||
return | ||
} | ||
var flag = args[0].toLowerCase(); | ||
var flag = args[0].toLowerCase() | ||
if(flag === '-h' || flag === '--help') { | ||
var h = help.toString(); | ||
var msg = h.substring(h.indexOf('*') + 2, h.lastIndexOf('*')); | ||
return console.log(msg); | ||
} | ||
if (flag === '-h' || flag === '--help') { | ||
var h = help.toString() | ||
var msg = h.substring(h.indexOf('*') + 2, h.lastIndexOf('*')) | ||
return console.log(msg) | ||
} | ||
if(flag === '-v' || flag === '--version') { | ||
var pkg = require('../package.json'); | ||
return console.log(pkg.version); | ||
} | ||
if (flag === '-v' || flag === '--version') { | ||
var pkg = require('../package.json') | ||
return console.log(pkg.version) | ||
} | ||
var src = path.join(root, args[0]); | ||
var dest = args[1] | ||
? path.join(root, args[1]) | ||
: null; | ||
var src = path.join(root, args[0]) | ||
var dest = args[1] | ||
? path.join(root, args[1]) | ||
: null | ||
var text = fs.readFileSync(src); | ||
var data = himalaya.parse(text); | ||
var cout = toJSON(data); | ||
var text = fs.readFileSync(src) | ||
var data = himalaya.parse(text) | ||
var cout = toJSON(data) | ||
if(dest) { | ||
fs.writeFileSync(dest, cout); | ||
} else { | ||
console.log(cout); | ||
} | ||
if (dest) { | ||
fs.writeFileSync(dest, cout) | ||
} else { | ||
console.log(cout) | ||
} | ||
})() |
{ | ||
"name": "himalaya", | ||
"version": "0.2.2", | ||
"description": "HTML to JSON parser", | ||
"main": "index.js", | ||
"version": "0.2.3", | ||
"author": "Chris Andrejewski <christopher.andrejewski@gmail.com>", | ||
"bin": { | ||
"himalaya": "./bin/himalaya.js" | ||
}, | ||
"scripts": { | ||
"test": "mocha", | ||
"himalaya": "./bin/himalaya.js" | ||
"bugs": { | ||
"url": "https://github.com/andrejewski/himalaya/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/andrejewski/himalaya.git" | ||
"dependencies": { | ||
"paul": "0.0.3" | ||
}, | ||
"devDependencies": { | ||
"ava": "^0.16.0", | ||
"babel-polyfill": "^6.16.0", | ||
"babel-preset-es2015": "^6.16.0", | ||
"babel-preset-stage-0": "^6.16.0", | ||
"babel-regenerator-runtime": "^6.5.0", | ||
"del": "^2.2.2", | ||
"gulp": "^3.9.1", | ||
"gulp-babel": "^6.1.2", | ||
"gulp-sourcemaps": "^2.1.1", | ||
"source-map-support": "^0.4.3", | ||
"standard": "^8.4.0" | ||
}, | ||
"homepage": "https://github.com/andrejewski/himalaya", | ||
"keywords": [ | ||
"ast", | ||
"html", | ||
"parser", | ||
"ast", | ||
"json" | ||
"json", | ||
"parser" | ||
], | ||
"author": "Chris Andrejewski <christopher.andrejewski@gmail.com>", | ||
"license": "ISC", | ||
"bugs": { | ||
"url": "https://github.com/andrejewski/himalaya/issues" | ||
"main": "lib/index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/andrejewski/himalaya.git" | ||
}, | ||
"homepage": "https://github.com/andrejewski/himalaya", | ||
"devDependencies": { | ||
"mocha": "^3.1.0" | ||
}, | ||
"dependencies": { | ||
"paul": "0.0.3" | ||
"scripts": { | ||
"himalaya": "./bin/himalaya.js", | ||
"prepublish": "standard --fix && fixpack && npm run test", | ||
"test": "gulp --silent && ava" | ||
} | ||
} |
@@ -1,267 +0,144 @@ | ||
var h = require('../'); | ||
var assert = require('assert'); | ||
import test from 'ava' | ||
import himalaya from '../' | ||
function print(s) { | ||
console.log(JSON.stringify(s, null, 2)); | ||
} | ||
/* | ||
These tests mainly serve as a gauntlet for generic use. | ||
Do not add any more of these kinds of tests, instead | ||
test the more granular bits. | ||
// README demo | ||
// print(h.parse(["<div class='post post-featured'><p>Himalaya parsed me...</p><!-- ...and I liked it. --></div>"])); | ||
// return; | ||
TODO: remove overlapping tests | ||
*/ | ||
describe('himalaya', function() { | ||
describe('parse(String) Object', function() { | ||
it('should return the AST of given HTML', function() { | ||
var h1 = "<html><h1>Hello, World</h1></html>"; | ||
var d1 = [{ | ||
type: 'Element', | ||
tagName: 'html', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Element', | ||
tagName: 'h1', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'Hello, World' | ||
}] | ||
}] | ||
}]; | ||
assert.deepEqual(d1, h.parse(h1)); | ||
test('parse() should pass the Hello World case', t => { | ||
const html = '<html><h1>Hello, World</h1></html>' | ||
const data = [{ | ||
type: 'Element', | ||
tagName: 'html', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Element', | ||
tagName: 'h1', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'Hello, World' | ||
}] | ||
}] | ||
}] | ||
t.deepEqual(data, himalaya.parse(html)) | ||
}) | ||
var h2 = "<div class='section widget'><b disabled>Poop</b><p>Pee</p></div>"; | ||
var d2 = [{ | ||
type: 'Element', | ||
tagName: 'div', | ||
attributes: { | ||
className: ['section', 'widget'] | ||
}, | ||
children: [{ | ||
type: 'Element', | ||
tagName: 'b', | ||
attributes: { | ||
disabled: 'disabled' | ||
}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'Poop' | ||
}] | ||
}, { | ||
type: 'Element', | ||
tagName: 'p', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'Pee' | ||
}] | ||
}] | ||
}]; | ||
assert.deepEqual(d2, h.parse(h2)); | ||
test('parse() should work for mixed attributes', t => { | ||
const html = "<div class='section widget'><b disabled>Poop</b><p>Pee</p></div>" | ||
const data = [{ | ||
type: 'Element', | ||
tagName: 'div', | ||
attributes: { | ||
className: ['section', 'widget'] | ||
}, | ||
children: [{ | ||
type: 'Element', | ||
tagName: 'b', | ||
attributes: { | ||
disabled: 'disabled' | ||
}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'Poop' | ||
}] | ||
}, { | ||
type: 'Element', | ||
tagName: 'p', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'Pee' | ||
}] | ||
}] | ||
}] | ||
t.deepEqual(data, himalaya.parse(html)) | ||
}) | ||
var h3 = "<b><!--comment text-->words</b>"; | ||
var d3 = [{ | ||
type: 'Element', | ||
tagName: 'b', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Comment', | ||
content: 'comment text' | ||
}, { | ||
type: 'Text', | ||
content: 'words' | ||
}] | ||
}]; | ||
assert.deepEqual(d3, h.parse(h3)); | ||
test('parse() should work for commented html', t => { | ||
const html = '<b><!--comment text-->words</b>' | ||
const data = [{ | ||
type: 'Element', | ||
tagName: 'b', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Comment', | ||
content: 'comment text' | ||
}, { | ||
type: 'Text', | ||
content: 'words' | ||
}] | ||
}] | ||
t.deepEqual(data, himalaya.parse(html)) | ||
}) | ||
var h4 = "<div style='width: 360px; height: 120px; background-color: #fff'></div>"; | ||
var d4 = [{ | ||
type: 'Element', | ||
tagName: 'div', | ||
attributes: { | ||
style: { | ||
width: '360px', | ||
height: '120px', | ||
backgroundColor: '#fff' | ||
} | ||
}, | ||
children: [] | ||
}]; | ||
assert.deepEqual(d4, h.parse(h4)); | ||
test('parse() should work for style properties', t => { | ||
const html = "<div style='width: 360px; height: 120px; background-color: #fff'></div>" | ||
const data = [{ | ||
type: 'Element', | ||
tagName: 'div', | ||
attributes: { | ||
style: { | ||
width: '360px', | ||
height: '120px', | ||
backgroundColor: '#fff' | ||
} | ||
}, | ||
children: [] | ||
}] | ||
t.deepEqual(data, himalaya.parse(html)) | ||
}) | ||
var h5 = "<div data-num=0 data-word='poop' data-cake='2'></div>"; | ||
var d5 = [{ | ||
type: 'Element', | ||
tagName: 'div', | ||
attributes: { | ||
dataset: { | ||
num: 0, | ||
word: 'poop', | ||
cake: 2 | ||
} | ||
}, | ||
children: [] | ||
}]; | ||
assert.deepEqual(d5, h.parse(h5)); | ||
test('parse() should work on data-* attributes', t => { | ||
const html = "<div data-num=0 data-word='poop' data-cake='2'></div>" | ||
const data = [{ | ||
type: 'Element', | ||
tagName: 'div', | ||
attributes: { | ||
dataset: { | ||
num: 0, | ||
word: 'poop', | ||
cake: 2 | ||
} | ||
}, | ||
children: [] | ||
}] | ||
t.deepEqual(data, himalaya.parse(html)) | ||
}) | ||
var h6 = "<p>One two<p>three four"; | ||
var d6 = [{ | ||
type: 'Element', | ||
tagName: 'p', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'One two' | ||
}] | ||
}, { | ||
type: 'Element', | ||
tagName: 'p', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'three four' | ||
}] | ||
}]; | ||
assert.deepEqual(d6, h.parse(h6)); | ||
}); | ||
}); | ||
test('should work on unclosed tags', t => { | ||
const html = '<p>One two<p>three four' | ||
const data = [{ | ||
type: 'Element', | ||
tagName: 'p', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'One two' | ||
}] | ||
}, { | ||
type: 'Element', | ||
tagName: 'p', | ||
attributes: {}, | ||
children: [{ | ||
type: 'Text', | ||
content: 'three four' | ||
}] | ||
}] | ||
t.deepEqual(data, himalaya.parse(html)) | ||
}) | ||
describe('parseTag(String, Array[String]) Object', function() { | ||
describe('return {stack: Array[Name]}', function() { | ||
it('should be the given stack for void elements', function() { | ||
var text = '<meta charset="utf8">'; | ||
var s1 = []; | ||
var s2 = ['root']; | ||
assert.deepEqual(s1, h.parseTag(text, s1).stack); | ||
assert.deepEqual(s2, h.parseTag(text, s2).stack); | ||
}); | ||
it('should be the given stack for childless elements', function() { | ||
var text = '<script type="text/javascript">kill(9);</script>'; | ||
var s1 = []; | ||
var s2 = ['root']; | ||
assert.deepEqual(s1, h.parseTag(text, s1).stack); | ||
assert.deepEqual(s2, h.parseTag(text, s2).stack); | ||
}); | ||
it('should be the correct stack for nested elements', function() { | ||
var text = '<p>Peanuts</div>'; | ||
var s1 = ['root', 'div']; | ||
var s2 = ['div', 'span']; | ||
var s3 = ['div', 'div', 'table']; | ||
function x(s) { | ||
return h.parseTag(text, s.concat('div')).stack; | ||
} | ||
assert.deepEqual(s1, x(s1)); | ||
assert.deepEqual(s2, x(s2)); | ||
assert.deepEqual(s3, x(s3)); | ||
}); | ||
}); | ||
describe('return {tag: Object}', function() { | ||
it('should have the correct `tagName` property', function() { | ||
var text1 = '<p>Words and letters</p>'; | ||
var name1 = h.parseTag(text1, []).tag.tagName; | ||
assert.equal('p', name1); | ||
var text2 = '<ng-element>Words and letters</ng-element>'; | ||
var name2 = h.parseTag(text2, []).tag.tagName; | ||
assert.equal('ng-element', name2); | ||
}); | ||
}); | ||
}); | ||
describe('parseAttrs(String) Object', function() { | ||
it('should return {str:String} starting at the end of attributes', function() { | ||
var text1 = ' data-attr=0 type="text" disabled />...'; | ||
var results = h.parseAttrs(text1); | ||
assert.equal('/>...', results.str); | ||
var text2 = ' />...'; | ||
var results = h.parseAttrs(text2); | ||
assert.equal('/>...', results.str); | ||
var text3 = ' data-attr=0 type="text" disabled >...'; | ||
var results = h.parseAttrs(text3); | ||
assert.equal('>...', results.str); | ||
var text4 = ' >...'; | ||
var results = h.parseAttrs(text4); | ||
assert.equal('>...', results.str); | ||
}); | ||
describe('return {attributes:Object}', function() { | ||
it('should have all attributes', function() { | ||
var text = ' data-attr=0 type="text" disabled >...' | ||
var data = { | ||
dataset: { | ||
attr: 0 | ||
}, | ||
type: 'text', | ||
disabled: 'disabled' | ||
}; | ||
assert.deepEqual(data, h.parseAttrs(text).attributes); | ||
}); | ||
it('should handle attributes with no quotes', function() { | ||
var text = ' dumb = little stupid=quirks>...'; | ||
var data = { | ||
dumb: 'little', | ||
stupid: 'quirks' | ||
}; | ||
assert.deepEqual(data, h.parseAttrs(text).attributes); | ||
}); | ||
it('should handle attributes with whitespace between the equals (=)', function() { | ||
var text = ' dumb = "stuff" please = no>...'; | ||
var data = { | ||
dumb: 'stuff', | ||
please: 'no' | ||
}; | ||
assert.deepEqual(data, h.parseAttrs(text).attributes); | ||
}); | ||
it('should group all data-* in the `dataset` Object', function() { | ||
var text = ' data-attr=0 data-name="Chris" type="text" disabled >...'; | ||
var data = h.parseAttrs(text).attributes; | ||
assert.equal(0, data.dataset.attr); | ||
assert.equal('Chris', data.dataset.name); | ||
assert(!data.dataset.type); | ||
assert(!data.dataset.disabled); | ||
}); | ||
it('should put parsed styles in the `style` attribute', function() { | ||
var text = 'style="width: 20px; height: 40px; font-size: 12px" >'; | ||
var data = { | ||
style: { | ||
width: '20px', | ||
height: '40px', | ||
fontSize: '12px' | ||
} | ||
}; | ||
assert.deepEqual(data, h.parseAttrs(text).attributes); | ||
}); | ||
}); | ||
}); | ||
describe('parseStyle(String) Object', function() { | ||
it('should return an hashmap of style declarations', function() { | ||
var style = 'color: #000; height: 80px'; | ||
var data = { | ||
color: '#000', | ||
height: '80px' | ||
}; | ||
assert.deepEqual(data, h.parseStyle(style)); | ||
}); | ||
it('should camelCase CSS properties', function() { | ||
var style = [ | ||
'background-color: #fff', | ||
'border-right: 1px solid #000', | ||
'border-top-left-radius: 4px' | ||
].join(';'); | ||
var data = { | ||
backgroundColor: '#fff', | ||
borderRight: '1px solid #000', | ||
borderTopLeftRadius: '4px' | ||
}; | ||
assert.deepEqual(data, h.parseStyle(style)); | ||
}); | ||
}); | ||
}); | ||
test('should not set custom attrs to zeroes', t => { | ||
const html = "<div custom-attr=''></div>" | ||
const data = [{ | ||
type: 'Element', | ||
tagName: 'div', | ||
attributes: {customAttr: ''}, | ||
children: [] | ||
}] | ||
t.deepEqual(data, himalaya.parse(html)) | ||
}) |
@@ -1,185 +0,188 @@ | ||
var himalaya = require('..'); | ||
var translations = require('../translate'); | ||
var toHTML = translations.toHTML; | ||
var toJade = translations.toJade; | ||
var toPug = translations.toPug; | ||
var assert = require('assert'); | ||
import test from 'ava' | ||
import himalaya from '../lib' | ||
import translate from '../lib/translate' | ||
const {toHTML, toJade, toPug} = translate | ||
describe('translations', function() { | ||
describe('toHTML(ast) html', function() { | ||
it('should handle simple conversions', function() { | ||
var str1 = '<h1>Text</h1>'; | ||
assert.equal(toHTML(himalaya.parse(str1)), str1); | ||
test('toHTML() should handle simple conversions', t => { | ||
const str1 = '<h1>Text</h1>' | ||
t.is(toHTML(himalaya.parse(str1)), str1) | ||
var str2 = 'Text'; | ||
assert.equal(toHTML(himalaya.parse(str2)), str2); | ||
const str2 = 'Text' | ||
t.is(toHTML(himalaya.parse(str2)), str2) | ||
var str3 = '<!--Comment-->'; | ||
assert.equal(toHTML(himalaya.parse(str3)), str3); | ||
}); | ||
const str3 = '<!--Comment-->' | ||
t.is(toHTML(himalaya.parse(str3)), str3) | ||
}) | ||
it('should work for void elements', function() { | ||
var meta = "<meta charset='utf8'>"; | ||
assert.equal(toHTML(himalaya.parse(meta)), meta); | ||
test('toHTML() should work for void elements', t => { | ||
const meta = "<meta charset='utf8'>" | ||
t.is(toHTML(himalaya.parse(meta)), meta) | ||
var link = "<link rel='stylesheet' href='file.css'>"; | ||
assert.equal(toHTML(himalaya.parse(link)), link); | ||
}); | ||
const link = "<link rel='stylesheet' href='file.css'>" | ||
t.is(toHTML(himalaya.parse(link)), link) | ||
}) | ||
it('should build data-* attributes properly', function() { | ||
var elem = "<div data-one='5' data-two='five'></div>"; | ||
assert.equal(toHTML(himalaya.parse(elem)), elem); | ||
}); | ||
test('toHTML() should build data-* attributes properly', t => { | ||
const elem = "<div data-one='5' data-two='five'></div>" | ||
t.is(toHTML(himalaya.parse(elem)), elem) | ||
}) | ||
it('should build the style attribute properly', function() { | ||
var elem = "<div style='color: #fff; font-size: 12px'></div>"; | ||
assert.equal(toHTML(himalaya.parse(elem)), elem); | ||
}); | ||
test('toHTML() should build the style attribute properly', t => { | ||
const elem = "<div style='color: #fff; font-size: 12px'></div>" | ||
t.is(toHTML(himalaya.parse(elem)), elem) | ||
}) | ||
it('should do basic escaping if a value contains either single or double quotes', function() { | ||
var html = '<div data-val="cake is \'good\'"></div>'; | ||
assert.equal(toHTML(himalaya.parse(html)), html); | ||
}); | ||
test('toHTML() should do basic escaping if a value contains either single or double quotes', t => { | ||
const html = '<div data-val="cake is \'good\'"></div>' | ||
t.is(toHTML(himalaya.parse(html)), html) | ||
}) | ||
it('should preserve whitespace', function() { | ||
var html = [ | ||
"<html> ", | ||
" <h1> Document </h1>", | ||
"</html> " | ||
].join('\n'); | ||
assert.equal(toHTML(himalaya.parse(html)), html); | ||
}); | ||
test('toHTML() should preserve whitespace', t => { | ||
const html = [ | ||
'<html> ', | ||
' <h1> Document </h1>', | ||
'</html> ' | ||
].join('\n') | ||
t.is(toHTML(himalaya.parse(html)), html) | ||
}) | ||
it('should close void tags when doctype is xml', function() { | ||
var html = "<img src='bar.png'>"; | ||
var xml = "<img src='bar.png'></img>"; | ||
var jsonHTML = himalaya.parse(html); | ||
var jsonXML = himalaya.parse(xml); | ||
test('toHTML() should close void tags when doctype is xml', t => { | ||
const html = "<img src='bar.png'>" | ||
const xml = "<img src='bar.png'></img>" | ||
const jsonHTML = himalaya.parse(html) | ||
const jsonXML = himalaya.parse(xml) | ||
assert.equal(toHTML(jsonHTML), html); | ||
assert.equal(toHTML(jsonHTML, { | ||
doctype: 'xml' | ||
}), xml); | ||
t.is(toHTML(jsonHTML), html) | ||
t.is(toHTML(jsonHTML, { | ||
doctype: 'xml' | ||
}), xml) | ||
assert.equal(toHTML(jsonXML), html); | ||
assert.equal(toHTML(jsonXML, { | ||
doctype: 'xml' | ||
}), xml); | ||
}); | ||
t.is(toHTML(jsonXML), html) | ||
t.is(toHTML(jsonXML, { | ||
doctype: 'xml' | ||
}), xml) | ||
}) | ||
it('should write out boolean attributes when doctype is xml', function() { | ||
var html = "<script src='bar.js' async></script>"; | ||
var xml = "<script src='bar.js' async='async'></script>"; | ||
var jsonHTML = himalaya.parse(html); | ||
var jsonXML = himalaya.parse(xml); | ||
test('toHTML() should write out boolean attributes when doctype is xml', t => { | ||
const html = "<script src='bar.js' async></script>" | ||
const xml = "<script src='bar.js' async='async'></script>" | ||
const jsonHTML = himalaya.parse(html) | ||
const jsonXML = himalaya.parse(xml) | ||
assert.equal(toHTML(jsonHTML), html); | ||
assert.equal(toHTML(jsonHTML, { | ||
doctype: 'xml' | ||
}), xml); | ||
t.is(toHTML(jsonHTML), html) | ||
t.is(toHTML(jsonHTML, { | ||
doctype: 'xml' | ||
}), xml) | ||
assert.equal(toHTML(jsonXML), html); | ||
assert.equal(toHTML(jsonXML, { | ||
doctype: 'xml' | ||
}), xml); | ||
}); | ||
}); | ||
t.is(toHTML(jsonXML), html) | ||
t.is(toHTML(jsonXML, { | ||
doctype: 'xml' | ||
}), xml) | ||
}) | ||
describe('toJade(ast, options) jade', function() { | ||
it('should handle plain text', function() { | ||
var html = 'This is text.'; | ||
var jade = '| This is text.'; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should handle multi-line plain text', function() { | ||
var html = 'This is multiline text.\nLook newlines.'; | ||
var jade = '| This is multiline text.\n| Look newlines.'; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should handle inline comments', function() { | ||
var html = '<!-- Comment -->'; | ||
var jade = '// Comment '; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should handle multi-line comments', function() { | ||
var html = [ | ||
"<!--", | ||
" This is a multiline comment.", | ||
" Look newlines.", | ||
"-->" | ||
].join('\n'); | ||
var jade = [ | ||
"//", | ||
" This is a multiline comment.", | ||
" Look newlines." | ||
].join('\n'); | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should write short-hand tag ids', function() { | ||
var html = "<article id='story'></article>"; | ||
var jade = "article#story"; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should write short-hand tag classes', function() { | ||
var html = "<article class='story story--main'></article>"; | ||
var jade = "article.story.story--main"; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should ignore `div` if an id or class(es) are provided', function() { | ||
var htmlId = "<div id='block'></div>"; | ||
var jadeId = "#block"; | ||
assert.equal(toJade(himalaya.parse(htmlId)), jadeId); | ||
test('toJade() should handle plain text', t => { | ||
const html = 'This is text.' | ||
const jade = '| This is text.' | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
var htmlClass = "<div class='block'></div>"; | ||
var jadeClass = ".block"; | ||
assert.equal(toJade(himalaya.parse(htmlClass)), jadeClass); | ||
test('toJade() should handle multi-line plain text', t => { | ||
const html = 'This is multiline text.\nLook newlines.' | ||
const jade = '| This is multiline text.\n| Look newlines.' | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
var htmlClasses = "<div class='block block--jumbo'></div>"; | ||
var jadeClasses = ".block.block--jumbo"; | ||
assert.equal(toJade(himalaya.parse(htmlClasses)), jadeClasses); | ||
}); | ||
it('should write attributes', function() { | ||
var html = "<canvas width='500' height='400'></canvas>"; | ||
var jade = "canvas(width='500', height='400')"; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should write data-* attributes', function() { | ||
var html = "<div data-one='5' data-two='five'></div>"; | ||
var jade = "div(data-one='5', data-two='five')"; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should do basic escaping if a value contains either single or double quotes', function() { | ||
var html = '<div data-val="cake is \'good\'"></div>'; | ||
var jade = 'div(data-val="cake is \'good\'")'; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should write the style attribute', function() { | ||
var html = "<b style='font-weight: bold; font-style: italics'>Word</b>"; | ||
var jade = "b(style='font-weight: bold; font-style: italics') Word"; | ||
assert.equal(toJade(himalaya.parse(html)), jade); | ||
}); | ||
it('should appropriate place tag inner text', function() { | ||
var htmlInline = "<h1>Hello</h1>"; | ||
var jadeInline = "h1 Hello"; | ||
assert.equal(toJade(himalaya.parse(htmlInline)), jadeInline); | ||
test('toJade() should handle inline comments', t => { | ||
const html = '<!-- Comment -->' | ||
const jade = '// Comment ' | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
var htmlMultiline = "<h1>Hello\nWorld</h1>"; | ||
var jadeMultiline = "h1.\n Hello\n World"; | ||
assert.equal(toJade(himalaya.parse(htmlMultiline)), jadeMultiline); | ||
}); | ||
it('should work for script and style tags', function() { | ||
var htmlScript = "<script type='text/javascript'>console.log('yes');</script>"; | ||
var jadeScript = "script(type='text/javascript').\n console.log('yes');"; | ||
assert.equal(toJade(himalaya.parse(htmlScript)), jadeScript); | ||
test('toJade() should handle multi-line comments', t => { | ||
const html = [ | ||
'<!--', | ||
' This is a multiline comment.', | ||
' Look newlines.', | ||
'-->' | ||
].join('\n') | ||
const jade = [ | ||
'//', | ||
' This is a multiline comment.', | ||
' Look newlines.' | ||
].join('\n') | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
var htmlStyle = "<style>h1 {color: #fff;} .text {font-size: 12px;}</style>"; | ||
var jadeStyle = "style.\n h1 {color: #fff;} .text {font-size: 12px;}"; | ||
assert.equal(toJade(himalaya.parse(htmlStyle)), jadeStyle); | ||
}); | ||
}); | ||
describe('toPug(ast, options)', function() { | ||
it('should be an alias for toJade(ast, options)', function() { | ||
assert.equal(toJade, toPug); | ||
}); | ||
}); | ||
}); | ||
test('toJade() should write short-hand tag ids', t => { | ||
const html = "<article id='story'></article>" | ||
const jade = 'article#story' | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
test('toJade() should write short-hand tag classes', t => { | ||
const html = "<article class='story story--main'></article>" | ||
const jade = 'article.story.story--main' | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
test('toJade() should ignore `div` if an id or class(es) are provided', t => { | ||
const htmlId = "<div id='block'></div>" | ||
const jadeId = '#block' | ||
t.is(toJade(himalaya.parse(htmlId)), jadeId) | ||
const htmlClass = "<div class='block'></div>" | ||
const jadeClass = '.block' | ||
t.is(toJade(himalaya.parse(htmlClass)), jadeClass) | ||
const htmlClasses = "<div class='block block--jumbo'></div>" | ||
const jadeClasses = '.block.block--jumbo' | ||
t.is(toJade(himalaya.parse(htmlClasses)), jadeClasses) | ||
}) | ||
test('toJade() should write attributes', t => { | ||
const html = "<canvas width='500' height='400'></canvas>" | ||
const jade = "canvas(width='500', height='400')" | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
test('toJade() should write data-* attributes', t => { | ||
const html = "<div data-one='5' data-two='five'></div>" | ||
const jade = "div(data-one='5', data-two='five')" | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
test('toJade() should do basic escaping if a value contains either single or double quotes', t => { | ||
const html = '<div data-val="cake is \'good\'"></div>' | ||
const jade = 'div(data-val="cake is \'good\'")' | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
test('toJade() should write the style attribute', t => { | ||
const html = "<b style='font-weight: bold; font-style: italics'>Word</b>" | ||
const jade = "b(style='font-weight: bold; font-style: italics') Word" | ||
t.is(toJade(himalaya.parse(html)), jade) | ||
}) | ||
test('toJade() should appropriate place tag inner text', t => { | ||
const htmlInline = '<h1>Hello</h1>' | ||
const jadeInline = 'h1 Hello' | ||
t.is(toJade(himalaya.parse(htmlInline)), jadeInline) | ||
const htmlMultiline = '<h1>Hello\nWorld</h1>' | ||
const jadeMultiline = 'h1.\n Hello\n World' | ||
t.is(toJade(himalaya.parse(htmlMultiline)), jadeMultiline) | ||
}) | ||
test('toJade() should work for script and style tags', t => { | ||
const htmlScript = "<script type='text/javascript'>console.log('yes');\nconsole.log('no');</script>" | ||
const jadeScript = "script(type='text/javascript').\n console.log('yes');\n console.log('no');" | ||
t.is(toJade(himalaya.parse(htmlScript)), jadeScript) | ||
const htmlStyle = '<style>\nh1 {color: #fff;}\n.text {font-size: 12px;}</style>' | ||
const jadeStyle = 'style.\n h1 {color: #fff;}\n .text {font-size: 12px;}' | ||
t.is(toJade(himalaya.parse(htmlStyle)), jadeStyle) | ||
}) | ||
test('toPug() should be an alias for toJade(ast, options)', t => { | ||
t.is(toJade, toPug) | ||
}) |
216
translate.js
@@ -1,215 +0,1 @@ | ||
var paul = require('paul'); | ||
// c/p'd from ../index.js | ||
var voidTags = [ | ||
"!doctype", "area", "base", "br", "col", "command", | ||
"embed", "hr", "img", "input", "keygen", "link", | ||
"meta", "param", "source", "track", "wbr" | ||
]; | ||
function serializeAttr(attr, value, isXml) { | ||
if (!isXml && attr === value) return attr; | ||
var text = value.toString(); | ||
var quoteEscape = text.indexOf('\'') !== -1; | ||
var quote = quoteEscape ? '\"' : '\''; | ||
return attr + '=' + quote + text + quote; | ||
} | ||
// stolen from underscore.string | ||
function dasherize(str) { | ||
return str.trim() | ||
.replace(/([A-Z])/g, '-$1') | ||
.replace(/[-_\s]+/g, '-') | ||
.toLowerCase(); | ||
} | ||
function inlineStyle(style) { | ||
return Object.keys(style).reduce(function(css, key) { | ||
return css + '; ' + dasherize(key) + ': ' + style[key]; | ||
}, '').slice(2); | ||
} | ||
var toHTML = function(tree, options) { | ||
options = options || {}; | ||
var dtype = options.doctype; | ||
var html = paul.walk(tree, function _html(node, walk) { | ||
if (node.type === 'Text') return node.content; | ||
if (node.type === 'Comment') { | ||
return '<!--' + node.content + '-->'; | ||
} | ||
var tag = '<' + node.tagName; | ||
var attrs = node.attributes; | ||
for (var attr in attrs) { | ||
if (attrs.hasOwnProperty(attr)) { | ||
var val = attrs[attr]; | ||
if (attr === 'dataset') { | ||
for (var prop in val) { | ||
if (val.hasOwnProperty(prop)) { | ||
var key = 'data-' + dasherize(prop); | ||
tag += ' ' + serializeAttr(key, val[prop], dtype === 'xml'); | ||
} | ||
} | ||
} else if (attr === 'style') { | ||
tag += ' ' + serializeAttr(attr, inlineStyle(val)); | ||
} else if (attr === 'className') { | ||
tag += ' ' + serializeAttr('class', val.join(' ')); | ||
} else { | ||
tag += ' ' + serializeAttr(dasherize(attr), val, dtype === 'xml'); | ||
} | ||
} | ||
} | ||
var lowTagName = node.tagName.toLowerCase(); | ||
if (dtype !== 'xml' && ~voidTags.indexOf(lowTagName)) { | ||
if (!dtype && lowTagName === '!doctype') { | ||
dtype = doctypeShortcut(tag); | ||
} | ||
return tag + '>'; | ||
} | ||
tag += '>'; | ||
var innerds = typeof node.content === 'string' ? | ||
node.content : | ||
walk(node.children || []).join('') | ||
return tag + innerds + '</' + node.tagName + '>'; | ||
}); | ||
if (html.join) html = html.join(''); | ||
return html; | ||
} | ||
var newline = '\n'; | ||
var toJade = function(tree, options) { | ||
options = options || {}; | ||
var dtype = options.doctype; | ||
var ident = options.indentation || ' '; | ||
var multi = multilineText(ident); | ||
function isWhitespaceNode(node) { | ||
return !(node.type === 'Text' && !node.content.trim()); | ||
} | ||
if (tree.filter) tree = tree.filter(isWhitespaceNode); | ||
var jade = paul.walk(tree, function(node, walk, depth) { | ||
if (node.type === 'Text') { | ||
return multi(node.content, depth, '| '); | ||
} | ||
if (node.type === 'Comment') { | ||
var text = node.content; | ||
return ~text.indexOf(newline) ? | ||
multi('//', depth) + newline + multi(text, depth + 1) : | ||
multi('//' + text, depth); | ||
} | ||
var tag = node.tagName; | ||
if (node.attributes.id) { | ||
tag += '#' + node.attributes.id; | ||
} | ||
if (node.attributes.className) { | ||
tag += '.' + node.attributes.className.join('.'); | ||
} | ||
if (node.tagName === 'div' && tag.length > 3) { | ||
tag = tag.slice(3); | ||
} | ||
tag = multi(tag, depth); | ||
var attrs = node.attributes; | ||
var props = Object.keys(attrs).filter(function(key) { | ||
return key !== 'className' && key !== 'id'; | ||
}); | ||
if (props.length) { | ||
tag += '('; | ||
tag += props.map(function(prop) { | ||
var val = attrs[prop]; | ||
if (prop === 'dataset') { | ||
return Object.keys(val).map(function(attr) { | ||
return serializeAttr('data-' + dasherize(attr), val[attr], dtype === 'xml'); | ||
}).join(', '); | ||
} else if (prop === 'style') { | ||
return serializeAttr(prop, inlineStyle(val)); | ||
} else { | ||
return serializeAttr(dasherize(prop), val, dtype === 'xml'); | ||
} | ||
}).join(', '); | ||
tag += ')'; | ||
} | ||
var lowTagName = node.tagName.toLowerCase(); | ||
if (~voidTags.indexOf(lowTagName)) { | ||
if (lowTagName === '!doctype') { | ||
if (!dtype) dtype = doctypeShortcut(tag); | ||
return multi('doctype ' + dtype, depth); | ||
} | ||
return tag; | ||
} else if (typeof node.content === 'string') { | ||
if (!node.content) return tag; | ||
return tag + '.' + newline + multi(node.content, depth + 1); | ||
} else { | ||
if (!node.children.length) return tag; | ||
if (node.children.length === 1 && node.children[0].type === 'Text') { | ||
var text = node.children[0].content; | ||
return ~text.indexOf(newline) ? | ||
tag + '.' + newline + multi(text, depth + 1) : | ||
tag + ' ' + text; | ||
} | ||
return tag + newline + | ||
walk(node.children.filter(isWhitespaceNode), depth + 1).join(newline); | ||
} | ||
}, 0); | ||
if (jade.join) jade = jade.join(newline); | ||
return jade; | ||
} | ||
function multilineText(ident) { | ||
var fmt = !~ident.indexOf('\t') ? | ||
function(line) { | ||
return line.replace(/\t/g, ident); | ||
} : | ||
function(line) { | ||
return line; | ||
}; | ||
function indent(depth, str) { | ||
while (depth--) { | ||
str = ident + str; | ||
} | ||
return str; | ||
} | ||
return function(str, depth, lead) { | ||
lead = lead || ''; | ||
var lines = str | ||
.split(newline).map(fmt) | ||
.filter(function(line) { | ||
return !!line.trim(); | ||
}); | ||
var start = maxSharedIndent(lines); | ||
return lines.map(function(line) { | ||
return indent(depth, lead + line.slice(start)); | ||
}).join(newline); | ||
} | ||
} | ||
function maxSharedIndent(lines) { | ||
return lines.reduce(function(num, line) { | ||
return Math.min(num, line.length - line.trimLeft().length); | ||
}, Infinity); | ||
} | ||
// see http://jade-lang.com/reference/doctype/ | ||
function doctypeShortcut(str) { | ||
function has(q) { | ||
return ~str.indexOf(q); | ||
} | ||
if (has('Transitional')) return 'transitional'; | ||
if (has('Strict')) return 'strict'; | ||
if (has('Frameset')) return 'frameset'; | ||
if (has('Basic')) return 'basic'; | ||
if (has('1.1')) return '1.1'; | ||
if (has('Mobile')) return 'mobile'; | ||
return 'html'; | ||
} | ||
module.exports = { | ||
toHTML: toHTML, | ||
toJade: toJade, | ||
toPug: toJade | ||
}; | ||
module.exports = require('./lib/translate') |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
112204
32
1943
11
1