refactor(core/custom-elements): run like regular plugins

This commit is contained in:
Sid Vishnoi 2021-02-19 21:05:38 +05:30
parent 8e82f29b98
commit dc17c275b5
6 changed files with 54 additions and 68 deletions

View File

@ -48,7 +48,7 @@ const modules = [
import("../src/core/data-type.js"),
import("../src/core/algorithms.js"),
import("../src/core/anchor-expander.js"),
import("../src/core/custom-elements/index.js"),
import("../src/core/custom-elements/rs-changelog.js"),
/* Linter must be the last thing to run */
import("../src/core/linter.js"),
];

View File

@ -79,7 +79,7 @@ const modules = [
import("../src/core/data-type.js"),
import("../src/core/algorithms.js"),
import("../src/core/anchor-expander.js"),
import("../src/core/custom-elements/index.js"),
import("../src/core/custom-elements/rs-changelog.js"),
/* Linter must be the last thing to run */
import("../src/core/linter.js"),
import("../src/core/a11y.js"),

View File

@ -63,7 +63,7 @@ const modules = [
import("../src/core/data-type.js"),
import("../src/core/algorithms.js"),
import("../src/core/anchor-expander.js"),
import("../src/core/custom-elements/index.js"),
import("../src/core/custom-elements/rs-changelog.js"),
/* Linters must be the last thing to run */
import("../src/core/linter.js"),
import("../src/core/a11y.js"),

View File

@ -1,34 +0,0 @@
// @ts-check
/**
* Registers custom elements and waits for them to finish their processing.
*
* Every custom element file exports:
* - `name`: registered name of the custom element, prefixed with `rs-`.
* - `element`: class defintion of the custom element.
*
* Every custom element must dispatch a CustomEvent 'done' that tells the
* element has finished its processing, with or without errors.
*
* @typedef {{ name: string, element: CustomElementConstructor }} CustomElementDfn
*/
import * as changelog from "./rs-changelog.js";
/** @type {CustomElementDfn[]} */
const CUSTOM_ELEMENTS = [changelog];
export const name = "core/custom-elements/index";
export async function run() {
// prepare and register elements
CUSTOM_ELEMENTS.forEach(el => {
customElements.define(el.name, el.element);
});
// wait for each element to be ready
const selectors = CUSTOM_ELEMENTS.map(el => el.name).join(", ");
const elems = document.querySelectorAll(selectors);
const readyPromises = [...elems].map(
el => new Promise(res => el.addEventListener("done", res, { once: true }))
);
await Promise.all(readyPromises);
}

View File

@ -7,13 +7,44 @@
*
* @typedef {{message: string, hash: string}} Commit
*/
import { github } from "../github.js";
import { html } from "../import-maps.js";
import { showError } from "../utils.js";
export const name = "rs-changelog";
export const name = "core/custom-elements/rs-changelog";
const customElementName = "rs-changelog";
export const element = class ChangelogElement extends HTMLElement {
export async function run(conf) {
/** @type {NodeListOf<HTMLElement>} */
const elems = document.querySelectorAll(customElementName);
if (!elems.length) return;
const github = conf.github;
if (!github) {
const msg = "`respecConfig.github` is not set.";
return showError(msg, name);
}
const { apiBase, fullName, repoURL } = github;
elems.forEach(el => {
Object.assign(el.dataset, { apiBase, fullName, repoURL });
});
customElements.define(customElementName, ChangelogElement);
const readyPromises = [...elems].map(
el => new Promise(res => el.addEventListener("done", res, { once: true }))
);
await Promise.all(readyPromises);
// Cleanup
elems.forEach(el => {
delete el.dataset.apiBase;
delete el.dataset.fullName;
delete el.dataset.repoURL;
});
}
class ChangelogElement extends HTMLElement {
constructor() {
super();
this.props = {
@ -24,16 +55,22 @@ export const element = class ChangelogElement extends HTMLElement {
typeof window[this.getAttribute("filter")] === "function"
? window[this.getAttribute("filter")]
: () => true,
// props handled by ReSpec
github: {
apiBase: this.dataset.apiBase,
fullName: this.dataset.fullName,
repoURL: this.dataset.repoURL,
},
};
}
connectedCallback() {
const { from, to, filter } = this.props;
const { from, to, filter, github } = this.props;
html.bind(this)`
<ul>
${{
any: fetchCommits(from, to, filter)
.then(commits => toHTML(commits))
any: fetchCommits(from, to, filter, github)
.then(commits => toHTML(commits, github))
.catch(error => showError(error.message, name, { elements: [this] }))
.finally(() => {
this.dispatchEvent(new CustomEvent("done"));
@ -43,16 +80,12 @@ export const element = class ChangelogElement extends HTMLElement {
</ul>
`;
}
};
}
async function fetchCommits(from, to, filter) {
async function fetchCommits(from, to, filter, gh) {
/** @type {Commit[]} */
let commits;
try {
const gh = await github;
if (!gh) {
throw new Error("`respecConfig.github` is not set");
}
const url = new URL("commits", `${gh.apiBase}/${gh.fullName}/`);
url.searchParams.set("from", from);
url.searchParams.set("to", to);
@ -76,8 +109,8 @@ async function fetchCommits(from, to, filter) {
return commits;
}
async function toHTML(commits) {
const { repoURL } = await github;
async function toHTML(commits, github) {
const { repoURL } = github;
return commits.map(commit => {
const [message, prNumber = null] = commit.message.split(/\(#(\d+)\)/, 2);
const commitURL = `${repoURL}commit/${commit.hash}`;

View File

@ -8,17 +8,6 @@
import { getIntlData, showError, showWarning } from "../core/utils.js";
export const name = "core/github";
let resolveGithubPromise;
let rejectGithubPromise;
/** @type {Promise<{ apiBase: string, fullName: string, branch: string, repoURL: string } | null>} */
export const github = new Promise((resolve, reject) => {
resolveGithubPromise = resolve;
rejectGithubPromise = message => {
showError(message, name);
reject(new Error(message));
};
});
const localizationStrings = {
en: {
file_a_bug: "File a bug",
@ -58,7 +47,6 @@ const l10n = getIntlData(localizationStrings);
export async function run(conf) {
if (!conf.hasOwnProperty("github") || !conf.github) {
// nothing to do, bail out.
resolveGithubPromise(null);
return;
}
if (
@ -68,7 +56,7 @@ export async function run(conf) {
const msg =
"Config option `[github](https://github.com/w3c/respec/wiki/github)` " +
"is missing property `repoURL`.";
rejectGithubPromise(msg);
showError(msg, name);
return;
}
let tempURL = conf.github.repoURL || conf.github;
@ -78,19 +66,19 @@ export async function run(conf) {
ghURL = new URL(tempURL, "https://github.com");
} catch {
const msg = `\`respecConf.github\` is not a valid URL? (${ghURL})`;
rejectGithubPromise(msg);
showError(msg, name);
return;
}
if (ghURL.origin !== "https://github.com") {
const msg = `\`respecConf.github\` must be HTTPS and pointing to GitHub. (${ghURL})`;
rejectGithubPromise(msg);
showError(msg, name);
return;
}
const [org, repo] = ghURL.pathname.split("/").filter(item => item);
if (!org || !repo) {
const msg =
"`respecConf.github` URL needs a path with, for example, w3c/my-spec";
rejectGithubPromise(msg);
showError(msg, name);
return;
}
const branch = conf.github.branch || "gh-pages";
@ -143,7 +131,6 @@ export async function run(conf) {
apiBase: githubAPI,
fullName: `${org}/${repo}`,
};
resolveGithubPromise(normalizedGHObj);
const normalizedConfig = {
...newProps,