From ecc931a162d566be3d8838956f2805ee5ba62421 Mon Sep 17 00:00:00 2001 From: Muffin Date: Tue, 22 Aug 2023 14:57:36 -0500 Subject: [PATCH] Run prettier on the development server (#813 - part 3) --- .prettierignore | 1 - development/build-production.js | 8 +- development/builder.js | 308 ++++++++++++++---------- development/colors.js | 10 +- development/compatibility-aliases.js | 16 +- development/parse-extension-metadata.js | 32 +-- development/render-docs.js | 41 ++-- development/render-template.js | 6 +- development/server.js | 37 +-- development/validate.js | 20 +- 10 files changed, 279 insertions(+), 200 deletions(-) diff --git a/.prettierignore b/.prettierignore index 0794b57987..0a39a3b587 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,4 @@ build -development images licenses website diff --git a/development/build-production.js b/development/build-production.js index c4664ac017..39f50abffe 100644 --- a/development/build-production.js +++ b/development/build-production.js @@ -1,9 +1,9 @@ -const pathUtil = require('path'); -const Builder = require('./builder'); +const pathUtil = require("path"); +const Builder = require("./builder"); -const outputDirectory = pathUtil.join(__dirname, '..', 'build'); +const outputDirectory = pathUtil.join(__dirname, "..", "build"); -const builder = new Builder('production'); +const builder = new Builder("production"); const build = builder.build(); build.export(outputDirectory); diff --git a/development/builder.js b/development/builder.js index 0358fb76d1..2ca29d13c4 100644 --- a/development/builder.js +++ b/development/builder.js @@ -1,8 +1,8 @@ -const fs = require('fs'); -const pathUtil = require('path'); -const compatibilityAliases = require('./compatibility-aliases'); -const parseMetadata = require('./parse-extension-metadata'); -const featuredExtensionSlugs = require('../extensions/extensions.json'); +const fs = require("fs"); +const pathUtil = require("path"); +const compatibilityAliases = require("./compatibility-aliases"); +const parseMetadata = require("./parse-extension-metadata"); +const featuredExtensionSlugs = require("../extensions/extensions.json"); /** * @typedef {'development'|'production'|'desktop'} Mode @@ -17,14 +17,17 @@ const featuredExtensionSlugs = require('../extensions/extensions.json'); const recursiveReadDirectory = (directory) => { const result = []; for (const name of fs.readdirSync(directory)) { - if (name.startsWith('.')) { + if (name.startsWith(".")) { // Ignore .eslintrc.js, .DS_Store, etc. continue; } const absolutePath = pathUtil.join(directory, name); const stat = fs.statSync(absolutePath); if (stat.isDirectory()) { - for (const [relativeToChildName, childAbsolutePath] of recursiveReadDirectory(absolutePath)) { + for (const [ + relativeToChildName, + childAbsolutePath, + ] of recursiveReadDirectory(absolutePath)) { // This always needs to use / on all systems result.push([`${name}/${relativeToChildName}`, childAbsolutePath]); } @@ -36,39 +39,39 @@ const recursiveReadDirectory = (directory) => { }; class BuildFile { - constructor (source) { + constructor(source) { this.sourcePath = source; } - getType () { + getType() { return pathUtil.extname(this.sourcePath); } - getLastModified () { + getLastModified() { return fs.statSync(this.sourcePath).mtimeMs; } - read () { + read() { return fs.readFileSync(this.sourcePath); } - validate () { + validate() { // no-op by default } } class ExtensionFile extends BuildFile { - constructor (absolutePath, featured) { + constructor(absolutePath, featured) { super(absolutePath); this.featured = featured; } - getMetadata () { - const data = fs.readFileSync(this.sourcePath, 'utf-8'); + getMetadata() { + const data = fs.readFileSync(this.sourcePath, "utf-8"); return parseMetadata(data); } - validate () { + validate() { if (!this.featured) { return; } @@ -76,36 +79,47 @@ class ExtensionFile extends BuildFile { const metadata = this.getMetadata(); if (!metadata.id) { - throw new Error('Missing // ID:'); + throw new Error("Missing // ID:"); } if (!metadata.name) { - throw new Error('Missing // Name:'); + throw new Error("Missing // Name:"); } if (!metadata.description) { - throw new Error('Missing // Description:'); + throw new Error("Missing // Description:"); } - const PUNCTUATION = ['.', '!', '?']; - if (!PUNCTUATION.some((punctuation) => metadata.description.endsWith(punctuation))) { - throw new Error(`Description is missing punctuation: ${metadata.description}`); + const PUNCTUATION = [".", "!", "?"]; + if ( + !PUNCTUATION.some((punctuation) => + metadata.description.endsWith(punctuation) + ) + ) { + throw new Error( + `Description is missing punctuation: ${metadata.description}` + ); } for (const person of [...metadata.by, ...metadata.original]) { if (!person.name) { - throw new Error('Person is missing name'); + throw new Error("Person is missing name"); } - if (person.link && !person.link.startsWith('https://scratch.mit.edu/users/')) { - throw new Error(`Link for ${person.name} does not point to a Scratch user`); + if ( + person.link && + !person.link.startsWith("https://scratch.mit.edu/users/") + ) { + throw new Error( + `Link for ${person.name} does not point to a Scratch user` + ); } } } } class HomepageFile extends BuildFile { - constructor (extensionFiles, extensionImages, mode) { - super(pathUtil.join(__dirname, 'homepage-template.ejs')); + constructor(extensionFiles, extensionImages, mode) { + super(pathUtil.join(__dirname, "homepage-template.ejs")); /** @type {Record} */ this.extensionFiles = extensionFiles; @@ -116,33 +130,40 @@ class HomepageFile extends BuildFile { /** @type {Mode} */ this.mode = mode; - this.host = mode === 'development' ? 'http://localhost:8000/' : 'https://extensions.turbowarp.org/'; + this.host = + mode === "development" + ? "http://localhost:8000/" + : "https://extensions.turbowarp.org/"; } - getType () { - return '.html'; + getType() { + return ".html"; } - getFullExtensionURL (extensionSlug) { + getFullExtensionURL(extensionSlug) { return `${this.host}${extensionSlug}.js`; } - getRunExtensionURL (extensionSlug) { - return `https://turbowarp.org/editor?extension=${this.getFullExtensionURL(extensionSlug)}`; + getRunExtensionURL(extensionSlug) { + return `https://turbowarp.org/editor?extension=${this.getFullExtensionURL( + extensionSlug + )}`; } - read () { - const renderTemplate = require('./render-template'); + read() { + const renderTemplate = require("./render-template"); const mostRecentExtensions = Object.entries(this.extensionFiles) .sort((a, b) => b[1].getLastModified() - a[1].getLastModified()) .slice(0, 5) .map((i) => i[0]); - const extensionMetadata = Object.fromEntries(featuredExtensionSlugs.map((id) => [ - id, - this.extensionFiles[id].getMetadata() - ])); + const extensionMetadata = Object.fromEntries( + featuredExtensionSlugs.map((id) => [ + id, + this.extensionFiles[id].getMetadata(), + ]) + ); return renderTemplate(this.sourcePath, { mode: this.mode, @@ -150,13 +171,13 @@ class HomepageFile extends BuildFile { extensionImages: this.extensionImages, extensionMetadata, getFullExtensionURL: this.getFullExtensionURL.bind(this), - getRunExtensionURL: this.getRunExtensionURL.bind(this) + getRunExtensionURL: this.getRunExtensionURL.bind(this), }); } } class JSONMetadataFile extends BuildFile { - constructor (extensionFiles, extensionImages) { + constructor(extensionFiles, extensionImages) { super(null); /** @type {Record} */ @@ -166,11 +187,11 @@ class JSONMetadataFile extends BuildFile { this.extensionImages = extensionImages; } - getType () { - return '.json'; + getType() { + return ".json"; } - read () { + read() { const extensions = []; for (const extensionSlug of featuredExtensionSlugs) { const extension = {}; @@ -196,29 +217,35 @@ class JSONMetadataFile extends BuildFile { } const data = { - extensions + extensions, }; return JSON.stringify(data); } } class ImageFile extends BuildFile { - validate () { - const sizeOfImage = require('image-size'); + validate() { + const sizeOfImage = require("image-size"); const contents = this.read(); - const {width, height} = sizeOfImage(contents); + const { width, height } = sizeOfImage(contents); const aspectRatio = width / height; if (aspectRatio !== 2) { - throw new Error(`Aspect ratio must be exactly 2, but found ${aspectRatio.toFixed(4)} (${width}x${height})`); + throw new Error( + `Aspect ratio must be exactly 2, but found ${aspectRatio.toFixed( + 4 + )} (${width}x${height})` + ); } } } class SVGFile extends ImageFile { - validate () { + validate() { const contents = this.read(); - if (contents.includes(' elements -- please convert the text to a path. This ensures it will display correctly on all devices.'); + if (contents.includes(" elements -- please convert the text to a path. This ensures it will display correctly on all devices." + ); } super.validate(); @@ -226,75 +253,80 @@ class SVGFile extends ImageFile { } class SitemapFile extends BuildFile { - constructor (build) { + constructor(build) { super(null); this.build = build; } - getType () { - return '.xml'; + getType() { + return ".xml"; } - read () { - let xml = ''; + read() { + let xml = ""; xml += '\n'; xml += '\n'; xml += Object.keys(this.build.files) - .filter(file => file.endsWith('.html')) - .map(file => file.replace('index.html', '').replace('.html', '')) + .filter((file) => file.endsWith(".html")) + .map((file) => file.replace("index.html", "").replace(".html", "")) .sort((a, b) => { if (a.length < b.length) return -1; if (a.length > b.length) return 1; return a - b; }) - .map(path => `https://extensions.turbowarp.org${path}`) - .map(absoluteURL => `${absoluteURL}`) - .join('\n'); + .map((path) => `https://extensions.turbowarp.org${path}`) + .map((absoluteURL) => `${absoluteURL}`) + .join("\n"); - xml += '\n'; + xml += "\n"; return xml; } } const IMAGE_FORMATS = new Map(); -IMAGE_FORMATS.set('.png', ImageFile); -IMAGE_FORMATS.set('.jpg', ImageFile); -IMAGE_FORMATS.set('.svg', SVGFile); +IMAGE_FORMATS.set(".png", ImageFile); +IMAGE_FORMATS.set(".jpg", ImageFile); +IMAGE_FORMATS.set(".svg", SVGFile); class DocsFile extends BuildFile { - constructor (absolutePath, extensionSlug) { + constructor(absolutePath, extensionSlug) { super(absolutePath); this.extensionSlug = extensionSlug; } - read () { - const renderDocs = require('./render-docs'); - const markdown = super.read().toString('utf-8'); + read() { + const renderDocs = require("./render-docs"); + const markdown = super.read().toString("utf-8"); return renderDocs(markdown, this.extensionSlug); } - getType () { - return '.html'; + getType() { + return ".html"; } } class Build { - constructor () { + constructor() { this.files = {}; } - getFile (path) { - return this.files[path] || this.files[`${path}.html`] || this.files[`${path}index.html`] || null; + getFile(path) { + return ( + this.files[path] || + this.files[`${path}.html`] || + this.files[`${path}index.html`] || + null + ); } - export (root) { + export(root) { try { fs.rmSync(root, { - recursive: true + recursive: true, }); } catch (e) { - if (e.code !== 'ENOENT') { + if (e.code !== "ENOENT") { throw e; } } @@ -302,7 +334,7 @@ class Build { for (const [relativePath, file] of Object.entries(this.files)) { const directoryName = pathUtil.dirname(relativePath); fs.mkdirSync(pathUtil.join(root, directoryName), { - recursive: true + recursive: true, }); fs.writeFileSync(pathUtil.join(root, relativePath), file.read()); } @@ -313,34 +345,36 @@ class Builder { /** * @param {Mode} mode */ - constructor (mode) { - if (process.argv.includes('--production')) { - this.mode = 'production'; - } else if (process.argv.includes('--development')) { - this.mode = 'development'; - } else if (process.argv.includes('--desktop')) { - this.mode = 'desktop'; + constructor(mode) { + if (process.argv.includes("--production")) { + this.mode = "production"; + } else if (process.argv.includes("--development")) { + this.mode = "development"; + } else if (process.argv.includes("--desktop")) { + this.mode = "desktop"; } else { /** @type {Mode} */ this.mode = mode; } - this.extensionsRoot = pathUtil.join(__dirname, '../extensions'); - this.websiteRoot = pathUtil.join(__dirname, '../website'); - this.imagesRoot = pathUtil.join(__dirname, '../images'); - this.docsRoot = pathUtil.join(__dirname, '../docs'); + this.extensionsRoot = pathUtil.join(__dirname, "../extensions"); + this.websiteRoot = pathUtil.join(__dirname, "../website"); + this.imagesRoot = pathUtil.join(__dirname, "../images"); + this.docsRoot = pathUtil.join(__dirname, "../docs"); } - build () { + build() { const build = new Build(this.mode); /** @type {Record} */ const extensionFiles = {}; - for (const [filename, absolutePath] of recursiveReadDirectory(this.extensionsRoot)) { - if (!filename.endsWith('.js')) { + for (const [filename, absolutePath] of recursiveReadDirectory( + this.extensionsRoot + )) { + if (!filename.endsWith(".js")) { continue; } - const extensionSlug = filename.split('.')[0]; + const extensionSlug = filename.split(".")[0]; const featured = featuredExtensionSlugs.includes(extensionSlug); const file = new ExtensionFile(absolutePath, featured); extensionFiles[extensionSlug] = file; @@ -349,40 +383,59 @@ class Builder { /** @type {Record} */ const extensionImages = {}; - for (const [filename, absolutePath] of recursiveReadDirectory(this.imagesRoot)) { + for (const [filename, absolutePath] of recursiveReadDirectory( + this.imagesRoot + )) { const extension = pathUtil.extname(filename); const ImageFileClass = IMAGE_FORMATS.get(extension); if (!ImageFileClass) { continue; } - const extensionSlug = filename.split('.')[0]; - if (extensionSlug !== 'unknown') { + const extensionSlug = filename.split(".")[0]; + if (extensionSlug !== "unknown") { extensionImages[extensionSlug] = `images/${filename}`; } build.files[`/images/${filename}`] = new ImageFileClass(absolutePath); } - if (this.mode !== 'desktop') { - for (const [filename, absolutePath] of recursiveReadDirectory(this.websiteRoot)) { + if (this.mode !== "desktop") { + for (const [filename, absolutePath] of recursiveReadDirectory( + this.websiteRoot + )) { build.files[`/${filename}`] = new BuildFile(absolutePath); } - for (const [filename, absolutePath] of recursiveReadDirectory(this.docsRoot)) { - if (!filename.endsWith('.md')) { + for (const [filename, absolutePath] of recursiveReadDirectory( + this.docsRoot + )) { + if (!filename.endsWith(".md")) { continue; } - const extensionSlug = filename.split('.')[0]; - build.files[`/${extensionSlug}.html`] = new DocsFile(absolutePath, extensionSlug); + const extensionSlug = filename.split(".")[0]; + build.files[`/${extensionSlug}.html`] = new DocsFile( + absolutePath, + extensionSlug + ); } - const scratchblocksPath = pathUtil.join(__dirname, '../node_modules/scratchblocks/build/scratchblocks.min.js'); - build.files['/docs-internal/scratchblocks.js'] = new BuildFile(scratchblocksPath); - - build.files['/index.html'] = new HomepageFile(extensionFiles, extensionImages, this.mode); - build.files['/sitemap.xml'] = new SitemapFile(build); + const scratchblocksPath = pathUtil.join( + __dirname, + "../node_modules/scratchblocks/build/scratchblocks.min.js" + ); + build.files["/docs-internal/scratchblocks.js"] = new BuildFile( + scratchblocksPath + ); + + build.files["/index.html"] = new HomepageFile( + extensionFiles, + extensionImages, + this.mode + ); + build.files["/sitemap.xml"] = new SitemapFile(build); } - build.files['/generated-metadata/extensions-v0.json'] = new JSONMetadataFile(extensionFiles, extensionImages); + build.files["/generated-metadata/extensions-v0.json"] = + new JSONMetadataFile(extensionFiles, extensionImages); for (const [oldPath, newPath] of Object.entries(compatibilityAliases)) { build.files[oldPath] = build.files[newPath]; @@ -391,7 +444,7 @@ class Builder { return build; } - tryBuild (...args) { + tryBuild(...args) { const start = new Date(); process.stdout.write(`[${start.toLocaleTimeString()}] Building... `); @@ -401,30 +454,35 @@ class Builder { console.log(`done in ${time}ms`); return build; } catch (error) { - console.log('error'); + console.log("error"); console.error(error); } return null; } - startWatcher (callback) { + startWatcher(callback) { // Load chokidar lazily. - const chokidar = require('chokidar'); + const chokidar = require("chokidar"); callback(this.tryBuild()); - chokidar.watch([ - `${this.extensionsRoot}/**/*`, - `${this.imagesRoot}/**/*`, - `${this.websiteRoot}/**/*`, - `${this.docsRoot}/**/*`, - ], { - ignoreInitial: true - }).on('all', () => { - callback(this.tryBuild()); - }); + chokidar + .watch( + [ + `${this.extensionsRoot}/**/*`, + `${this.imagesRoot}/**/*`, + `${this.websiteRoot}/**/*`, + `${this.docsRoot}/**/*`, + ], + { + ignoreInitial: true, + } + ) + .on("all", () => { + callback(this.tryBuild()); + }); } - validate () { + validate() { const errors = []; const build = this.build(); for (const [fileName, file] of Object.entries(build.files)) { @@ -433,7 +491,7 @@ class Builder { } catch (e) { errors.push({ fileName, - error: e + error: e, }); } } diff --git a/development/colors.js b/development/colors.js index 6dc21194d1..7e6fa1eaa8 100644 --- a/development/colors.js +++ b/development/colors.js @@ -1,9 +1,9 @@ const enableColor = !process.env.NO_COLOR; -const color = (i) => enableColor ? i : ''; +const color = (i) => (enableColor ? i : ""); module.exports = { - RESET: color('\x1b[0m'), - BOLD: color('\x1b[1m'), - RED: color('\x1b[31m'), - GREEN: color('\x1b[32m') + RESET: color("\x1b[0m"), + BOLD: color("\x1b[1m"), + RED: color("\x1b[31m"), + GREEN: color("\x1b[32m"), }; diff --git a/development/compatibility-aliases.js b/development/compatibility-aliases.js index a3302ea292..e1722787fa 100644 --- a/development/compatibility-aliases.js +++ b/development/compatibility-aliases.js @@ -1,13 +1,13 @@ const extensions = { // maps old path to new path - '/LukeManiaStudios/ClonesPlus.js': '/Lily/ClonesPlus.js', - '/LukeManiaStudios/CommentBlocks.js': '/Lily/CommentBlocks.js', - '/LukeManiaStudios/lmsutils.js': '/Lily/lmsutils.js', - '/LukeManiaStudios/LooksPlus.js': '/Lily/LooksPlus.js', - '/LukeManiaStudios/McUtils.js': '/Lily/McUtils.js', - '/LukeManiaStudios/MoreTimers.js': '/Lily/MoreTimers.js', - '/LukeManiaStudios/TempVariables.js': '/Lily/TempVariables.js', - '/LukeManiaStudios/TempVariables2.js': '/Lily/TempVariables2.js' + "/LukeManiaStudios/ClonesPlus.js": "/Lily/ClonesPlus.js", + "/LukeManiaStudios/CommentBlocks.js": "/Lily/CommentBlocks.js", + "/LukeManiaStudios/lmsutils.js": "/Lily/lmsutils.js", + "/LukeManiaStudios/LooksPlus.js": "/Lily/LooksPlus.js", + "/LukeManiaStudios/McUtils.js": "/Lily/McUtils.js", + "/LukeManiaStudios/MoreTimers.js": "/Lily/MoreTimers.js", + "/LukeManiaStudios/TempVariables.js": "/Lily/TempVariables.js", + "/LukeManiaStudios/TempVariables2.js": "/Lily/TempVariables2.js", }; module.exports = extensions; diff --git a/development/parse-extension-metadata.js b/development/parse-extension-metadata.js index 2d2defc683..632f01216c 100644 --- a/development/parse-extension-metadata.js +++ b/development/parse-extension-metadata.js @@ -1,12 +1,12 @@ class Person { - constructor (name, link) { + constructor(name, link) { /** @type {string} */ this.name = name; /** @type {string|null} */ this.link = link; } - toHTML () { + toHTML() { // Don't need to bother escaping here. There's no vulnerability. if (this.link) { return `${this.name}`; @@ -16,10 +16,10 @@ class Person { } class Extension { - constructor () { - this.id = ''; - this.name = ''; - this.description = ''; + constructor() { + this.id = ""; + this.name = ""; + this.description = ""; /** @type {Person[]} */ this.by = []; /** @type {Person[]} */ @@ -45,13 +45,13 @@ const splitFirst = (string, split) => { * @returns {Person} */ const parsePerson = (person) => { - const parts = splitFirst(person, '<'); + const parts = splitFirst(person, "<"); if (parts.length === 1) { return new Person(person, null); } const name = parts[0].trim(); - const link = parts[1].replace('>', ''); + const link = parts[1].replace(">", ""); return new Person(name, link); }; @@ -62,14 +62,14 @@ const parsePerson = (person) => { const parseMetadata = (extensionCode) => { const metadata = new Extension(); - for (const line of extensionCode.split('\n')) { - if (!line.startsWith('//')) { + for (const line of extensionCode.split("\n")) { + if (!line.startsWith("//")) { // End of header. break; } const withoutComment = line.substring(2).trim(); - const parts = splitFirst(withoutComment, ':'); + const parts = splitFirst(withoutComment, ":"); if (parts.length === 1) { // Invalid. continue; @@ -79,19 +79,19 @@ const parseMetadata = (extensionCode) => { const value = parts[1].trim(); switch (key) { - case 'id': + case "id": metadata.id = value; break; - case 'name': + case "name": metadata.name = value; break; - case 'description': + case "description": metadata.description = value; break; - case 'by': + case "by": metadata.by.push(parsePerson(value)); break; - case 'original': + case "original": metadata.original.push(parsePerson(value)); break; default: diff --git a/development/render-docs.js b/development/render-docs.js index b882596354..3bdcfab88e 100644 --- a/development/render-docs.js +++ b/development/render-docs.js @@ -1,24 +1,28 @@ -const path = require('path'); -const MarkdownIt = require('markdown-it'); -const renderTemplate = require('./render-template'); +const path = require("path"); +const MarkdownIt = require("markdown-it"); +const renderTemplate = require("./render-template"); const md = new MarkdownIt({ html: true, linkify: true, - breaks: true + breaks: true, }); md.renderer.rules.fence = function (tokens, idx, options, env, self) { const token = tokens[idx]; - if (token.info === 'scratch') { + if (token.info === "scratch") { env.usesScratchBlocks = true; - return `
${md.utils.escapeHtml(token.content)}
`; + return `
${md.utils.escapeHtml( + token.content + )}
`; } // By default markdown-it will use a strange combination of and
; we'd rather it
   // just use 
-  return `
${md.utils.escapeHtml(token.content)}
`; + return `
${md.utils.escapeHtml(token.content)}
`; }; /** @@ -31,12 +35,19 @@ const renderDocs = (markdownSource, slug) => { const tokens = md.parse(markdownSource, env); // Extract the header - let headerHTML = '## file did not contain header ##'; + let headerHTML = "## file did not contain header ##"; let headerText = headerHTML; - const headerStart = tokens.findIndex((token) => token.type === 'heading_open' && token.tag === 'h1'); - const headerEnd = tokens.findIndex((token) => token.type === 'heading_close' && token.tag === 'h1'); + const headerStart = tokens.findIndex( + (token) => token.type === "heading_open" && token.tag === "h1" + ); + const headerEnd = tokens.findIndex( + (token) => token.type === "heading_close" && token.tag === "h1" + ); if (headerStart !== -1 && headerEnd !== -1) { - const headerTokens = tokens.splice(headerStart, headerEnd - headerStart + 1); + const headerTokens = tokens.splice( + headerStart, + headerEnd - headerStart + 1 + ); // Discard the header tokens themselves, but render the HTML title with any formatting headerTokens.shift(); @@ -44,18 +55,20 @@ const renderDocs = (markdownSource, slug) => { headerHTML = md.renderer.render(headerTokens, md.options, env); // We also need a no-formatting version for the title - const justTextTokens = headerTokens.filter(token => token.type === 'inline'); + const justTextTokens = headerTokens.filter( + (token) => token.type === "inline" + ); headerText = md.renderer.render(justTextTokens, md.options, env); } const bodyHTML = md.renderer.render(tokens, md.options, env); - return renderTemplate(path.join(__dirname, 'docs-template.ejs'), { + return renderTemplate(path.join(__dirname, "docs-template.ejs"), { slug, headerHTML, headerText, bodyHTML, - usesScratchBlocks: !!env.usesScratchBlocks + usesScratchBlocks: !!env.usesScratchBlocks, }); }; diff --git a/development/render-template.js b/development/render-template.js index fe8afd689d..41f036b4d1 100644 --- a/development/render-template.js +++ b/development/render-template.js @@ -1,10 +1,10 @@ -const fs = require('fs'); -const ejs = require('ejs'); +const fs = require("fs"); +const ejs = require("ejs"); // TODO: Investigate the value of removing dependency on `ejs` and possibly writing our own DSL. const renderTemplate = (path, data) => { - const inputEJS = fs.readFileSync(path, 'utf-8'); + const inputEJS = fs.readFileSync(path, "utf-8"); const outputHTML = ejs.render(inputEJS, data); return outputHTML; }; diff --git a/development/server.js b/development/server.js index e0bdfee855..875d6f6b8f 100644 --- a/development/server.js +++ b/development/server.js @@ -1,46 +1,49 @@ -const express = require('express'); -const Builder = require('./builder'); +const express = require("express"); +const Builder = require("./builder"); let mostRecentBuild = null; -const builder = new Builder('development'); +const builder = new Builder("development"); builder.startWatcher((newBuild) => { mostRecentBuild = newBuild; }); const app = express(); -app.set('strict routing', true); -app.set('x-powered-by', false); +app.set("strict routing", true); +app.set("x-powered-by", false); app.use((req, res, next) => { // If we don't tell the browser not to cache files, it does by default, and people will get confused when // script changes aren't being applied if they don't do a reload without cache. - res.setHeader('Cache-Control', 'no-store'); - res.setHeader('Pragma', 'no-cache'); + res.setHeader("Cache-Control", "no-store"); + res.setHeader("Pragma", "no-cache"); // Prevent browser from trying to guess file types. - res.setHeader('X-Content-Type-Options', 'nosniff'); + res.setHeader("X-Content-Type-Options", "nosniff"); // We don't want this site to be embedded in frames. - res.setHeader('X-Frame-Options', 'DENY'); + res.setHeader("X-Frame-Options", "DENY"); // No need to leak Referer headers. - res.setHeader('Referrer-Policy', 'no-referrer'); + res.setHeader("Referrer-Policy", "no-referrer"); // We want all resources used by the website to be local. // This CSP does *not* apply to the extensions, just the website. - res.setHeader('Content-Security-Policy', "default-src 'self' 'unsafe-inline' data: blob:"); + res.setHeader( + "Content-Security-Policy", + "default-src 'self' 'unsafe-inline' data: blob:" + ); // Allows loading cross-origin example images and matches GitHub pages. - res.setHeader('Access-Control-Allow-Origin', '*'); + res.setHeader("Access-Control-Allow-Origin", "*"); next(); }); -app.get('/*', (req, res, next) => { +app.get("/*", (req, res, next) => { if (!mostRecentBuild) { - res.contentType('text/plain'); + res.contentType("text/plain"); res.status(500); - res.send('Build Failed; See Console'); + res.send("Build Failed; See Console"); return; } @@ -54,9 +57,9 @@ app.get('/*', (req, res, next) => { }); app.use((req, res) => { - res.contentType('text/plain'); + res.contentType("text/plain"); res.status(404); - res.send('404 Not Found'); + res.send("404 Not Found"); }); // The port the server runs on matters. The editor only treats port 8000 as unsandboxed. diff --git a/development/validate.js b/development/validate.js index e9386baebe..64bf9496ab 100644 --- a/development/validate.js +++ b/development/validate.js @@ -1,16 +1,22 @@ -const Builder = require('./builder'); -const Colors = require('./colors'); +const Builder = require("./builder"); +const Colors = require("./colors"); -const builder = new Builder('production'); +const builder = new Builder("production"); const errors = builder.validate(); if (errors.length === 0) { - console.log(`${Colors.GREEN}${Colors.BOLD}Validation checks passed.${Colors.RESET}`); + console.log( + `${Colors.GREEN}${Colors.BOLD}Validation checks passed.${Colors.RESET}` + ); process.exit(0); } else { - console.error(`${Colors.RED}${Colors.BOLD}${errors.length} ${errors.length === 1 ? 'file' : 'files'} failed validation.${Colors.RESET}`); - console.error(''); - for (const {fileName, error} of errors) { + console.error( + `${Colors.RED}${Colors.BOLD}${errors.length} ${ + errors.length === 1 ? "file" : "files" + } failed validation.${Colors.RESET}` + ); + console.error(""); + for (const { fileName, error } of errors) { console.error(`${Colors.BOLD}${fileName}${Colors.RESET}: ${error}`); } console.error(``);