aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorache <ache@ache.one>2018-05-19 10:09:19 +0200
committerache <ache@ache.one>2018-05-19 10:09:19 +0200
commitfd7d2e7cf485902c4662468b744451427066ac60 (patch)
tree3f84217b863d43584b97e742c8fcf0bfa2e97b0e
parentCorrect README typo's (diff)
Add more tests
-rw-r--r--__tests__/index.js145
-rw-r--r--index.js22
2 files changed, 156 insertions, 11 deletions
diff --git a/__tests__/index.js b/__tests__/index.js
index 3c86fea..45f1315 100644
--- a/__tests__/index.js
+++ b/__tests__/index.js
@@ -13,6 +13,13 @@ import plugin from '..';
const Stream = stream.Readable;
+const renderDefault = text => unified()
+ .use(reParse)
+ .use(plugin)
+ .use(remark2rehype)
+ .use(stringify)
+ .processSync(text);
+
const render = text => unified()
.use(reParse)
.use(plugin, {allowDangerousDOMEventHandlers: false, scope: 'permissive'})
@@ -22,13 +29,20 @@ const render = text => unified()
const renderRaw = text => unified()
.use(reParse)
- .use(plugin, {allowDangerousDOMEventHandlers: true, scope: 'permissive'})
+ .use(plugin, {allowDangerousDOMEventHandlers: false, scope: 'permissive'})
.use(remark2rehype, {allowDangerousHTML: true})
.use(raw)
.use(stringify)
.processSync(text);
-const mainTestString = `Inline *test*{style="em:4"} paragraphe. Use **multiple**{ style="color:pink"} inline ~~block~~ tag. Line \`tagCode\`{ style="color:yellow"}.`;
+/*
+ * TODO :
+ * - Invalid scope
+ * - Invalid extended
+ * - aria attributes
+ */
+
+const mainTestString = `Inline *test*{style="em:4"} paragraph. Use **multiple**{ style="color:pink"} inline ~~block~~ tag. Line \`tagCode\`{ style="color:yellow"}.`;
function string2stream(string) {
const stream = new Stream();
@@ -59,6 +73,20 @@ function every(obj, fct) {
return true;
}
+test('basic-default', t => {
+ const {contents} = renderDefault(mainTestString);
+ const parser = new parse5.SAXParser();
+
+ const nbTag = {em: 1, s: 1, code: 1, strong: 1, errorTag: 0};
+ parser.on('startTag', name => {
+ if (name in nbTag) {
+ nbTag[name] -= 1;
+ }
+ });
+ string2stream(contents).pipe(parser);
+ t.true(every(nbTag, x => x === 0));
+});
+
test('basic', t => {
const {contents} = render(mainTestString);
const parser = new parse5.SAXParser();
@@ -88,7 +116,7 @@ test('basic-raw', t => {
});
test('em', async t => {
- const {contents} = render('textexampleno interest **Important**{style=4em} still no interest');
+ const {contents} = render('textexamplenointerest **Important**{style=4em} still no interest');
const parser = new parse5.SAXParser();
parser.on('startTag', (name, attrs) => {
@@ -100,6 +128,41 @@ test('em', async t => {
await string2stream(contents).pipe(parser);
});
+test('readme-default', async t => {
+ const fileExample = file(join(__dirname, 'readMeTest.txt'));
+ const {contents} = renderDefault(fileExample);
+ const parser = new parse5.SAXParser();
+
+ parser.on('startTag', (name, attrs) => {
+ switch (name) {
+ case 'img':
+ t.true(propEgal({height: 50, alt: 'alt', src: 'img'}, attrs));
+ break;
+ case 'a':
+ t.true(propEgal({ref: 'external', src: 'https://rms.sexy'}, attrs));
+ break;
+ case 'h3':
+ t.true(propEgal({style: 'color:red;'}, attrs));
+ break;
+ case 'em':
+ t.true(propEgal({style: 'color:yellow;'}, attrs));
+ break;
+ case 'strong':
+ t.true(propEgal({}, attrs));
+ break;
+ case 'del':
+ t.true(propEgal({style: 'color: grey;'}, attrs));
+ break;
+ case 'code':
+ t.true(propEgal({}, attrs));
+ break;
+ default:
+ }
+ });
+
+ await string2stream(contents).pipe(parser);
+});
+
test('readme', async t => {
const fileExample = file(join(__dirname, 'readMeTest.txt'));
const {contents} = render(fileExample);
@@ -123,7 +186,7 @@ test('readme', async t => {
t.true(propEgal({awesome: ''}, attrs));
break;
case 'del':
- t.true(propEgal({style: 'color: grey;'}, attrs));
+ t.true(propEgal({style: 'color: gray;'}, attrs));
break;
case 'code':
t.true(propEgal({lang: 'c'}, attrs));
@@ -135,3 +198,77 @@ test('readme', async t => {
await string2stream(contents).pipe(parser);
});
+test('extended', async t => {
+ const renderExtended = text => unified()
+ .use(reParse)
+ .use(plugin, {extend: {image: ['quality']}})
+ .use(remark2rehype)
+ .use(stringify)
+ .process(text, (err, file) => {
+ const parser = new parse5.SAXParser();
+
+ t.true(!err);
+
+ parser.on('startTag', (name, attrs) => {
+ if (name === 'img') {
+ t.true(propEgal({alt: 'Awesome image', src: 'aws://image.jpg', quality: '80'}, attrs));
+ }
+ });
+ string2stream(String(file)).pipe(parser);
+ });
+
+ await renderExtended(`
+*Wait* !
+This is an awesome image : ![Awesome image](aws://image.jpg){ quality="80" awesomeness="max" }
+`);
+});
+
+test('extended Dangerous', async t => {
+ const renderExtended = text => unified()
+ .use(reParse)
+ .use(plugin, {extend: {image: ['quality', 'onload']}})
+ .use(remark2rehype)
+ .use(stringify)
+ .process(text, (err, file) => {
+ const parser = new parse5.SAXParser();
+
+ t.true(!err);
+
+ parser.on('startTag', (name, attrs) => {
+ if (name === 'img') {
+ t.true(propEgal({alt: 'Awesome image', src: 'aws://image.jpg', quality: '80', onload: 'launchAwesomeFunction();'}, attrs));
+ }
+ });
+ string2stream(String(file)).pipe(parser);
+ });
+
+ await renderExtended(`
+*Wait* !
+This is an awesome image : ![Awesome image](aws://image.jpg){ quality="80" awesomeness="max" onload="launchAwesomeFunction();" }
+`);
+});
+
+test('extended-global', async t => {
+ const renderExtended = text => unified()
+ .use(reParse)
+ .use(plugin, {extend: {'*': ['exAttr']}})
+ .use(remark2rehype)
+ .use(stringify)
+ .process(text, (err, file) => {
+ const parser = new parse5.SAXParser();
+
+ t.true(!err);
+
+ parser.on('startTag', (name, attrs) => {
+ if (name === 'strong') {
+ t.true(propEgal({exAttr: 'true'}, attrs));
+ }
+ });
+ string2stream(String(file)).pipe(parser);
+ });
+
+ await renderExtended(`
+*Wait* ! You are **beautiful**{ exAttr="true" } !
+`);
+});
+
diff --git a/index.js b/index.js
index ace52e5..b9eba7e 100644
--- a/index.js
+++ b/index.js
@@ -39,6 +39,7 @@ const convTypeTag = {
emphasis: 'em',
delete: 's',
inlineCode: 'code',
+ '*': '*',
};
/* TODO :
@@ -102,6 +103,14 @@ function filterAttributes(prop, config, type) {
const {allowDangerousDOMEventHandlers} = config;
const specific = htmlElemAttr;
+ const extendTag = (extend => {
+ const t = {};
+ Object.getOwnPropertyNames(extend).forEach(p => {
+ t[convTypeTag[p]] = extend[p];
+ });
+ return t;
+ })(extend);
+
Object.getOwnPropertyNames(prop).forEach(p => {
if (p !== 'key' && p !== 'class' && p !== 'id') {
prop[p] = prop[p] || '';
@@ -109,7 +118,7 @@ function filterAttributes(prop, config, type) {
});
const isDangerous = p => DOMEventHandler.indexOf(p) >= 0;
- const isSpecific = p => 'type' in specific && specific[type].indexOf(p) >= 0;
+ const isSpecific = p => type in specific && specific[type].indexOf(p) >= 0;
const isGlobal = p => htmlElemAttr['*'].indexOf(p) >= 0;
let inScope = _ => false;
@@ -127,8 +136,9 @@ function filterAttributes(prop, config, type) {
inScope = x => !isDangerous(x);
}
break;
- case 'extented':
- inScope = p => extend[type].indexOf(p) >= 0;
+ case 'extended':
+ inScope = p => extendTag && type in extendTag && extendTag[type].indexOf(p) >= 0;
+ inScope = orFunc(inScope, p => '*' in extendTag && extendTag['*'].indexOf(p) >= 0);
// Or if it in the specific scope, fallthrough
case 'specific':
inScope = orFunc(inScope, isSpecific);
@@ -141,10 +151,8 @@ function filterAttributes(prop, config, type) {
}
}
- const filterFunction = x => !inScope(x);
-
Object.getOwnPropertyNames(prop).forEach(p => {
- if (filterFunction(p)) {
+ if (!inScope(p)) {
delete prop[p];
}
});
@@ -163,7 +171,7 @@ function remarkAttr(userConfig) {
allowDangerousDOMEventHandlers: false,
elements: supportedElements,
extend: {},
- scope: 'specific',
+ scope: 'extended',
};
const config = {...defaultConfig, ...userConfig};