Skip to content

core(artifacts): unify AnchorElements into single gatherer#7101

Merged
brendankenny merged 8 commits into
masterfrom
anchor_elements
Feb 11, 2019
Merged

core(artifacts): unify AnchorElements into single gatherer#7101
brendankenny merged 8 commits into
masterfrom
anchor_elements

Conversation

@patrickhulce

Copy link
Copy Markdown
Collaborator

Summary
Unifies all our usage of <a> elements under a single AnchorElements gatherer/artifact. Replaces the two other artifacts (AnchorsWithNoRelOpener and CrawableLinks)

Related Issues/PRs
#6747

@@ -33,7 +33,9 @@ class ExternalAnchorsUseRelNoopenerAudit extends Audit {
const warnings = [];
const pageHost = new URL(artifacts.URL.finalUrl).host;
// Filter usages to exclude anchors that are same origin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

move the comment down to the second filter?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

@@ -0,0 +1,77 @@
/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

lot of lint stuff in here :)

const auditResult = ExternalAnchorsAudit.audit({
AnchorElements: [
{href: 'https://other.com/test', target: '_blank', rel: 'nofollow noopener'},
{href: 'https://other.com/test1', target: '_blank', rel: 'noreferrer'},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add one for just noopener as well?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

{href: 'https://example.com/test1'},
AnchorElements: [
{href: 'https://example.com/test', target: '_blank', rel: ''},
{href: 'https://example.com/test1', target: '_blank', rel: ''},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

maybe vary the rel values to give that some exercise?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done

})()`

// We'll use evaluateAsync because the `node.getAttribute` method doesn't actually normalize
// the values like access from JavaScript does.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: this comment seems like it makes more sense before the definition of expression

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

done


return anchorElements.map(node => {
/** @type {HTMLAnchorElement} */
const anchorNode = (node);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

the () thing is a bug in tsc's js support, I think. It's hard to notice the different behavior than without the parens (non-coercive assertion). Can we do inline instead (const anchorNode = /** @type {HTMLAnchorElement} */ (node);) if going this route?

What about an instanceof HTMLAnchorElement check instead, though? No need to cast for type checking in that case, and can do an early return.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

sure sg

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

wdyt about something like

return anchorElements.map(node => {
  // @ts-ignore - put into scope via stringification
  const outerHTML = getOuterHTMLSnippet(node); // eslint-disable-line no-undef

  if (node instanceof HTMLAnchorElement) {
    return {
      href: node.href,
      text: node.innerText,
      rel: node.rel,
      target: node.target,
      outerHTML,
    };
  }

  return {
    href: resolveURLOrEmpty(node.href.baseVal),
    text: node.textContent || '',
    rel: '',
    target: node.target.baseVal || '',
    outerHTML,
  };
});

(as far as I can tell, SVGAElement.href is always a SVGAnimatedString, see SVGAElement implementing SVGURIReference)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

yeah I like it!

const href = (anchorNode.href);
/** @type {SVGAElement} */
const svgNode = (node);
if (href instanceof SVGAnimatedString) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

although considering this is testing the href, maybe there's a reason this isn't doing instanceof against the whole node?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

correct, it can be either or

node.href,
text: node.href instanceof SVGAnimatedString ?
node.textContent :
node.innerText,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

also, do you know why the original code is innerText for HTMLAnchorElement vs textContent for SVGAElement? We should keep it, just seems weird :)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I think we didn't want to return invisible text, IIRC there were some situations where we started sticking large amounts of nonsense text in the table

@brendankenny brendankenny left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, take or leave the suggestion :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants