Skip to content
This repository has been archived by the owner on Feb 28, 2022. It is now read-only.

feat(html pipe): Default pipeline should include <section/>s #379

Merged
merged 11 commits into from
Jul 5, 2019

Conversation

ramboz
Copy link
Contributor

@ramboz ramboz commented Jun 15, 2019

Include proper sections in the HTML pipeline instead of plain <hr> sectioning

BREAKING CHANGE:

  • Remove context.content.sections and move the sections directly under
    context.content.mdast
  • Adjust json schemas accordingly
  • Move the section yaml meta info to <node>.meta
  • Move the section types to the mdast <node>.meta.types

Is dependent on adobe/helix-cli#1037

fix #279

@ramboz ramboz requested review from koraa, trieloff, rofe and kptdobe June 15, 2019 00:34
@ramboz
Copy link
Contributor Author

ramboz commented Jun 15, 2019

Trying to gather some early feedback to validate the approach before spending too much time on re-writing the tests

Copy link
Contributor

@trieloff trieloff left a comment

Choose a reason for hiding this comment

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

Looks good so far.

@@ -19,7 +19,7 @@ const {

function yaml(section) {
const yamls = selectAll('yaml', section);
section.meta = obj(flat(map(yamls, ({ payload }) => payload)));
section.meta = Object.assign({}, obj(flat(map(yamls, ({ payload }) => payload))));
Copy link
Contributor

Choose a reason for hiding this comment

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

Why the additional Object.assign?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 Some left-overs from testing various approaches. I'll definitely remove in the final PR.

@@ -11,8 +11,15 @@
*/

const between = require('unist-util-find-all-between');
const { selectAll } = require('unist-util-select');
const { flat, obj, map } = require('@adobe/helix-shared').sequence;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd import @adobe/ferrum directly

@@ -144,7 +144,8 @@ function fallback(section) {
}

function getmetadata({ content }, { logger }) {
const { sections } = content;
const { mdast: { children } } = content;
const sections = children.filter(node => node.type === 'root');
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this work? Below, you are changing the type to section.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 Again, some left-overs from playing around… though it should have failed somehow. Will double-check

return {
type: 'root',
const section = {
type: 'section',
Copy link
Contributor

Choose a reason for hiding this comment

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

New node type is a good idea.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it ok to just inline the node type or do we have a central place to expose them as enum constants that I could use?

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe a schema would be in order?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rofe I added a schema, and updated existing ones accordingly with the changes.
Was just wondering if we have a sort of global "constants" file where I would be pulling the string from, or if it is ok to just inline for now

@@ -76,15 +77,21 @@
"imageReference": "A pointer to an image",
"footnote": "A footnote",
"footnoteReference": "A reference to a footnote",
"embed": "Content embedded from another page, identified by the `url` attribute."
"embed": "Content embedded from another page, identified by the `url` attribute.",
"section": "The extracted sections of the document"
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
"section": "The extracted sections of the document"
"section": "A section within the document. Sections serve as a high-level structure of a single markdown document and can have their own section-specific front matter metadata."

* @returns {string} The tag name for the section. Defaults to {@code div}.
*/
function getTageName(section) {
return (section.meta && section.meta.tagName) || 'div';
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we not use camelCase for YAML properties? tagname should be sufficient.

* @returns {string} The class name for the section. Defaults to {@code hlx-section}.
*/
function getClass(section) {
return (section.meta && section.meta.className) || 'hlx-section';
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here, the YAML property should be class, even if it is slightly inconvenient to read it from JavaScript.

Also, what happens to the detected section types?

// we have a section that is not the document root, so wrap it in the desired tag
if (parent && parent.type === 'root' && parent.children.length > 1) {
const tagName = getTageName(n);
const props = { class: getClass(n), 'data-hlx-types': getTypes(n) };
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rather merge the types into class and then have data-<prop for each additional prop that's in the section metadata.

Copy link
Contributor Author

@ramboz ramboz Jun 17, 2019

Choose a reason for hiding this comment

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

@trieloff So, something like this?

<div class="hlx-Section hlx-Section--hasImage hlx-Section--nbImage1 hlx-Section--hasOnlyImage" data-hlx-<meta1>="<value1>" data-hlx-<meta2>="<value2>" …></div>

And we let the dev:

  • overwrite the section class
  • toggle whether type classes are added (and use the custom section class as prefix if set)
  • toggle whether additional meta props are exposed as data attributes

I went with the SUIT CSS naming convention, but we could also do:

<div class="hlx-section has-image nb-image-1 has-only-image" data-hlx-<meta1>="<value1>" data-hlx-<meta2>="<value2>" …></div>

We just run a higher risk of collisions with domain specific CSS class names

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, except that classnames should be lowercase and should be kept as they are (your lower example).

We can fix the collisions later, i.e. through a step that performs class renaming.

My reason for this is that the HTML is simpler, and writing CSS selectors for attributes is harder than for classes, so I'd err on the side of simplicity over consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@trieloff If we assume a step that does the renaming, then does it make sense to let the author specify the section class name in the first place in the yaml? I could just hardcode hlx-section then.

Less logic => fewer risk of bugs

Copy link
Contributor

Choose a reason for hiding this comment

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

I think allowing to specify the class name is a useful quick fix for some scenarios.

Copy link
Contributor

Choose a reason for hiding this comment

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

i don't think we need to prefix the section with hlx-section as i think that the entire default DOM is a helix DOM and in case of a conflict the or some other desire to change the DOM it is very easily done in a the pre.js via jquery or regular DOM manipulation.

src/utils/section-handler.js Outdated Show resolved Hide resolved
src/utils/section-handler.js Outdated Show resolved Hide resolved
Copy link
Contributor

@trieloff trieloff left a comment

Choose a reason for hiding this comment

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

Looks good so far. I guess eslint is still angry at you.

@ramboz
Copy link
Contributor Author

ramboz commented Jun 18, 2019

@trieloff Mostly the tests are failing since I did not touch them yet. Wanted to first validate the approach

@trieloff
Copy link
Contributor

Keep going, you are on the right track.

@codecov
Copy link

codecov bot commented Jun 21, 2019

Codecov Report

Merging #379 into master will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@          Coverage Diff          @@
##           master   #379   +/-   ##
=====================================
  Coverage     100%   100%           
=====================================
  Files          48     50    +2     
  Lines        1100   1150   +50     
=====================================
+ Hits         1100   1150   +50
Impacted Files Coverage Δ
src/utils/section-handler.js 100% <100%> (ø)
src/utils/conditional-sections.js 100% <100%> (ø) ⬆️
src/html/unwrap-sole-images.js 100% <100%> (ø) ⬆️
src/defaults/html.pipe.js 100% <100%> (ø) ⬆️
src/html/removeHlxProps.js 100% <100%> (ø)
src/html/split-sections.js 100% <100%> (ø) ⬆️
src/utils/mdast-to-vdom.js 100% <100%> (ø) ⬆️
src/html/get-metadata.js 100% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update de63086...d985356. Read the comment docs.

@@ -33,13 +33,6 @@
"mdast": {
"$ref": "https://ns.adobe.com/helix/pipeline/mdast"
},
"sections": {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

BREAKING CHANGE: Sections is removed and added to the mdast directly

| [label](#label) | `string` | Optional | No | MDAST (this schema) |
| [lang](#lang) | `string` | Optional | Yes | MDAST (this schema) |
| [meta](#meta) | `string` | Optional | Yes | MDAST (this schema) |
| [meta](#meta) | `object` | Optional | Yes | MDAST (this schema) |
Copy link
Contributor Author

Choose a reason for hiding this comment

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

BREAKING CHANGE: the meta now contains the yaml meta information

@@ -33,13 +33,6 @@
"mdast": {
"$ref": "https://ns.adobe.com/helix/pipeline/mdast"
},
"sections": {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

BREAKING CHANGE: as above in the doc

@@ -148,9 +153,29 @@
"format": "uri-reference",
"description": "For resources, an url field must be present. It represents a URL to the referenced resource."
},
"meta": {
"type": ["null", "object"],
Copy link
Contributor Author

Choose a reason for hiding this comment

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

BREAKING CHANGE: as above in the doc


const DEFAULT_SECTION_TAG = 'div';
const DEFAULT_SECTION_CLASS = 'hlx-section';
const SYSTEM_META_PROPERTIES = ['class', 'meta', 'tagname', 'types'];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

YAML properties:

  • class {string}: will allow overwriting the default section class (i.e. hlx-section)
  • meta {boolean}: when set to true will output any additional YAML properties as data-hlx-* attributes
  • tagname {string}: will allow overwriting the default section tag (i.e. div)
  • types {boolean}: when set to true will output the section types as additional classes on the section (i.e. has-image, etc.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since meta and types are actual feature flags, should we follow a specific naming convention?
enable_meta/enable_types, output_meta/output_types, etc.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would only do that once we expose it as a config parameter.

@@ -1,42 +1,40 @@
[
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just unwrapping the array since we unwrap sole sections directly on the mdast

}
{
"type": "root",
"children": [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just wrapping the array inside the mdast root's children

@@ -1,50 +1,48 @@
[
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just unwrapping the array since we unwrap sole sections directly on the mdast

(same for rest of the sections fixtures below)

@@ -441,7 +453,7 @@ Or that one at the same time, because they are both part of an A/B test.
// format, section metadata, the mdast format or the input above, you probably
// want to change one of these values until you find one that *happens* to work
// again...
assert.notDeepEqual(await runpipe('foo'), await runpipe('bang'));
assert.notDeepEqual(await runpipe('foo'), await runpipe('bar'));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

As per existing comment above, the test started failing after my changes, so tried out some other value

@@ -29,7 +29,7 @@ function callback(body) {
parseFront(dat);
split(dat, { logger });
getmetadata(dat, { logger });
return dat.content.sections;
return dat.content.mdast;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Expose the mdast node directly since most tests have a single section that will be unwrapped to it

assert.deepEqual(dat.content.meta, {});
});

it('getmetadata does not fail with missing sections', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removing this test since the empty mdast and missing sections are now the same.

@ramboz ramboz changed the title [WIP] feat(html pipe): Default pipeline should include <section/>s feat(html pipe): Default pipeline should include <section/>s Jun 21, 2019
ramboz added 6 commits June 21, 2019 17:17
Include proper sections in the HTML pipeline instead of plain <hr/> sectioning

BREAKING CHANGE: Remove `context.content.sections` and move the sections directly under
`context.content.mdast`; move the section types to the mdast `<node>.data.types`; move the section
yaml meta info to `<node>.data.meta`

fix #279
Include proper sections in the HTML pipeline instead of plain <hr/> sectioning

fix #279
refactor existing tests and adjust code to properly support the new sections in the mdast

fix #279
@@ -158,9 +157,9 @@ function getmetadata({ content }, { logger }) {

const img = sections.filter(section => section.image)[0];

content.meta = empty(sections) ? {} : sections[0].meta;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

sections will never be empty as we fall back to the mdast node

Copy link
Contributor

@trieloff trieloff left a comment

Choose a reason for hiding this comment

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

@ramboz merge when ready.

@trieloff
Copy link
Contributor

@davidnuescheler
Copy link
Contributor

nice find @trieloff , of course that one didn't work yet.

i am really looking forward to having this implemented, looks great to me.

BREAKING CHANGE: section types are moved to the sectio's meta object

fix #279
@ramboz
Copy link
Contributor Author

ramboz commented Jun 28, 2019

After a quite lengthy discussion with @davidnuescheler, the conclusion is:

  1. use a plain <div/> to wrap the section content. can be overridden with the tagname YAML property
  2. use a default hlx-section class, but custom class can be added via YAML property
  3. all valid HTML attributes in a YAML block are added as-is on the section element. Non-valid attributes are set as data-<attribute> instead.
    ---
    title: foo
    bar: baz
    ---
    becomes
    <div class="hlx-section" title="foo" data-bar="baz" ></div>
  4. Section types (i.e. has-image is-image-only …) are moved back to the MDAST meta object (instead of directly on the meta). And exposed in the resulting DOM as data-hlx-types (edited)
  5. Pipeline after step removes all hlx-* classes and data-hlx-* attributes in production code

@ramboz
Copy link
Contributor Author

ramboz commented Jun 28, 2019

@trieloff As this requires changes in the IT tests in the cli, I'm not sure how to link the 2 branches together so the tests are passing. Any suggestion?

@trieloff
Copy link
Contributor

@ramboz proceed carefully. Merge this branch, knowing that the smoke tests fail (and make sure they only fail in places you expect) then merge the fix in CLI.

@ramboz
Copy link
Contributor Author

ramboz commented Jul 1, 2019

@trieloff Sounds good. Would have been great if the smoke test was smart enough to run from the same named branch instead of master in that case.

Anyway, haven't merged directly here before. Anything special in the procedure, or can I just go ahead and squash-merge, then update cli accordingly?

@tripodsan
Copy link
Contributor

just go ahead and squash-merge, then update cli accordingly?

yes.

@ramboz ramboz merged commit 27ad875 into master Jul 5, 2019
@ramboz ramboz deleted the issues/279 branch July 5, 2019 17:06
adobe-bot pushed a commit that referenced this pull request Jul 5, 2019
# [4.0.0](v3.7.4...v4.0.0) (2019-07-05)

### Features

* **html pipe:** Default pipeline should include <section/>s ([#379](#379)) ([27ad875](27ad875)), closes [adobe/helix-cli#1037](adobe/helix-cli#1037) [#279](#279)

### BREAKING CHANGES

* **html pipe:** - Remove `context.content.sections` and move the sections directly under
`context.content.mdast`
- Adjust json schemas accordingly
- Move the section yaml meta info to `<node>.meta`
- Move the section types to the mdast `<node>.meta.types`
@adobe-bot
Copy link

🎉 This PR is included in version 4.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Default pipeline should include <section/>s
6 participants