More tests, will start merging now

This commit is contained in:
Ludwig Schubert
2017-10-17 10:49:55 -07:00
parent 5cb9b79559
commit 95d357c308
10 changed files with 248 additions and 71 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
import { FrontMatter } from './front-matter';
import { FrontMatter, mergeFromYMLFrontmatter } from './front-matter';
import { DMath } from './components/d-math';
import { collect_citations } from './helpers/citation.js';
import { parseFrontmatter } from './components/d-front-matter';
@@ -107,7 +107,7 @@ export const Controller = {
onFrontMatterChanged(event) {
const data = event.detail;
frontMatter.mergeFromYMLFrontmatter(data);
mergeFromYMLFrontmatter(frontMatter, data);
const interstitial = document.querySelector('d-interstitial');
if (interstitial) {
+6 -1
View File
@@ -1,5 +1,10 @@
import { collect_citations } from '../helpers/citation.js';
export default function(dom, data) {
data.citations = collect_citations(dom);
const citations = new Set(data.citations);
const newCitations = collect_citations(dom);
for (const citation of newCitations) {
citations.add(citation);
}
data.citations = Array.from(citations);
}
+2 -1
View File
@@ -1,4 +1,5 @@
import { parseFrontmatter } from '../components/d-front-matter';
import { mergeFromYMLFrontmatter } from '../front-matter.js';
export default function(dom, data) {
const frontMatterTag = dom.querySelector('d-front-matter');
@@ -7,5 +8,5 @@ export default function(dom, data) {
return;
}
const extractedData = parseFrontmatter(frontMatterTag);
data.mergeFromYMLFrontmatter(extractedData);
mergeFromYMLFrontmatter(data, extractedData);
}
+9 -9
View File
@@ -42,6 +42,15 @@ class Author {
}
}
export function mergeFromYMLFrontmatter(target, source) {
target.title = source.title;
target.publishedDate = new Date(source.published);
target.description = source.description;
target.authors = source.authors.map( (authorObject) => new Author(authorObject));
target.katex = source.katex;
target.password = source.password;
}
export class FrontMatter {
constructor() {
this.title = ''; // 'Attention and Augmented Recurrent Neural Networks'
@@ -118,15 +127,6 @@ export class FrontMatter {
// - Google Brain:
// - Google Brain: http://g.co/brain
mergeFromYMLFrontmatter(data) {
this.title = data.title;
this.publishedDate = new Date(data.published);
this.description = data.description;
this.authors = data.authors.map( (authorObject) => new Author(authorObject));
this.katex = data.katex;
this.password = data.password;
}
//
// Computed Properties
//
+45 -32
View File
@@ -7,11 +7,11 @@ import ExtractFrontmatter from './extractors/front-matter';
import ExtractBibliography from './extractors/bibliography';
import ExtractCitations from './extractors/citations';
const extractors = [
ExtractFrontmatter,
ExtractBibliography,
ExtractCitations,
];
const extractors = new Map([
['ExtractFrontmatter', ExtractFrontmatter],
['ExtractBibliography', ExtractBibliography],
['ExtractCitations', ExtractCitations],
]);
/* Transforms */
import HTML from './transforms/html';
@@ -25,43 +25,53 @@ import TOC from './transforms/toc';
import Typeset from './transforms/typeset';
import Bibliography from './transforms/bibliography';
const transforms = [
HTML, makeStyleTag, Polyfills, OptionalComponents, TOC, Byline, Mathematics,
Meta, Typeset, Bibliography,
];
const transforms = new Map([
['HTML', HTML],
['makeStyleTag', makeStyleTag],
['Polyfills', Polyfills],
['OptionalComponents', OptionalComponents],
['TOC', TOC],
['Byline', Byline],
['Mathematics', Mathematics],
['Meta', Meta],
['Typeset', Typeset],
['Bibliography', Bibliography],
]);
/* Distill Transforms */
import DistillHeader from './distill-transforms/distill-header';
import DistillAppendix from './distill-transforms/distill-appendix';
import DistillFooter from './distill-transforms/distill-footer';
const distillTransforms = [
DistillHeader, DistillAppendix, DistillFooter,
];
const distillTransforms = new Map([
['DistillHeader', DistillHeader],
['DistillAppendix', DistillAppendix],
['DistillFooter', DistillFooter],
]);
/* Exported functions */
export function render(dom, data) {
export function render(dom, data, verbose=true) {
// first, we collect static data from the dom
for (const extract of extractors) {
console.warn('Running extractor...');
extract(dom, data);
for (const [name, extract] of extractors.entries()) {
if (verbose) console.warn('Running extractor: ' + name);
extract(dom, data, verbose);
}
// secondly we use it to transform parts of the dom
for (const transform of transforms) {
console.warn('Running transform...');
for (const [name, transform] of transforms.entries()) {
if (verbose) console.warn('Running transform: ' + name);
// console.warn('Running transform: ', transform);
transform(dom, data);
transform(dom, data, verbose);
}
dom.body.setAttribute('distill-prerendered', '');
// the function calling us can now use the transformed dom and filled data object
}
export function distillify(dom, data) {
export function distillify(dom, data, verbose=true) {
// thirdly, we can use these additional transforms when publishing on the Distill website
for (const transform of distillTransforms) {
// console.warn('Running distillify: ', transform);
transform(dom, data);
for (const [name, transform] of distillTransforms.entries()) {
if (verbose) console.warn('Running distillify: ', name);
transform(dom, data, verbose);
}
}
@@ -70,14 +80,12 @@ export function usesTemplateV2(dom) {
let usesV2 = undefined;
for (const tag of tags) {
const src = tag.src;
if (src.includes('distill.pub')) {
if (src.includes('template.v1.js')) {
usesV2 = false;
} else if (src.includes('template.v2.js')) {
usesV2 = true;
} else {
throw new Error('Uses distill template, but unknown version?!');
}
if (src.includes('template.v1.js')) {
usesV2 = false;
} else if (src.includes('template.v2.js')) {
usesV2 = true;
} else if (src.includes('template.')) {
throw new Error('Uses distill template, but unknown version?!');
}
}
@@ -87,5 +95,10 @@ export function usesTemplateV2(dom) {
return usesV2;
}
}
export { FrontMatter }; // TODO: removable?
export { FrontMatter };
export const testing = {
extractors: extractors,
transforms: transforms,
distillTransforms: distillTransforms
};
+5
View File
@@ -5,6 +5,11 @@ export default function(dom, data) {
let needsCSS = false;
const article = dom.querySelector('d-article');
if (!article) {
console.warn("No d-article tag found!");
return;
}
if (data.katex && data.katex.delimiters) {
global.document = dom;
renderMathInElement(article, data.katex);
+17 -12
View File
@@ -22,7 +22,8 @@ export default function(dom, data) {
<meta property="article:published" itemprop="datePublished" content="${data.publishedYear}-${data.publishedMonthPadded}-${data.publishedDayPadded}" />
<meta property="article:modified" itemprop="dateModified" content="${data.updatedDate}" />
`);
data.authors.forEach((a) => {
(data.authors || []).forEach((a) => {
appendHtml(head, `
<meta property="article:author" content="${a.firstName} ${a.lastName}" />`);
});
@@ -58,7 +59,7 @@ export default function(dom, data) {
meta('citation_fulltext_html_url', data.url);
meta('citation_volume', data.volume);
meta('citation_issue', data.issue);
meta('citation_firstpage', data.doiSuffix? `e${data.doiSuffix}` : undefined);
meta('citation_firstpage', data.doiSuffix ? `e${data.doiSuffix}` : undefined);
meta('citation_doi', data.doi);
let journal = data.journal || {};
@@ -75,17 +76,21 @@ export default function(dom, data) {
meta('citation_author', `${a.lastName}, ${a.firstName}`);
meta('citation_author_institution', a.affiliation);
});
} else {
console.warn('No DOI suffix in data; not adding citation meta tags!');
}
if (data.citations) {
data.citations.forEach(key => {
let d = data.bibliography[key];
if(!d) {
console.warn('No bibliography data fround for ' + key);
} else {
meta('citation_reference', citation_meta_content(data.bibliography[key]) );
}
});
}
if (data.citations) {
data.citations.forEach(key => {
if (data.bibliography && data.bibliography.has(key)) {
const entry = data.bibliography.get(key);
meta('citation_reference', citation_meta_content(entry) );
} else {
console.warn('No bibliography data found for ' + key);
}
});
} else {
console.warn('No citations found; not adding any references meta tags!');
}
}
+5 -1
View File
@@ -9,7 +9,11 @@
export default function(dom, data) {
const article = dom.querySelector('d-article');
// const abstract = dom.querySelector('d-abstract');
if (!article) {
console.warn('No d-article tag found!');
return;
}
let interstitial = dom.querySelector('d-interstitial');
if (!interstitial && data.password) {
+3
View File
@@ -0,0 +1,3 @@
function nodeListToArray(nodeList) {
return Array.prototype.slice.call(nodeList);
}
+154 -13
View File
@@ -1,15 +1,23 @@
/* global it, should, describe, before, beforeEach, after, afterEach */
/* global it, describe, before, beforeEach, after, afterEach */
const jsdom = require("jsdom");
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
const expect = require('chai').expect;
const distill = require('../dist/transforms.v2.js');
// omitJSDOMErrors as JSDOM routinely can't parse modern CSS
const virtualConsole = new jsdom.VirtualConsole();
virtualConsole.sendTo(console, { omitJSDOMErrors: true });
const options = { runScripts: 'outside-only', QuerySelector: true, virtualConsole: virtualConsole };
describe('Distill V2 (transforms)', function() {
it('should export usesTemplateV2()', function() {
it('should export its expected interface', function() {
expect(distill.testing).to.be.an('object');
expect(distill.usesTemplateV2).to.be.a('function');
expect(distill.render).to.be.a('function');
expect(distill.distillify).to.be.a('function');
});
describe('#usesTemplateV2()', function() {
@@ -24,8 +32,13 @@ describe('Distill V2 (transforms)', function() {
expect(distill.usesTemplateV2(frag)).to.be.true;
});
it('should detect local scripts as well', function() {
const frag = JSDOM.fragment('<script src="/template.v2.js"></script>');
expect(distill.usesTemplateV2(frag)).to.be.true;
});
it('should error on unknown distill script', function() {
const frag = JSDOM.fragment('<script src="https://distill.pub/unknown.v2.js"></script>');
const frag = JSDOM.fragment('<script src="https://distill.pub/template.v42.js"></script>');
expect(()=> distill.usesTemplateV2(frag)).to.throw('unknown');
});
@@ -36,18 +49,146 @@ describe('Distill V2 (transforms)', function() {
});
it('should export render()', function() {
expect(distill.render).to.be.a('function');
});
describe('#render()', function() {
it('should extract metadata');
it('should run transforms');
describe('should extract metadata', function() {
});
it('should extract citations', function() {
const dom = new JSDOM('<d-cite key="test-citation-key">sth</d-cite>', options);
const data = {};
const extractCitations = distill.testing.extractors.get('ExtractCitations');
expect(extractCitations).to.be.a('function');
extractCitations(dom.window.document, data);
expect(data).to.have.property('citations');
const citations = data.citations;
expect(citations).to.be.an.instanceof(Array);
expect(citations).to.have.lengthOf(1);
const citation = citations[0];
expect(citation).to.equal('test-citation-key');
});
it('should extract bibliography', function() {
const dom = new JSDOM(`
<d-cite key="mercier2011humans">sth</d-cite>
<d-bibliography>
<script type="text/bibtex">
@article{mercier2011humans,
title={Why do humans reason? Arguments for an argumentative theory},
author={Mercier, Hugo and Sperber, Dan},
journal={Behavioral and brain sciences},
volume={34},
number={02},
pages={57--74},
year={2011},
publisher={Cambridge Univ Press},
doi={10.1017/S0140525X10000968}
}
</script>
</d-bibliography>
`, options);
const data = {};
const extractBibliography = distill.testing.extractors.get('ExtractBibliography');
extractBibliography(dom.window.document, data);
expect(data.bibliography).to.be.an.instanceof(Map);
const entry = data.bibliography.get('mercier2011humans');
expect(entry).to.be.an('object');
expect(entry).to.have.property('year', '2011');
});
it('should extract front-matter');
}); // metadata
describe('should transform the DOM', function() {
it('should add Google scholar citation information', function() {
const dom = new JSDOM('', options);
const data = {
authors: [
{firstName: 'Frank', lastName: 'Underwood', affiliation: 'Google Brain', affiliationURL: 'https://g.co/brain'},
{firstName: 'Shan', lastName: 'Carter', affiliation: 'Google Brain', affiliationURL: 'https://g.co/brain'},
],
doiSuffix: 'test-doi-suffix'
};
const firstAuthorName = data.authors[0].firstName + ' ' + data.authors[0].lastName;
const GSfirstAuthorName = data.authors[0].lastName + ', ' + data.authors[0].firstName;
const meta = distill.testing.transforms.get('Meta');
expect(meta).to.be.a('function');
meta(dom.window.document, data);
const metaTags = dom.window.document.querySelectorAll('meta');
expect(metaTags).to.not.be.empty;
// Google Scholar
const GSAuthorTags = Array.prototype.filter.call(metaTags, (tag) => {
return tag.name === 'citation_author';
});
expect(GSAuthorTags).to.have.lengthOf(2);
const GSFirstAuthorTag = GSAuthorTags[0];
expect(GSFirstAuthorTag.content).to.equal(GSfirstAuthorName);
// Schema.org Author tags
const SOAuthorTags = Array.prototype.filter.call(metaTags, (tag) => {
return tag.getAttribute('property') === 'article:author';
});
expect(SOAuthorTags).to.have.lengthOf(2);
const SOFirstAuthorTag = SOAuthorTags[0];
expect(SOFirstAuthorTag.content).to.equal(firstAuthorName);
});
it('given already correct data, it should add Google scholar references information', function() {
const dom = new JSDOM('', options);
const data = {
doiSuffix: 'test-doi-suffix',
citations: ['test-citation-key'],
bibliography: new Map([[
'test-citation-key', {
title: 'Why do humans reason? Arguments for an argumentative theory',
author: 'Mercier, Hugo and Sperber, Dan',
journal: 'Behavioral and brain sciences',
volume: 34,
number: 2
}
]])
};
const meta = distill.testing.transforms.get('Meta');
expect(meta).to.be.a('function');
meta(dom.window.document, data);
const metaTags = [].slice.call(dom.window.document.querySelectorAll('meta[name="citation_reference"]'));
expect(metaTags).to.not.be.empty;
});
it('given only a DOM, it should add Google scholar references information', function() {
const dom = new JSDOM(`
<d-cite key="mercier2011humans">sth</d-cite>
<d-bibliography>
<script type="text/bibtex">
@article{mercier2011humans,
title={Why do humans reason? Arguments for an argumentative theory},
author={Mercier, Hugo and Sperber, Dan},
journal={Behavioral and brain sciences},
volume={34},
number={02},
pages={57--74},
year={2011},
publisher={Cambridge Univ Press},
doi={10.1017/S0140525X10000968}
}
</script>
</d-bibliography>
`, options);
const data = {};
distill.render(dom.window.document, data, false);
const metaTags = [].slice.call(dom.window.document.querySelectorAll('meta[name="citation_reference"]'));
expect(metaTags).to.not.be.empty;
});
});
}); // render
it('should export #distillify()', function() {
expect(distill.distillify).to.be.a('function');
@@ -61,4 +202,4 @@ describe('Distill V2 (transforms)', function() {
});
}); // describe 'Render'
}); // describe 'Transform'