Skip to content
This repository has been archived by the owner on Sep 7, 2021. It is now read-only.

Use the recipe to drive the renderer #107

Merged
merged 6 commits into from
Aug 20, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions recipes/html-element.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ body:
- prose.accessibility_concerns?
- prose.*
- meta.examples
- meta.info_box:
- meta.api
- meta.permitted_aria_roles
- meta.tag_omission
- meta.info_box
- meta.browser_compatibility
- prose.see_also
78 changes: 62 additions & 16 deletions scripts/build-json/build-page-json.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,75 @@ function writeToFile(json, elementPath) {
fs.writeFileSync(dest, `${JSON.stringify(json, null, 2)}`);
};

async function processMetaIngredient(elementPath, ingredientName, data) {
switch (ingredientName) {
case 'interactive_example':
return data.interactive_example;
case 'browser_compatibility':
return bcd.package(data.browser_compatibility);
case 'attributes':
if (data.attributes.element_specific) {
const attributesPath = path.join(elementPath, data.attributes.element_specific);
return await attributes.package(attributesPath);
} else {
return [];
}
case 'examples':
const examplesPaths = data.examples.map(relativePath => path.join(elementPath, relativePath));
return await examples.package(examplesPaths);
case 'info_box':
// TODO: implement packaging for info boxes
wbamberg marked this conversation as resolved.
Show resolved Hide resolved
return 'info_box-value';
default:
console.error(`Error: Unrecognized ingredient: ${ingredient}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
console.error(`Error: Unrecognized ingredient: ${ingredient}`);
throw new Error(`Unrecognized ingredient: ${ingredient}`);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you like this suggestion, the next line would need to be nixed.

return null;
}
}

async function processProseIngredient(ingredientName, proseSections) {
if (ingredientName !== '*') {
const matches = proseSections.filter(section => section.value.id === ingredientName);
if (matches.length > 0) {
wbamberg marked this conversation as resolved.
Show resolved Hide resolved
return matches[0];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the else case, should it at least return null or perhaps throw an error? Either way, looks a bit "naked" without dealing with this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is permissible for there not to be any matches, if the prose ingredient is optional and this item omits it. But I agree that we should have an explicit return branch here.

} else {
const additional = proseSections.filter(section => !section.value.id);
wbamberg marked this conversation as resolved.
Show resolved Hide resolved
return {
type: 'additional_prose',
value: additional
wbamberg marked this conversation as resolved.
Show resolved Hide resolved
};
}
}

async function buildFromRecipe(elementPath, data, content) {
const item = {};
item.title = data.title;
item.mdn_url = data.mdn_url;

// load the recipe to get related_content
const recipePath = path.join(process.cwd(), './recipes', `${data.recipe}.yaml`);
const recipe = yaml.safeLoad(fs.readFileSync(recipePath, 'utf8'));
item.related_content = related.buildRelatedContent(recipe.related_content);

item.title = data.title;
item.mdn_url = data.mdn_url;
item.interactive_example_url = data.interactive_example;
item.browser_compatibility = bcd.package(data.browser_compatibility);

if (data.attributes.element_specific) {
const attributesPath = path.join(elementPath, data.attributes.element_specific);
item.attributes = await attributes.package(attributesPath);
} else {
item.attributes = [];
}

const examplesPaths = data.examples.map(relativePath => path.join(elementPath, relativePath));
item.examples = await examples.package(examplesPaths);
item.prose = await prose.package(content);
// for each ingredient in the recipe, process the item's ingredient
const proseSections = await prose.package(content);
item.body = await Promise.all(recipe.body.map(async ingredient => {
const [ingredientType, ingredientName] = ingredient.replace(/\?$/, '').split('.');
if (ingredientType === 'meta') {
const value = await processMetaIngredient(elementPath, ingredientName, data);
if (value) {
return {
type: ingredientName,
value: value
};
}
} else if (ingredientType === 'prose') {
return await processProseIngredient(ingredientName, proseSections);
} else {
throw (`Error: Unrecognized ingredient type: ${ingredientType}`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be...

throw new Error(`Unrecognized ingredient type: ${ingredientType}`);

Also, perhaps it's overkill but I could see how this error might be very cryptic if it happens in a CI build. We could either do something like this:

console.warn(`Ingredient processing problem in ${elementPath}`);
throw new Error(`Unrecognized ingredient type: ${ingredientType}`);

...or...

throw new Error(`Unrecognized ingredient type: ${ingredientType} in ${elementPath}`);

}
}));
// filter out missing ingredients
item.body = item.body.filter(x => !!x);

const contributorsPath = path.join(elementPath, 'contributors.md');
item.contributors = await contributors.package(contributorsPath);
Expand Down
24 changes: 13 additions & 11 deletions scripts/build-json/slice-prose.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,35 +33,37 @@ function extractFromSiblings(node, terminatorTag, contentType) {
return content;
}

function getSection(node, sections) {
function getSectionValue(node, sections) {
const sectionName = node.textContent.trim();
const sectionContent = extractFromSiblings(node, 'H2', 'html');

if (namedSections.includes(sectionName)) {
const sectionSlug = sectionNameToSlug(sectionName);
sections[sectionSlug] = {
const sectionId = sectionNameToSlug(sectionName);
return {
title: sectionName,
id: sectionId,
content: sectionContent
}
};
} else {
const additionalSection = {
return {
title: sectionName,
content: sectionContent
};
sections['additional_sections'].push(additionalSection);
}
}

async function package(proseMD) {
const proseHTML = await markdown.markdownToHTML(proseMD)
const proseHTML = await markdown.markdownToHTML(proseMD);
const dom = JSDOM.fragment(proseHTML);
const sections = {
'additional_sections': []
};
const sections = [];
let node = dom.firstChild;
while (node) {
if (node.nodeName === 'H2') {
getSection(node, sections);
const sectionValue = getSectionValue(node, sections);
sections.push({
type: 'prose',
value: sectionValue
});
}
node = node.nextSibling;
}
Expand Down