Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Static further reading links #15890

Merged
merged 5 commits into from May 20, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions .eslintrc.js
Expand Up @@ -74,6 +74,12 @@ module.exports = {
"internal-rules/multiline-comment-style": "error"
},
overrides: [
{
files: ["tools/*.js"],
rules: {
"no-console": "off"
}
},
{
files: ["lib/rules/*", "tools/internal-rules/*"],
excludedFiles: ["index.js"],
Expand Down
24 changes: 16 additions & 8 deletions docs/.eleventy.js
Expand Up @@ -123,19 +123,27 @@ module.exports = function(eleventyConfig) {
/**********************************************************************
* Shortcodes
* ********************************************************************/
eleventyConfig.addNunjucksAsyncShortcode("link", async function(link) {
const { body: html, url } = await got(link);
const metadata = await metascraper({ html, url });
const the_url = (new URL(link)); // same as url
const domain = the_url.hostname;
eleventyConfig.addNunjucksShortcode("link", function(url) {

const urlData = this.ctx.further_reading_links[url];

if (!urlData) {
throw new Error(`Data missing for ${url}`);
}

const {
domain,
title,
logo
} = urlData;

return `
<article class="resource">
<div class="resource__image">
<img class="resource__img" width="75" height="75" src="${metadata.logo}" alt="Avatar image for ${domain}" />
<img class="resource__img" width="75" height="75" src="${logo}" alt="Avatar image for ${domain}" onerror="this.src = '/icon.svg'" />
nzakas marked this conversation as resolved.
Show resolved Hide resolved
</div>
<div class="resource__content">
<a href="${metadata.url}" class="resource__title"> ${metadata.title} </a><br>
<a href="${url}" class="resource__title"> ${title} </a><br>
<span class="resource__domain"> ${domain}</span>
</div>
<svg class="c-icon resource__icon" width="13" height="12" viewBox="0 0 13 12" fill="none">
Expand Down Expand Up @@ -297,7 +305,7 @@ module.exports = function(eleventyConfig) {
// START, eleventy-img
function imageShortcode(src, alt, cls, sizes = "(max-width: 768px) 100vw, 50vw") {
const source = src;
// console.log(`Generating image(s) from: ${src}`)

let options = {
widths: [600, 900, 1500],
formats: ["webp", "jpeg"],
Expand Down
15 changes: 15 additions & 0 deletions docs/README.md
@@ -0,0 +1,15 @@
# ESLint Documentation

## Run Locally

```shell
npm start
```

## Scripts

To update the links data file:

```shell
npm run update:links
nzakas marked this conversation as resolved.
Show resolved Hide resolved
```
13 changes: 1 addition & 12 deletions docs/package.json
@@ -1,5 +1,5 @@
{
"name": "foundation",
"name": "docs-eslint",
"version": "1.0.0",
"description": "",
"main": "index.js",
Expand Down Expand Up @@ -35,16 +35,5 @@
"rimraf": "^3.0.2",
"sass": "^1.38.0",
"slugify": "^1.6.3"
},
"dependencies": {
"got": "^11.8.3",
"metascraper": "^5.25.7",
"metascraper-description": "^5.25.7",
"metascraper-image": "^5.25.7",
"metascraper-logo": "^5.25.7",
"metascraper-logo-favicon": "^5.25.7",
"metascraper-publisher": "^5.25.7",
"metascraper-title": "^5.25.7",
"metascraper-url": "^5.25.7"
nzakas marked this conversation as resolved.
Show resolved Hide resolved
}
}
688 changes: 688 additions & 0 deletions docs/src/_data/further_reading_links.json

Large diffs are not rendered by default.

11 changes: 3 additions & 8 deletions docs/src/_includes/layouts/doc.html
Expand Up @@ -27,7 +27,9 @@ <h2 id="related-rules">Related Rules</h2>
{% if further_reading %}
{% set further_reading_content %}
<h2 id="further-reading">Further Reading</h2>
{# async shortcodes don't work here so need to manually insert later #}
{% for url in further_reading %}
{% link url %}
{% endfor %}
{% endset %}

{% set all_content = [all_content, further_reading_content] | join %}
Expand All @@ -40,13 +42,6 @@ <h1>{{ title }}</h1>

{{ all_content | safe }}

{# now insert the async-fetched link data if necessary #}
{% if further_reading %}
{% for url in further_reading %}
{% link url %}
{% endfor %}
{% endif %}

<div class="docs-edit-link">
<a href="{{ edit_link }}" class="c-btn c-btn--secondary">Edit this page</a>
</div>
Expand Down
6 changes: 1 addition & 5 deletions docs/src/library/link-card.md
Expand Up @@ -10,10 +10,6 @@ Links can be rendered as cards by using the `link` shortcode. The only required

## Examples

{% link "https://developer.mozilla.org/en-US/docs/Web/JavaScript" %}

{% link "https://github.com/microlinkhq/metascraper" %}

{% link "https://blog.izs.me/2010/12/an-open-letter-to-javascript-leaders-regarding/" %}

{% link "https://humanwhocodes.com/blog/2021/12/making-open-source-project-sponsor-ready-accepting-sponsorships/" %}
{% link "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get" %}
15 changes: 13 additions & 2 deletions package.json
Expand Up @@ -25,14 +25,16 @@
"publish-release": "node Makefile.js publishRelease",
"gensite": "node Makefile.js gensite",
"webpack": "node Makefile.js webpack",
"perf": "node Makefile.js perf"
"perf": "node Makefile.js perf",
"docs:update-links": "node tools/fetch-docs-links.js"
},
"gitHooks": {
"pre-commit": "lint-staged"
},
"lint-staged": {
"*.js": "eslint --fix",
"*.md": "markdownlint --fix"
"*.md": "markdownlint --fix",
"docs/src/rules/*.md": "node tools/fetch-docs-links.js"
},
"files": [
"LICENSE",
Expand Down Expand Up @@ -104,8 +106,11 @@
"eslint-release": "^3.2.0",
"eslump": "^3.0.0",
"esprima": "^4.0.1",
"fast-glob": "^3.2.11",
"fs-teardown": "^0.1.3",
"glob": "^7.1.6",
"got": "^11.8.3",
"gray-matter": "^4.0.3",
"jsdoc": "^3.5.5",
"karma": "^6.1.1",
"karma-chrome-launcher": "^3.1.0",
Expand All @@ -118,6 +123,12 @@
"markdownlint-cli": "^0.30.0",
"marked": "^4.0.8",
"memfs": "^3.0.1",
"metascraper": "^5.25.7",
"metascraper-description": "^5.25.7",
"metascraper-image": "^5.29.3",
"metascraper-logo": "^5.25.7",
"metascraper-logo-favicon": "^5.25.7",
"metascraper-title": "^5.25.7",
"mocha": "^8.3.2",
"mocha-junit-reporter": "^2.0.0",
"node-polyfill-webpack-plugin": "^1.0.3",
Expand Down
112 changes: 112 additions & 0 deletions tools/fetch-docs-links.js
@@ -0,0 +1,112 @@
/**
* @fileoverview Script to fetch link data.
*
* To fetch info about all files:
*
* node tools/fetch-docs-links.js
*
* To fetch info for just selected files (for use with lint-staged):
*
* node tools/fetch-docs-links.js docs/src/user-guide/index.md
*
* @author Nicholas C. Zakas
*/

"use strict";

//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------

const matter = require("gray-matter");
const metascraper = require("metascraper")([
require("metascraper-image")(),
require("metascraper-logo")(),
require("metascraper-logo-favicon")(),
require("metascraper-title")(),
require("metascraper-description")()
]);
const got = require("got");
const path = require("path");
const fs = require("fs/promises");
const glob = require("fast-glob");

//-----------------------------------------------------------------------------
// Data
//-----------------------------------------------------------------------------

const BASE_DIR = path.resolve(__dirname, "../");
const SRC_DIR = path.resolve(BASE_DIR, "docs/src");
const DATA_DIR = path.resolve(SRC_DIR, "_data");
const DATA_FILE_PATH = path.resolve(DATA_DIR, "further_reading_links.json");

// determine which files to check
let filenames = process.argv.slice(2);

if (filenames.length === 0) {
filenames = glob.sync("docs/src/rules/*.md", { cwd: BASE_DIR });
}

filenames = filenames.map(filename => path.resolve(BASE_DIR, filename));

//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------

/**
* Fetches metadata information for a given URL.
* @param {string} url The URL to fetch data for.
* @returns {Promise<object>} An object with metadata info.
*/
async function fetchLinkMeta(url) {
const { body: html } = await got(url);
const metadata = await metascraper({ html, url });
nzakas marked this conversation as resolved.
Show resolved Hide resolved
const domain = (new URL(url)).hostname;

return {
domain,
url,
logo: metadata.logo,
title: metadata.title,
description: metadata.description
};
}


//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------

(async () => {

// First read in the current data file
const links = JSON.parse(await fs.readFile(DATA_FILE_PATH, "utf8"));

// check each file
for (const filename of filenames) {

const text = await fs.readFile(filename, "utf8");
const frontmatter = matter(text).data;

if (frontmatter.further_reading) {

for (const url of frontmatter.further_reading) {
if (!links[url]) {
try {
links[url] = await fetchLinkMeta(url);
} catch (ex) {
console.error("Error in ", filename);
console.error("Could not fetch data for", url);
console.error(ex.message);
console.error(ex.stack);
process.exit(1);
}
}
}

}
}

// Last write new data into the current data file
await fs.writeFile(DATA_FILE_PATH, JSON.stringify(links, null, 4), "utf8");
})();