diff --git a/.cspell.json b/.cspell.json index 95d11dd72..0b277e018 100644 --- a/.cspell.json +++ b/.cspell.json @@ -6,6 +6,7 @@ "badterms", "Beihang", "blocklist", + "capi", "Çelik", "charmod", "CRYD", @@ -14,6 +15,7 @@ "dcterms", "deniak", "DNOTE", + "doasync", "doctypes", "dvcs", "ERCIM", @@ -38,6 +40,7 @@ "linkchecker", "mediacapture", "memsub", + "metaviewport", "middot", "minami", "nodate", diff --git a/.eslintrc.json b/.eslintrc.json index 2029a1383..c11017c59 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,7 +10,9 @@ "global-require": "off", "no-restricted-syntax": "warn", "guard-for-in": "warn", - "prefer-destructuring": "warn" + "prefer-destructuring": "warn", + "import/prefer-default-export": "off", + "import/extensions": "off" }, "overrides": [ { @@ -25,6 +27,10 @@ { "files": ["app.js", "lib/**/*.js", "tools/**/*.js"], "plugins": ["node"], + "parserOptions": { + "ecmaVersion": 2020, + "sourceType": "module" + }, "extends": ["plugin:node/recommended", "plugin:jsdoc/recommended"] }, { @@ -36,7 +42,11 @@ "node/no-unpublished-require": "off" }, "plugins": ["node"], - "extends": "plugin:node/recommended" + "extends": "plugin:node/recommended", + "parserOptions": { + "ecmaVersion": 2022, + "sourceType": "module" + } } ] } diff --git a/app.js b/app.js index e5316630d..a28165a87 100644 --- a/app.js +++ b/app.js @@ -2,7 +2,21 @@ * Main runnable file. */ -'use strict'; +import compression from 'compression'; +import cors from 'cors'; +import express from 'express'; +import http from 'http'; +import insafe from 'insafe'; +import morgan from 'morgan'; +import { Server } from 'socket.io'; +import * as api from './lib/api.js'; +import * as l10n from './lib/l10n.js'; +import { Sink } from './lib/sink.js'; +import { allProfiles, importJSON } from './lib/util.js'; +import { Specberus } from './lib/validator.js'; +import * as views from './lib/views.js'; + +const { version } = importJSON('./package.json', import.meta.url); // Settings: const DEFAULT_PORT = 80; @@ -19,33 +33,13 @@ if (!process.env.BASE_URI || process.env.BASE_URI.length < 1) { ); } -// Native packages: -const http = require('http'); - -// External packages: -const compression = require('compression'); -const express = require('express'); -const insafe = require('insafe'); -const morgan = require('morgan'); -const socket = require('socket.io'); -// Internal packages: -const self = require('./package.json'); -const l10n = require('./lib/l10n'); -const sink = require('./lib/sink'); -const validator = require('./lib/validator'); -const views = require('./lib/views'); -const util = require('./lib/util'); -const api = require('./lib/api'); - const app = express(); const server = http.createServer(app); -const io = socket(server); -const { Sink } = sink; -const { version } = self; +const io = new Server(server); // Middleware: app.use(morgan('combined')); app.use(compression()); -app.use('/badterms.json', require('cors')()); +app.use('/badterms.json', cors()); app.use(express.static('public')); api.setUp(app, process.env.W3C_API_KEY); @@ -61,7 +55,7 @@ io.on('connection', socket => { socket.on('extractMetadata', data => { if (!data.url) return socket.emit('exception', { message: 'URL not provided.' }); - const specberus = new validator.Specberus(process.env.W3C_API_KEY); + const specberus = new Specberus(process.env.W3C_API_KEY); const handler = new Sink(); handler.on('err', (type, data) => { try { @@ -105,26 +99,26 @@ io.on('connection', socket => { events: handler, }); }); - socket.on('validate', data => { + socket.on('validate', async data => { if (!data.url) return socket.emit('exception', { message: 'URL not provided.' }); if (!data.profile) return socket.emit('exception', { message: 'Profile not provided.', }); - const profilePath = util.allProfiles.find(p => + const profilePath = allProfiles.find(p => p.endsWith(`/${data.profile}.js`) ); let profile; try { - // eslint-disable-next-line import/no-dynamic-require - profile = require(`./lib/profiles/${profilePath}`); + // eslint-disable-next-line node/no-unsupported-features/es-syntax + profile = await import(`./lib/profiles/${profilePath}`); } catch (err) { return socket.emit('exception', { message: 'Profile does not exist.', }); } - const specberus = new validator.Specberus(process.env.W3C_API_KEY); + const specberus = new Specberus(process.env.W3C_API_KEY); const handler = new Sink(); const profileCode = profile.name; socket.emit('start', { diff --git a/lib/api.js b/lib/api.js index 3c12b1635..4dc5561c8 100644 --- a/lib/api.js +++ b/lib/api.js @@ -3,13 +3,12 @@ */ // Internal packages: -const self = require('../package.json'); -const sink = require('./sink'); -const util = require('./util'); -const validator = require('./validator'); +import { Sink } from './sink.js'; +import { buildJSONresult, importJSON, processParams } from './util.js'; +import { Specberus } from './validator.js'; + +const { version } = importJSON('../package.json', import.meta.url); -const { Sink } = sink; -const { version } = self; /** * Send the JSON result to the client. * @@ -21,7 +20,7 @@ const { version } = self; */ const sendJSONresult = function (err, warn, inf, res, metadata) { - const wrapper = util.buildJSONresult(err, warn, inf, metadata); + const wrapper = buildJSONresult(err, warn, inf, metadata); res.status(wrapper.success ? 200 : 400).json(wrapper); }; @@ -30,7 +29,7 @@ const sendJSONresult = function (err, warn, inf, res, metadata) { * * @param {string} apiKey */ -const processRequest = apiKey => (req, res) => { +const processRequest = apiKey => async (req, res) => { if (req.path === '/api/version') { res.status(200).send(version); } else if (req.path === '/api/metadata' || req.path === '/api/validate') { @@ -48,7 +47,7 @@ const processRequest = apiKey => (req, res) => { let handler; let handler2; try { - options = util.processParams(req.query, undefined, { + options = await processParams(req.query, undefined, { required: validate ? ['profile'] : [], forbidden: ['document', 'source'], }); @@ -57,7 +56,7 @@ const processRequest = apiKey => (req, res) => { } if (validate && options.profile === 'auto') { errors = []; - v = new validator.Specberus(apiKey); + v = new Specberus(apiKey); handler = new Sink( (...data) => { errors.push(Object.assign({}, ...data)); @@ -70,7 +69,7 @@ const processRequest = apiKey => (req, res) => { if (options.url) meta.url = options.url; else meta.file = options.file; try { - options2 = util.processParams(meta, undefined, { + options2 = processParams(meta, undefined, { allowUnknownParams: true, }); } catch (err) { @@ -86,7 +85,7 @@ const processRequest = apiKey => (req, res) => { errors2 = []; warnings2 = []; info2 = []; - v2 = new validator.Specberus(apiKey); + v2 = new Specberus(apiKey); handler2 = new Sink( (...data2) => { errors2.push(Object.assign({}, ...data2)); @@ -136,7 +135,7 @@ const processRequest = apiKey => (req, res) => { errors = []; warnings = []; info = []; - v = new validator.Specberus(apiKey); + v = new Specberus(apiKey); handler = new Sink( (...data) => { errors.push(Object.assign({}, ...data)); @@ -169,8 +168,6 @@ const processRequest = apiKey => (req, res) => { } }; -const setUp = function (app, apiKey) { +export const setUp = function (app, apiKey) { app.get('/api/*', processRequest(apiKey)); }; - -exports.setUp = setUp; diff --git a/lib/exceptions.js b/lib/exceptions.js index 5a5c0cf3b..0f482b770 100644 --- a/lib/exceptions.js +++ b/lib/exceptions.js @@ -1,4 +1,6 @@ -const records = require('./exceptions.json'); +import { importJSON } from './util.js'; + +const records = importJSON('./exceptions.json', import.meta.url); /** * @param data @@ -36,7 +38,7 @@ function findSet(shortname) { return recursiveFindSet(shortname); } -const Exceptions = function () {}; +export const Exceptions = function () {}; Exceptions.prototype.has = function (shortname, rule, key, extra) { const set = findSet(shortname); @@ -58,5 +60,3 @@ Exceptions.prototype.has = function (shortname, rule, key, extra) { } return false; }; - -exports.Exceptions = Exceptions; diff --git a/lib/l10n-en_GB.js b/lib/l10n-en_GB.js index 305862b6a..841deda47 100644 --- a/lib/l10n-en_GB.js +++ b/lib/l10n-en_GB.js @@ -1,5 +1,5 @@ /* eslint-disable no-template-curly-in-string */ -exports.messages = { +export const messages = { // Generic 'generic.sotd.not-found': 'No “status of this document” section found. Some errors related to this one will be omitted from the output, but most likely this will cause further problems along the line.', diff --git a/lib/l10n.js b/lib/l10n.js index 98fef7324..22e897bb1 100644 --- a/lib/l10n.js +++ b/lib/l10n.js @@ -3,10 +3,13 @@ */ // Internal packages: -const originalRules = require('./rules.json'); -const english = require('./l10n-en_GB'); +import { messages } from './l10n-en_GB.js'; +import { importJSON } from './util.js'; + +const originalRules = importJSON('./rules.json', import.meta.url); + // Constants: -const enGB = english.messages; +const enGB = messages; // Variables: let lang; @@ -24,7 +27,10 @@ for (const t in originalRules) * @param {string} language - locale, expressed as a string, eg en_GB. */ -exports.setLanguage = function (language) { +/** + * @param language + */ +export function setLanguage(language) { if (!language) throw new Error( 'l10n.setLanguage() invoked without passing a language code as parameter' @@ -34,7 +40,7 @@ exports.setLanguage = function (language) { throw new Error( 'Language code passed to l10n.setLanguage() is not valid' ); -}; +} /** * @param profileCode @@ -42,7 +48,7 @@ exports.setLanguage = function (language) { * @param key * @param extra */ -exports.assembleData = function (profileCode, rule, key, extra) { +export function assembleData(profileCode, rule, key, extra) { const messageData = {}; // Corner case: if the profile is unknown, let's assume 'WD' (most common). const profile = profileCode ? profileCode.replace('-Echidna', '') : 'WD'; @@ -81,11 +87,17 @@ to let developers examine the problem (you can submit it as is; no additional in messageData.profile = profile; return messageData; } -}; +} -exports.message = function (profileCode, rule, key, extra) { +/** + * @param profileCode + * @param rule + * @param key + * @param extra + */ +export function message(profileCode, rule, key, extra) { const result = {}; - const messageData = exports.assembleData(profileCode, rule, key, extra); + const messageData = assembleData(profileCode, rule, key, extra); if (!messageData) return; result.message = messageData.message && messageData.message.length @@ -158,4 +170,4 @@ ${selector}&labels=from-template">file this issue on GitHub to help develope if (messageData.additionalMessage) result.message += messageData.additionalMessage; return result; -}; +} diff --git a/lib/profiles/SUBM.js b/lib/profiles/SUBM.js index d00ed5274..0fba908b8 100644 --- a/lib/profiles/SUBM.js +++ b/lib/profiles/SUBM.js @@ -1,11 +1,8 @@ // Base profile for all Submissions +import * as submLogo from '../rules/headers/subm-logo.js'; +import { rules as baseRules } from './base.js'; +import { insertAfter } from './profileUtil.js'; -exports.name = 'Submission'; +export const name = 'Submission'; -const profileUtil = require('./profileUtil'); - -exports.rules = profileUtil.insertAfter( - require('./base').rules, - 'headers.logo', - require('../rules/headers/subm-logo') -); +export const rules = insertAfter(baseRules, 'headers.logo', submLogo); diff --git a/lib/profiles/SUBM/MEM-SUBM.js b/lib/profiles/SUBM/MEM-SUBM.js index 681238a72..e9f5e06ee 100644 --- a/lib/profiles/SUBM/MEM-SUBM.js +++ b/lib/profiles/SUBM/MEM-SUBM.js @@ -1,22 +1,24 @@ -exports.name = 'MEM-SUBM'; -exports.config = { +import * as memsubCopyright from '../../rules/headers/memsub-copyright.js'; +import * as submission from '../../rules/sotd/submission.js'; +import { insertAfter } from '../profileUtil.js'; +import { rules as baseRules } from '../SUBM.js'; + +export const name = 'MEM-SUBM'; +export const config = { status: 'SUBM', longStatus: 'Member Submission', styleSheet: 'W3C-Member-SUBM', submissionType: 'member', }; -const profileUtil = require('../profileUtil'); -let rules = profileUtil.insertAfter( - require('../SUBM').rules, +const rulesWithAdditionalHeaderRule = insertAfter( + baseRules, 'headers.w3c-state', - [require('../../rules/headers/memsub-copyright')] + [memsubCopyright] ); -rules = profileUtil.insertAfter( - rules, +export const rules = insertAfter( + rulesWithAdditionalHeaderRule, 'sotd.supersedable', - require('../../rules/sotd/submission') + submission ); - -exports.rules = rules; diff --git a/lib/profiles/TR.js b/lib/profiles/TR.js index 2b3c4be2e..10b59e421 100644 --- a/lib/profiles/TR.js +++ b/lib/profiles/TR.js @@ -1,20 +1,23 @@ -// base profile for all things TR -exports.name = 'TR'; - -const profileUtil = require('./profileUtil'); -const base = require('./base').rules; +import * as copyright from '../rules/headers/copyright.js'; +import * as githubRepo from '../rules/headers/github-repo.js'; +import * as charter from '../rules/sotd/charter.js'; +import * as pp from '../rules/sotd/pp.js'; +import * as processDocument from '../rules/sotd/process-document.js'; +import * as publish from '../rules/sotd/publish.js'; +import * as stability from '../rules/sotd/stability.js'; +import { rules as base } from './base.js'; +import { insertAfter } from './profileUtil.js'; -let rules = profileUtil.insertAfter(base, 'headers.w3c-state', [ - require('../rules/headers/github-repo'), - require('../rules/headers/copyright'), -]); +// base profile for all things TR +export const name = 'TR'; -rules = profileUtil.insertAfter(rules, 'sotd.supersedable', [ - require('../rules/sotd/stability'), - require('../rules/sotd/publish'), - require('../rules/sotd/pp'), - require('../rules/sotd/charter'), - require('../rules/sotd/process-document'), +const rulesWithAdditionalHeaderRule = insertAfter(base, 'headers.w3c-state', [ + githubRepo, + copyright, ]); -exports.rules = rules; +export const rules = insertAfter( + rulesWithAdditionalHeaderRule, + 'sotd.supersedable', + [stability, publish, pp, charter, processDocument] +); diff --git a/lib/profiles/TR/Note/DNOTE-Echidna.js b/lib/profiles/TR/Note/DNOTE-Echidna.js index f937a0fd4..31c77c47b 100644 --- a/lib/profiles/TR/Note/DNOTE-Echidna.js +++ b/lib/profiles/TR/Note/DNOTE-Echidna.js @@ -1,13 +1,12 @@ // TODO: merge all Echidna files. -exports.name = 'DNOTE-Echidna'; -const base = require('./DNOTE'); -exports.config = base.config; +import * as todaysDate from '../../../rules/echidna/todays-date.js'; +import { insertAfter } from '../../profileUtil.js'; +import { config as baseConfig, rules as baseRules } from './DNOTE.js'; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/echidna/todays-date'), -]); +export const name = 'DNOTE-Echidna'; +export const config = baseConfig; -exports.rules = rules; +export const rules = insertAfter(baseRules, 'sotd.process-document', [ + todaysDate, +]); diff --git a/lib/profiles/TR/Note/DNOTE.js b/lib/profiles/TR/Note/DNOTE.js index a1fad9c26..e2a2bf3f3 100644 --- a/lib/profiles/TR/Note/DNOTE.js +++ b/lib/profiles/TR/Note/DNOTE.js @@ -1,18 +1,13 @@ -exports.name = 'DNOTE'; -const base = require('./note-base'); +import * as draftStability from '../../../rules/sotd/draft-stability.js'; +import { insertAfter } from '../../profileUtil.js'; +import { config as baseConfig, rules as baseRules } from './note-base.js'; -// customize config -const config = { +export const name = 'DNOTE'; +export const config = { + ...baseConfig, status: 'DNOTE', longStatus: 'Group Draft Note', styleSheet: 'W3C-DNOTE', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.pp', [ - require('../../../rules/sotd/draft-stability'), -]); - -exports.rules = rules; +export const rules = insertAfter(baseRules, 'sotd.pp', [draftStability]); diff --git a/lib/profiles/TR/Note/NOTE-Echidna.js b/lib/profiles/TR/Note/NOTE-Echidna.js index 9afab841f..a6acc53d7 100644 --- a/lib/profiles/TR/Note/NOTE-Echidna.js +++ b/lib/profiles/TR/Note/NOTE-Echidna.js @@ -1,9 +1,10 @@ -exports.name = 'NOTE-Echidna'; -const base = require('./NOTE'); +import * as todaysDate from '../../../rules/echidna/todays-date.js'; +import { insertAfter } from '../../profileUtil.js'; +import { config as baseConfig, rules as baseRules } from './NOTE.js'; -exports.config = base.config; +export const name = 'NOTE-Echidna'; +export const config = baseConfig; -const profileUtil = require('../../profileUtil'); -exports.rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/echidna/todays-date'), +export const rules = insertAfter(baseRules, 'sotd.process-document', [ + todaysDate, ]); diff --git a/lib/profiles/TR/Note/NOTE.js b/lib/profiles/TR/Note/NOTE.js index 6340878d0..1eb9e8282 100644 --- a/lib/profiles/TR/Note/NOTE.js +++ b/lib/profiles/TR/Note/NOTE.js @@ -1,12 +1,11 @@ -exports.name = 'NOTE'; -const base = require('./note-base'); +import { config as baseConfig, rules as baseRules } from './note-base.js'; -// customize config -const config = { +export const name = 'NOTE'; +export const config = { + ...baseConfig, status: 'NOTE', longStatus: 'Group Note', styleSheet: 'W3C-NOTE', }; -exports.config = { ...base.config, ...config }; -exports.rules = base.rules; +export const rules = baseRules; diff --git a/lib/profiles/TR/Note/STMT.js b/lib/profiles/TR/Note/STMT.js index c2aa273dd..8b1d88ffa 100644 --- a/lib/profiles/TR/Note/STMT.js +++ b/lib/profiles/TR/Note/STMT.js @@ -1,12 +1,10 @@ -exports.name = 'STMT'; -const base = require('./note-base'); +import { config as baseConfig, rules as baseRules } from './note-base.js'; -// customize config -const config = { +export const name = 'STMT'; +export const config = { + ...baseConfig, status: 'STMT', longStatus: 'Statement', styleSheet: 'W3C-STMT', }; -exports.config = { ...base.config, ...config }; - -exports.rules = base.rules; +export const rules = baseRules; diff --git a/lib/profiles/TR/Note/note-base.js b/lib/profiles/TR/Note/note-base.js index 3302dc31f..53c706a48 100644 --- a/lib/profiles/TR/Note/note-base.js +++ b/lib/profiles/TR/Note/note-base.js @@ -1,13 +1,9 @@ -exports.config = { +import * as deliverNote from '../../../rules/sotd/deliverer-note.js'; +import { insertAfter } from '../../profileUtil.js'; +import { rules as baseRules } from '../../TR.js'; + +export const config = { track: 'Note', }; -// customize rules -const base = require('../../TR'); -const profileUtil = require('../../profileUtil'); - -const rules = profileUtil.insertAfter(base.rules, 'sotd.pp', [ - require('../../../rules/sotd/deliverer-note'), -]); - -exports.rules = rules; +export const rules = insertAfter(baseRules, 'sotd.pp', [deliverNote]); diff --git a/lib/profiles/TR/Recommendation/CR-Echidna.js b/lib/profiles/TR/Recommendation/CR-Echidna.js index e8dc85c6b..ebe6bb93c 100644 --- a/lib/profiles/TR/Recommendation/CR-Echidna.js +++ b/lib/profiles/TR/Recommendation/CR-Echidna.js @@ -1,12 +1,10 @@ -exports.name = 'CR-Echidna'; -const base = require('./CR'); +import * as todaysDate from '../../../rules/echidna/todays-date.js'; +import { insertAfter } from '../../profileUtil.js'; +import { rules as baseRules } from './CR.js'; -exports.config = base.config; +export const name = 'CR-Echidna'; +export { config } from './CR.js'; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/echidna/todays-date'), +export const rules = insertAfter(baseRules, 'sotd.process-document', [ + todaysDate, ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Recommendation/CR.js b/lib/profiles/TR/Recommendation/CR.js index b0a9fcb18..32aa4cab6 100644 --- a/lib/profiles/TR/Recommendation/CR.js +++ b/lib/profiles/TR/Recommendation/CR.js @@ -1,19 +1,19 @@ -exports.name = 'CR'; -const base = require('./recommendation-base'); +import * as candidateReviewEnd from '../../../rules/sotd/candidate-review-end.js'; +import { insertAfter } from '../../profileUtil.js'; +import { + config as baseConfig, + rules as baseRules, +} from './recommendation-base.js'; -// customize config -const config = { +export const name = 'CR'; +export const config = { + ...baseConfig, status: 'CR', longStatus: 'Candidate Recommendation', crType: 'Snapshot', styleSheet: 'W3C-CR', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/sotd/candidate-review-end'), +export const rules = insertAfter(baseRules, 'sotd.process-document', [ + candidateReviewEnd, ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Recommendation/CRD-Echidna.js b/lib/profiles/TR/Recommendation/CRD-Echidna.js index c65c53ba7..cb2ce2f55 100644 --- a/lib/profiles/TR/Recommendation/CRD-Echidna.js +++ b/lib/profiles/TR/Recommendation/CRD-Echidna.js @@ -1,10 +1,10 @@ -exports.name = 'CRD-Echidna'; -const base = require('./CRD'); +import * as todaysDate from '../../../rules/echidna/todays-date.js'; +import { insertAfter } from '../../profileUtil.js'; +import { rules as baseRules } from './CRD.js'; -exports.config = base.config; +export { config } from './CRD.js'; +export const name = 'CRD-Echidna'; -// customize rules -const profileUtil = require('../../profileUtil'); -exports.rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/echidna/todays-date'), +export const rules = insertAfter(baseRules, 'sotd.process-document', [ + todaysDate, ]); diff --git a/lib/profiles/TR/Recommendation/CRD.js b/lib/profiles/TR/Recommendation/CRD.js index d64c4c6e5..f7df75012 100644 --- a/lib/profiles/TR/Recommendation/CRD.js +++ b/lib/profiles/TR/Recommendation/CRD.js @@ -1,19 +1,17 @@ -exports.name = 'CRD'; -const base = require('./recommendation-base'); +import * as draftStability from '../../../rules/sotd/draft-stability.js'; +import { insertAfter } from '../../profileUtil.js'; +import { + config as baseConfig, + rules as baseRules, +} from './recommendation-base.js'; -// customize config -const config = { +export const name = 'CRD'; +export const config = { + ...baseConfig, status: 'CRD', longStatus: 'Candidate Recommendation', crType: 'Draft', styleSheet: 'W3C-CRD', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.pp', [ - require('../../../rules/sotd/draft-stability'), -]); - -exports.rules = rules; +export const rules = insertAfter(baseRules, 'sotd.pp', [draftStability]); diff --git a/lib/profiles/TR/Recommendation/DISC.js b/lib/profiles/TR/Recommendation/DISC.js index f6baf7886..982bdaf7a 100644 --- a/lib/profiles/TR/Recommendation/DISC.js +++ b/lib/profiles/TR/Recommendation/DISC.js @@ -1,20 +1,19 @@ -exports.name = 'DISC'; -const base = require('./recommendation-base'); +// customize rules +import { removeRules } from '../../profileUtil.js'; +import { + config as baseConfig, + rules as baseRules, +} from './recommendation-base.js'; -// customize config -const config = { +export const name = 'DISC'; +export const config = { + ...baseConfig, status: 'DISC', longStatus: 'Discontinued Draft', styleSheet: 'W3C-DISC', }; -exports.config = { ...base.config, ...config }; - -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.removeRules(base.rules, [ +export const rules = removeRules(baseRules, [ 'structure.security-privacy', 'sotd.diff', ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Recommendation/FPWD.js b/lib/profiles/TR/Recommendation/FPWD.js index 097b149f3..61e6709e6 100644 --- a/lib/profiles/TR/Recommendation/FPWD.js +++ b/lib/profiles/TR/Recommendation/FPWD.js @@ -1,23 +1,21 @@ -exports.name = 'FPWD'; -const base = require('./recommendation-base'); +import * as draftStability from '../../../rules/sotd/draft-stability.js'; +import { insertAfter, removeRules } from '../../profileUtil.js'; +import { + config as baseConfig, + rules as baseRules, +} from './recommendation-base.js'; -// customize config -const config = { +export const name = 'FPWD'; +export const config = { + ...baseConfig, status: 'WD', longStatus: 'First Public Working Draft', styleSheet: 'W3C-WD', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -let rules = profileUtil.insertAfter(base.rules, 'sotd.pp', [ - require('../../../rules/sotd/draft-stability'), -]); +const rulesWithOthers = insertAfter(baseRules, 'sotd.pp', [draftStability]); -rules = profileUtil.removeRules(rules, [ +export const rules = removeRules(rulesWithOthers, [ 'structure.security-privacy', 'sotd.diff', ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Recommendation/PR.js b/lib/profiles/TR/Recommendation/PR.js index 9d983cddf..6d4c99ff7 100644 --- a/lib/profiles/TR/Recommendation/PR.js +++ b/lib/profiles/TR/Recommendation/PR.js @@ -1,21 +1,24 @@ -exports.name = 'PR'; -const base = require('./recommendation-base'); +import * as acReview from '../../../rules/sotd/ac-review.js'; +import * as draftStability from '../../../rules/sotd/draft-stability.js'; +import * as newFeatures from '../../../rules/sotd/new-features.js'; +import * as reviewEnd from '../../../rules/sotd/review-end.js'; +import { insertAfter } from '../../profileUtil.js'; +import { + config as baseConfig, + rules as baseRules, +} from './recommendation-base.js'; -// customize config -const config = { +export const name = 'PR'; +export const config = { + ...baseConfig, status: 'PR', longStatus: 'Proposed Recommendation', styleSheet: 'W3C-PR', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/sotd/ac-review'), - require('../../../rules/sotd/review-end'), - require('../../../rules/sotd/new-features'), - require('../../../rules/sotd/draft-stability'), +export const rules = insertAfter(baseRules, 'sotd.process-document', [ + acReview, + reviewEnd, + newFeatures, + draftStability, ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Recommendation/REC-RSCND.js b/lib/profiles/TR/Recommendation/REC-RSCND.js index e9a28d263..ed887eae5 100644 --- a/lib/profiles/TR/Recommendation/REC-RSCND.js +++ b/lib/profiles/TR/Recommendation/REC-RSCND.js @@ -1,22 +1,21 @@ -exports.name = 'REC-RSCND'; -const base = require('./REC'); +import * as obslRescind from '../../../rules/sotd/obsl-rescind.js'; +import { insertAfter, removeRules } from '../../profileUtil.js'; +import { config as baseConfig, rules as baseRules } from './REC.js'; -// customize config -const config = { +export const name = 'REC-RSCND'; +export const config = { + ...baseConfig, status: 'REC', longStatus: 'Rescinded Recommendation', rescinds: true, styleSheet: 'W3C-RSCND', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -let rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/sotd/obsl-rescind'), +const rulesWithObslRescind = insertAfter(baseRules, 'sotd.process-document', [ + obslRescind, ]); -rules = profileUtil.removeRules(rules, [ +export const rules = removeRules(rulesWithObslRescind, [ 'headers.errata', 'sotd.stability', 'sotd.publish', @@ -28,5 +27,3 @@ rules = profileUtil.removeRules(rules, [ 'sotd.new-features', 'sotd.deployment', ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Recommendation/REC.js b/lib/profiles/TR/Recommendation/REC.js index 455c744fb..a76b0de49 100644 --- a/lib/profiles/TR/Recommendation/REC.js +++ b/lib/profiles/TR/Recommendation/REC.js @@ -1,26 +1,31 @@ -exports.name = 'REC'; -const base = require('./recommendation-base'); +import * as errata from '../../../rules/headers/errata.js'; +import * as deployment from '../../../rules/sotd/deployment.js'; +import * as newFeatures from '../../../rules/sotd/new-features.js'; +import * as recAddition from '../../../rules/sotd/rec-addition.js'; +import * as recCommentEnd from '../../../rules/sotd/rec-comment-end.js'; +import { insertAfter, removeRules } from '../../profileUtil.js'; +import { + config as baseConfig, + rules as baseRules, +} from './recommendation-base.js'; -// customize config -const config = { +export const name = 'REC'; +export const config = { + ...baseConfig, status: 'REC', longStatus: 'Recommendation', styleSheet: 'W3C-REC', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -let rules = profileUtil.insertAfter(base.rules, 'headers.dl', [ - require('../../../rules/headers/errata'), -]); -rules = profileUtil.insertAfter(rules, 'sotd.supersedable', [ - require('../../../rules/sotd/rec-addition'), - require('../../../rules/sotd/rec-comment-end'), - require('../../../rules/sotd/new-features'), - require('../../../rules/sotd/deployment'), -]); +const rulesWithErrata = insertAfter(baseRules, 'headers.dl', [errata]); -rules = profileUtil.removeRules(rules, ['structure.security-privacy']); +const rulesWithOthers = insertAfter(rulesWithErrata, 'sotd.supersedable', [ + recAddition, + recCommentEnd, + newFeatures, + deployment, +]); -exports.rules = rules; +export const rules = removeRules(rulesWithOthers, [ + 'structure.security-privacy', +]); diff --git a/lib/profiles/TR/Recommendation/WD-Echidna.js b/lib/profiles/TR/Recommendation/WD-Echidna.js index e9d56a7ad..a1ad8223c 100644 --- a/lib/profiles/TR/Recommendation/WD-Echidna.js +++ b/lib/profiles/TR/Recommendation/WD-Echidna.js @@ -1,11 +1,10 @@ -// Working Draft profile +import * as todaysDate from '../../../rules/echidna/todays-date.js'; +import { insertAfter } from '../../profileUtil.js'; +import { rules as baseRules } from './WD.js'; -exports.name = 'WD-Echidna'; -const base = require('./WD'); +export const name = 'WD-Echidna'; +export { config } from './WD.js'; -exports.config = base.config; - -const profileUtil = require('../../profileUtil'); -exports.rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/echidna/todays-date'), +export const rules = insertAfter(baseRules, 'sotd.process-document', [ + todaysDate, ]); diff --git a/lib/profiles/TR/Recommendation/WD.js b/lib/profiles/TR/Recommendation/WD.js index 19e9aa7cb..3c3ed7224 100644 --- a/lib/profiles/TR/Recommendation/WD.js +++ b/lib/profiles/TR/Recommendation/WD.js @@ -1,20 +1,18 @@ -// Working Draft profile +import * as draftStability from '../../../rules/sotd/draft-stability.js'; +import { insertAfter } from '../../profileUtil.js'; +import { + config as baseConfig, + rules as baseRules, +} from './recommendation-base.js'; -exports.name = 'WD'; -const base = require('./recommendation-base'); - -// customize config -const config = { +export const name = 'WD'; +export const config = { + ...baseConfig, status: 'WD', longStatus: 'Working Draft', styleSheet: 'W3C-WD', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.supersedable', [ - require('../../../rules/sotd/draft-stability'), +export const rules = insertAfter(baseRules, 'sotd.supersedable', [ + draftStability, ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Recommendation/recommendation-base.js b/lib/profiles/TR/Recommendation/recommendation-base.js index 9ec5fa909..268501810 100644 --- a/lib/profiles/TR/Recommendation/recommendation-base.js +++ b/lib/profiles/TR/Recommendation/recommendation-base.js @@ -1,14 +1,13 @@ -exports.config = { +import * as diff from '../../../rules/sotd/diff.js'; +import * as securityPrivacy from '../../../rules/structure/security-privacy.js'; +import { insertAfter } from '../../profileUtil.js'; +import { rules as baseRules } from '../../TR.js'; + +export const config = { track: 'Recommendation', }; -// customize rules -const base = require('../../TR'); - -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.supersedable', [ - require('../../../rules/sotd/diff'), - require('../../../rules/structure/security-privacy'), +export const rules = insertAfter(baseRules, 'sotd.supersedable', [ + diff, + securityPrivacy, ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Registry/CRY.js b/lib/profiles/TR/Registry/CRY.js index c0f399301..3030bb2da 100644 --- a/lib/profiles/TR/Registry/CRY.js +++ b/lib/profiles/TR/Registry/CRY.js @@ -1,19 +1,17 @@ -exports.name = 'CRY'; -const base = require('./registry-base'); +// customize rules +import * as candidateReviewEnd from '../../../rules/sotd/candidate-review-end.js'; +import { insertAfter } from '../../profileUtil.js'; +import { config as baseConfig, rules as baseRules } from './registry-base.js'; -// customize config -const config = { +export const name = 'CRY'; +export const config = { + ...baseConfig, status: 'CRY', longStatus: 'Candidate Registry', cryType: 'Snapshot', styleSheet: 'W3C-CRY', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.process-document', [ - require('../../../rules/sotd/candidate-review-end'), +export const rules = insertAfter(baseRules, 'sotd.process-document', [ + candidateReviewEnd, ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Registry/CRYD.js b/lib/profiles/TR/Registry/CRYD.js index 55309d15d..2f75af88b 100644 --- a/lib/profiles/TR/Registry/CRYD.js +++ b/lib/profiles/TR/Registry/CRYD.js @@ -1,20 +1,16 @@ -exports.name = 'CRYD'; -const base = require('./registry-base'); +import * as draftStability from '../../../rules/sotd/draft-stability.js'; +import { insertAfter } from '../../profileUtil.js'; +import { config as baseConfig, rules as baseRules } from './registry-base.js'; -// customize config -const config = { +export const name = 'CRYD'; +export const config = { + ...baseConfig, status: 'CRYD', longStatus: 'Candidate Registry', cryType: 'Draft', styleSheet: 'W3C-CRYD', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); - -const rules = profileUtil.insertAfter(base.rules, 'sotd.supersedable', [ - require('../../../rules/sotd/draft-stability'), +export const rules = insertAfter(baseRules, 'sotd.supersedable', [ + draftStability, ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Registry/DRY.js b/lib/profiles/TR/Registry/DRY.js index 5a48c8e2e..85cc46512 100644 --- a/lib/profiles/TR/Registry/DRY.js +++ b/lib/profiles/TR/Registry/DRY.js @@ -1,18 +1,15 @@ -exports.name = 'DRY'; -const base = require('./registry-base'); +import * as draftStability from '../../../rules/sotd/draft-stability.js'; +import { insertAfter } from '../../profileUtil.js'; +import { config as baseConfig, rules as baseRules } from './registry-base.js'; -// customize config -const config = { +export const name = 'DRY'; +export const config = { + ...baseConfig, status: 'DRY', longStatus: 'Draft Registry', styleSheet: 'W3C-DRY', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.supersedable', [ - require('../../../rules/sotd/draft-stability'), +export const rules = insertAfter(baseRules, 'sotd.supersedable', [ + draftStability, ]); - -exports.rules = rules; diff --git a/lib/profiles/TR/Registry/RY.js b/lib/profiles/TR/Registry/RY.js index 42c51d40a..9495a6d1c 100644 --- a/lib/profiles/TR/Registry/RY.js +++ b/lib/profiles/TR/Registry/RY.js @@ -1,18 +1,13 @@ -exports.name = 'RY'; -const base = require('./registry-base'); +import * as usage from '../../../rules/sotd/usage.js'; +import { insertAfter } from '../../profileUtil.js'; +import { config as baseConfig, rules as baseRules } from './registry-base.js'; -// customize config -const config = { +export const name = 'RY'; +export const config = { + ...baseConfig, status: 'RY', longStatus: 'Registry', styleSheet: 'W3C-RY', }; -exports.config = { ...base.config, ...config }; -// customize rules -const profileUtil = require('../../profileUtil'); -const rules = profileUtil.insertAfter(base.rules, 'sotd.supersedable', [ - require('../../../rules/sotd/usage'), -]); - -exports.rules = rules; +export const rules = insertAfter(baseRules, 'sotd.supersedable', [usage]); diff --git a/lib/profiles/TR/Registry/registry-base.js b/lib/profiles/TR/Registry/registry-base.js index c79b908d5..5fde85a8c 100644 --- a/lib/profiles/TR/Registry/registry-base.js +++ b/lib/profiles/TR/Registry/registry-base.js @@ -1,7 +1,5 @@ -exports.config = { +export const config = { track: 'Registry', }; -const base = require('../../TR'); - -exports.rules = base.rules; +export { rules } from '../../TR.js'; diff --git a/lib/profiles/base.js b/lib/profiles/base.js index 2db48f4c0..65b793b05 100644 --- a/lib/profiles/base.js +++ b/lib/profiles/base.js @@ -1,39 +1,62 @@ // Base profile for all W3C published documents -exports.name = 'Base'; +import * as detailsSummary from '../rules/headers/details-summary.js'; +import * as divHead from '../rules/headers/div-head.js'; +import * as dl from '../rules/headers/dl.js'; +import * as h1Title from '../rules/headers/h1-title.js'; +import * as h2Toc from '../rules/headers/h2-toc.js'; +import * as hr from '../rules/headers/hr.js'; +import * as logo from '../rules/headers/logo.js'; +import * as olToc from '../rules/headers/ol-toc.js'; +import * as secno from '../rules/headers/secno.js'; +import * as w3cState from '../rules/headers/w3c-state.js'; +import * as dateFormat from '../rules/heuristic/date-format.js'; +import * as compound from '../rules/links/compound.js'; +/* import * as internal from '../rules/links/internal.js'; */ +import * as linkchecker from '../rules/links/linkchecker.js'; +import * as reliability from '../rules/links/reliability.js'; +import * as supersedable from '../rules/sotd/supersedable.js'; +import * as canonical from '../rules/structure/canonical.js'; +import * as displayOnly from '../rules/structure/display-only.js'; +import * as h2 from '../rules/structure/h2.js'; +import * as structureName from '../rules/structure/name.js'; +import * as neutral from '../rules/structure/neutral.js'; +import * as sectionIds from '../rules/structure/section-ids.js'; +import * as backToTop from '../rules/style/back-to-top.js'; +import * as bodyTocSidebar from '../rules/style/body-toc-sidebar.js'; +import * as meta from '../rules/style/meta.js'; +import * as script from '../rules/style/script.js'; +import * as sheet from '../rules/style/sheet.js'; +import * as html from '../rules/validation/html.js'; +import * as wcag from '../rules/validation/wcag.js'; -exports.rules = [ - require('../rules/headers/div-head'), - require('../rules/headers/hr'), - require('../rules/headers/logo'), - require('../rules/headers/h1-title'), - require('../rules/headers/details-summary'), - require('../rules/headers/dl'), - require('../rules/headers/w3c-state'), - require('../rules/headers/h2-toc'), - require('../rules/headers/ol-toc'), - require('../rules/headers/secno'), - - require('../rules/style/sheet'), - require('../rules/style/meta'), - require('../rules/style/body-toc-sidebar'), - require('../rules/style/script'), - require('../rules/style/back-to-top'), - - require('../rules/sotd/supersedable'), - - require('../rules/structure/name'), - require('../rules/structure/h2'), - require('../rules/structure/canonical'), - require('../rules/structure/section-ids'), - require('../rules/structure/display-only'), - require('../rules/structure/neutral'), - - // , require('../rules/links/internal') - require('../rules/links/linkchecker'), - require('../rules/links/compound'), - require('../rules/links/reliability'), - - require('../rules/validation/html'), - require('../rules/validation/wcag'), - require('../rules/heuristic/date-format'), +export const name = 'Base'; +export const rules = [ + divHead, + hr, + logo, + h1Title, + detailsSummary, + dl, + w3cState, + h2Toc, + olToc, + secno, + sheet, + meta, + bodyTocSidebar, + script, + backToTop, + supersedable, + structureName, + h2, + canonical, + sectionIds, + displayOnly, + neutral, + linkchecker, + compound, + reliability, + html, + wcag, + dateFormat, ]; diff --git a/lib/profiles/metadata.js b/lib/profiles/metadata.js index ddf0f5d72..c94477409 100644 --- a/lib/profiles/metadata.js +++ b/lib/profiles/metadata.js @@ -1,20 +1,32 @@ /** * Pseudo-profile for metadata extraction. */ +import * as charters from '../rules/metadata/charters.js'; +import * as deliverers from '../rules/metadata/deliverers.js'; +import * as dl from '../rules/metadata/dl.js'; +import * as docDate from '../rules/metadata/docDate.js'; +import * as editorIds from '../rules/metadata/editor-ids.js'; +import * as editorNames from '../rules/metadata/editor-names.js'; +import * as errata from '../rules/metadata/errata.js'; +import * as informative from '../rules/metadata/informative.js'; +import * as patentPolicy from '../rules/metadata/patent-policy.js'; +import * as process from '../rules/metadata/process.js'; +import * as profile from '../rules/metadata/profile.js'; +import * as title from '../rules/metadata/title.js'; -exports.name = 'Metadata'; +export const name = 'Metadata'; -exports.rules = [ - require('../rules/metadata/profile'), - require('../rules/metadata/title'), - require('../rules/metadata/docDate'), - require('../rules/metadata/dl'), - require('../rules/metadata/deliverers'), - require('../rules/metadata/patent-policy'), - require('../rules/metadata/charters'), - require('../rules/metadata/editor-ids'), - require('../rules/metadata/editor-names'), - require('../rules/metadata/informative'), - require('../rules/metadata/process'), - require('../rules/metadata/errata'), +export const rules = [ + profile, + title, + docDate, + dl, + deliverers, + patentPolicy, + charters, + editorIds, + editorNames, + informative, + process, + errata, ]; diff --git a/lib/profiles/profileUtil.js b/lib/profiles/profileUtil.js index 027db1eac..0e5608b46 100644 --- a/lib/profiles/profileUtil.js +++ b/lib/profiles/profileUtil.js @@ -1,5 +1,10 @@ // take an array of rules, return a copy with new rules added after a given named anchor -exports.insertAfter = function (original, anchor, rules) { +/** + * @param original + * @param anchor + * @param rules + */ +export function insertAfter(original, anchor, rules) { rules = Array.isArray(rules) ? rules : [rules]; original = original.slice(); const index = original.map(r => r.name).indexOf(anchor); @@ -15,11 +20,15 @@ exports.insertAfter = function (original, anchor, rules) { ); }); return original; -}; +} // take an array of rules, return a copy with specified rules removed // e.g. profileUtil.removeRules(rules, "sotd.pp") -exports.removeRules = function (original, rules) { +/** + * @param original + * @param rules + */ +export function removeRules(original, rules) { rules = Array.isArray(rules) ? rules : [rules]; original = original.slice(); rules.forEach(r => { @@ -33,4 +42,4 @@ exports.removeRules = function (original, rules) { } }); return original; -}; +} diff --git a/lib/rules/echidna/todays-date.js b/lib/rules/echidna/todays-date.js index d0481938a..8404f3f7d 100644 --- a/lib/rules/echidna/todays-date.js +++ b/lib/rules/echidna/todays-date.js @@ -5,9 +5,13 @@ const self = { rule: 'dateState', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { /** * Get the timestamp of a day, regardless the time of the day. * This function creates a new `Date` to avoid modifying the original one. @@ -26,4 +30,4 @@ exports.check = function (sr, done) { } done(); -}; +} diff --git a/lib/rules/headers/copyright.js b/lib/rules/headers/copyright.js index c980b18f8..d17e385a0 100644 --- a/lib/rules/headers/copyright.js +++ b/lib/rules/headers/copyright.js @@ -7,6 +7,7 @@ * 4. For "copyright-software", the url is https://www.w3.org/Consortium/Legal/copyright-software, the dated url is https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document, they are both allowed. The name in the API is "W3C Software and Document License", but the document would use text "permissive document license". * 5. For "copyright-documents", the url is https://www.w3.org/Consortium/Legal/copyright-documents. The name in the API is "W3C Document License", but the document would use text "document use". */ +import { AB, TAG } from '../../util.js'; const self = { name: 'headers.copyright', @@ -14,8 +15,6 @@ const self = { rule: 'copyright', }; -const util = require('../../util'); - // W3C Software and Document License const LICENSE_CS_TEXT = 'permissive document license'; const LICENSE_CS_URL = 'https://www.w3.org/Consortium/Legal/copyright-software'; @@ -38,14 +37,18 @@ const linksToCheckBase = { trademark: 'https://www.w3.org/Consortium/Legal/ipr-notice#W3C_Trademarks', }; -exports.name = self.name; +export const { name } = self; -exports.check = async function (sr, done) { +/** + * @param sr + * @param done + */ +export async function check(sr, done) { const copyright = sr.jsDocument.querySelector('body div.head p.copyright'); if (copyright) { // Skip check if the document is only published by TAG and/or AB - const TagID = util.TAG.id; - const AbID = util.AB.id; + const TagID = TAG.id; + const AbID = AB.id; const deliverers = await sr.getDelivererIDs(); // groupIds: a list of ids without TAG or AB const groupIds = deliverers.filter( @@ -150,4 +153,4 @@ exports.check = async function (sr, done) { }); } else sr.error(self, 'not-found'); return done(); -}; +} diff --git a/lib/rules/headers/details-summary.js b/lib/rules/headers/details-summary.js index eb1fbf361..3b7cf0d51 100644 --- a/lib/rules/headers/details-summary.js +++ b/lib/rules/headers/details-summary.js @@ -6,9 +6,13 @@ const self = { rule: 'docIDFormat', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const details = sr.jsDocument.querySelector('.head details'); if (!details) { sr.error(self, 'no-details'); @@ -37,4 +41,4 @@ exports.check = function (sr, done) { } return done(); -}; +} diff --git a/lib/rules/headers/div-head.js b/lib/rules/headers/div-head.js index 2b76ba606..89b4b97b5 100644 --- a/lib/rules/headers/div-head.js +++ b/lib/rules/headers/div-head.js @@ -6,8 +6,12 @@ const self = { rule: 'divClassHead', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { sr.checkSelector('body div.head', self, done); -}; +} diff --git a/lib/rules/headers/dl.js b/lib/rules/headers/dl.js index aece43660..5b708a176 100644 --- a/lib/rules/headers/dl.js +++ b/lib/rules/headers/dl.js @@ -7,7 +7,8 @@ // #w3c-state date and this version date must match // dt for editor or author -const superagent = require('superagent'); +import superagent from 'superagent'; +import doAsync from 'doasync'; const self = { name: 'headers.dl', @@ -34,7 +35,7 @@ const editorError = { section: 'front-matter', rule: 'editorSection', }; -exports.name = self.name; +export const name = self.name; /** * Check if link and href are consistent. @@ -52,7 +53,7 @@ function checkLink({ sr, rule = self, element, linkName, mustHave = true }) { return true; } -exports.check = async function (sr, done) { +export async function check(sr, done) { const { rescinds } = sr.config; const { obsoletes } = sr.config; const { supersedes } = sr.config; @@ -188,7 +189,6 @@ exports.check = async function (sr, done) { const historyHref = linkHistory.getAttribute('href'); // Check if the history link exist let historyStatusCode; - const doAsync = require('doasync'); try { const res = await doAsync(superagent).head(historyHref); historyStatusCode = res.statusCode; @@ -373,4 +373,4 @@ exports.check = async function (sr, done) { sr.error(editorError, 'editor-not-found'); } done(); -}; +} diff --git a/lib/rules/headers/errata.js b/lib/rules/headers/errata.js index e42c5bd3c..800ef5200 100644 --- a/lib/rules/headers/errata.js +++ b/lib/rules/headers/errata.js @@ -4,9 +4,13 @@ const self = { name: 'headers.errata', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const dts = sr.extractHeaders(); // Check 'Errata:' exist, don't check any further. if (!dts.Errata) { @@ -14,4 +18,4 @@ exports.check = function (sr, done) { return done(); } return done(); -}; +} diff --git a/lib/rules/headers/github-repo.js b/lib/rules/headers/github-repo.js index 2497485bd..0b3a5fafc 100644 --- a/lib/rules/headers/github-repo.js +++ b/lib/rules/headers/github-repo.js @@ -8,9 +8,13 @@ const self = { rule: 'docIDOrder', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const dts = sr.extractHeaders(); // Check 'Feedback:' exist if (!dts.Feedback) { @@ -38,4 +42,4 @@ exports.check = function (sr, done) { if (!foundRepo) sr.error(self, 'no-repo'); done(); -}; +} diff --git a/lib/rules/headers/h1-title.js b/lib/rules/headers/h1-title.js index 3538dc127..07fa4199c 100644 --- a/lib/rules/headers/h1-title.js +++ b/lib/rules/headers/h1-title.js @@ -6,9 +6,13 @@ const self = { rule: 'title', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const title = sr.jsDocument.querySelector('head > title'); const h1 = sr.jsDocument.querySelector('body div.head h1'); if (!title || !h1) { @@ -23,4 +27,4 @@ exports.check = function (sr, done) { sr.error(self, 'not-match', { titleText, h1Text }); } done(); -}; +} diff --git a/lib/rules/headers/h2-toc.js b/lib/rules/headers/h2-toc.js index 2e282b805..69e1cb430 100644 --- a/lib/rules/headers/h2-toc.js +++ b/lib/rules/headers/h2-toc.js @@ -10,9 +10,13 @@ const self = { rule: 'toc', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const EXPECTED_HEADING = /^table\s+of\s+contents$/i; const tocNav = sr.jsDocument.querySelectorAll('nav#toc > h2'); const tocDiv = sr.jsDocument.querySelectorAll('div#toc > h2'); @@ -36,4 +40,4 @@ exports.check = function (sr, done) { } done(); -}; +} diff --git a/lib/rules/headers/hr.js b/lib/rules/headers/hr.js index 2a1e3e64e..57ed46f24 100644 --- a/lib/rules/headers/hr.js +++ b/lib/rules/headers/hr.js @@ -4,9 +4,13 @@ const self = { rule: 'hrAfterCopyright', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const hasHrLastChild = sr.jsDocument.querySelectorAll('body div.head > hr:last-child') .length === 1; @@ -18,4 +22,4 @@ exports.check = function (sr, done) { sr.error(self, 'not-found'); } done(); -}; +} diff --git a/lib/rules/headers/logo.js b/lib/rules/headers/logo.js index 05ddf1c18..af5275ff1 100644 --- a/lib/rules/headers/logo.js +++ b/lib/rules/headers/logo.js @@ -4,9 +4,13 @@ const self = { rule: 'logo', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const logo = sr.jsDocument.querySelector( "body div.head a[href] > img[src][height='48'][width='72'][alt='W3C']" ); @@ -22,4 +26,4 @@ exports.check = function (sr, done) { sr.error(self, 'not-found'); } done(); -}; +} diff --git a/lib/rules/headers/memsub-copyright.js b/lib/rules/headers/memsub-copyright.js index c6e737f00..e4b21bcb9 100644 --- a/lib/rules/headers/memsub-copyright.js +++ b/lib/rules/headers/memsub-copyright.js @@ -2,9 +2,13 @@ const self = { name: 'headers.memsub-copyright', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const copyright = sr.jsDocument.querySelector('body div.head p.copyright'); if (copyright) { // , "https://www.w3.org/Consortium/Legal/copyright-documents": "document use" @@ -20,4 +24,4 @@ exports.check = function (sr, done) { if (!seen) sr.error(self, 'not-found'); } else sr.error(self, 'not-found'); done(); -}; +} diff --git a/lib/rules/headers/ol-toc.js b/lib/rules/headers/ol-toc.js index dac39eb69..692c521da 100644 --- a/lib/rules/headers/ol-toc.js +++ b/lib/rules/headers/ol-toc.js @@ -9,9 +9,13 @@ const self = { rule: 'toc', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const toc = sr.jsDocument.querySelectorAll( 'nav#toc ol.toc, div#toc ol.toc' ); @@ -21,4 +25,4 @@ exports.check = function (sr, done) { } done(); -}; +} diff --git a/lib/rules/headers/secno.js b/lib/rules/headers/secno.js index 5eebf2d89..f2e66cffe 100644 --- a/lib/rules/headers/secno.js +++ b/lib/rules/headers/secno.js @@ -6,9 +6,13 @@ const self = { name: 'headers.secno', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { // TODO: once supported, use: ":is(h2, h3, h4, h5, h6) :is(bdi.secno,span.secno)" const secnos = sr.jsDocument.querySelectorAll( 'h1 span.secno, h2 span.secno, h3 span.secno, h4 span.secno, h5 span.secno, h6 span.secno, #toc span.secno,' + @@ -20,4 +24,4 @@ exports.check = function (sr, done) { } done(); -}; +} diff --git a/lib/rules/headers/subm-logo.js b/lib/rules/headers/subm-logo.js index 4e18dbbb2..1b91a6d20 100644 --- a/lib/rules/headers/subm-logo.js +++ b/lib/rules/headers/subm-logo.js @@ -2,9 +2,13 @@ const self = { name: 'headers.subm-logo', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const logo = sr.jsDocument.querySelector( "body div.head a[href] > img[src][height='48'][width='211'][alt]" ); @@ -27,4 +31,4 @@ exports.check = function (sr, done) { }); } done(); -}; +} diff --git a/lib/rules/headers/w3c-state.js b/lib/rules/headers/w3c-state.js index a336e5fc6..cc96d64ea 100644 --- a/lib/rules/headers/w3c-state.js +++ b/lib/rules/headers/w3c-state.js @@ -1,4 +1,6 @@ -const rules = require('../../rules.json'); +import { importJSON } from '../../util.js'; + +const rules = importJSON('../../rules.json', import.meta.url); const self = { name: 'headers.w3c-state', @@ -6,9 +8,13 @@ const self = { rule: 'dateState', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { let profileFound = false; if (!sr.config.longStatus) return done(); @@ -62,4 +68,4 @@ exports.check = function (sr, done) { } done(); -}; +} diff --git a/lib/rules/heuristic/date-format.js b/lib/rules/heuristic/date-format.js index 77c116449..8363d95f1 100644 --- a/lib/rules/heuristic/date-format.js +++ b/lib/rules/heuristic/date-format.js @@ -4,9 +4,13 @@ const self = { rule: 'datesFormat', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { // Pseudo-constants: const MONTHS = 'jan|january|feb|february|mar|march|apr|april|may|jun|june|jul|july|aug|august|sep|september|oct|october|nov|november|dec|december'; @@ -46,4 +50,4 @@ exports.check = function (sr, done) { } return done(); -}; +} diff --git a/lib/rules/links/compound.js b/lib/rules/links/compound.js index c99e6d640..19c21547c 100644 --- a/lib/rules/links/compound.js +++ b/lib/rules/links/compound.js @@ -1,14 +1,18 @@ -const url = require('url'); -const sua = require('../../throttled-ua'); +import url from 'url'; +import { get } from '../../throttled-ua.js'; const self = { name: 'links.compound', }; const TIMEOUT = 10000; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { if (sr.config.validation !== 'recursive') { sr.warning(self, 'skipped'); return done(); @@ -33,8 +37,7 @@ exports.check = function (sr, done) { if (sr.config.validation === 'recursive') { const ua = `W3C-Pubrules/${sr.version}`; let isMarkupValid = false; - const req = sua - .get(markupService) + const req = get(markupService) .set('User-Agent', ua) .query({ doc: l, out: 'json' }) .on('error', err => { @@ -82,4 +85,4 @@ exports.check = function (sr, done) { } }); } else return done(); -}; +} diff --git a/lib/rules/links/internal.js b/lib/rules/links/internal.js index 5a301cb75..7d179316e 100644 --- a/lib/rules/links/internal.js +++ b/lib/rules/links/internal.js @@ -4,9 +4,13 @@ const self = { rule: 'brokenLink', }; -exports.name = self.name; +export const { name } = self; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { sr.jsDocument.querySelectorAll("a[href^='#']").forEach(element => { const id = element.getAttribute('href').replace('#', ''); const escId = id.replace(/([.()#:[\]+*])/g, '\\$1'); @@ -18,4 +22,4 @@ exports.check = function (sr, done) { } }); done(); -}; +} diff --git a/lib/rules/links/linkchecker.js b/lib/rules/links/linkchecker.js index ef1c29e56..921ce5b26 100644 --- a/lib/rules/links/linkchecker.js +++ b/lib/rules/links/linkchecker.js @@ -1,5 +1,5 @@ // Check every sources(img, stylesheets, scripts) are in same folder as spec document, and they are reachable. -const puppeteer = require('puppeteer'); +import puppeteer from 'puppeteer'; const self = { name: 'links.linkchecker', @@ -26,7 +26,7 @@ const noRespondAllowList = [ 'https://www.w3.org/analytics/piwik/matomo.js', ]; -exports.name = self.name; +export const { name } = self; /** * @param url @@ -57,7 +57,11 @@ function includedByReg(url, regArray = allowList) { }); } -exports.check = async function (sr, done) { +/** + * @param sr + * @param done + */ +export async function check(sr, done) { // send out warning for /nu W3C link checker. sr.warning(self, 'display', { link: sr.url }); @@ -114,4 +118,4 @@ exports.check = async function (sr, done) { await browser.close(); done(); -}; +} diff --git a/lib/rules/links/reliability.js b/lib/rules/links/reliability.js index 18d0f456b..0da069c55 100644 --- a/lib/rules/links/reliability.js +++ b/lib/rules/links/reliability.js @@ -3,7 +3,7 @@ const self = { section: 'document-body', }; -exports.name = self.name; +export const { name } = self; const unreliableServices = [ { domain: 'w3.org', path: /^\/Bugs/ }, @@ -18,7 +18,11 @@ const unreliableServices = [ // { domain: 'w3.org', path: /track(er)?\/(actions|issues|resolutions)/} ]; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { Array.prototype.some.call(sr.jsDocument.querySelectorAll('a'), element => { let url; try { @@ -49,4 +53,4 @@ exports.check = function (sr, done) { }); }); done(); -}; +} diff --git a/lib/rules/metadata/charters.js b/lib/rules/metadata/charters.js index 52c6a4c5d..3727c7b15 100644 --- a/lib/rules/metadata/charters.js +++ b/lib/rules/metadata/charters.js @@ -4,10 +4,14 @@ // 'self.name' would be 'metadata.charters' -exports.name = 'metadata.charters'; +export const name = 'metadata.charters'; -exports.check = async function (sr, done) { +/** + * @param sr + * @param done + */ +export async function check(sr, done) { const charters = await sr.getCharters(); return done({ charters }); -}; +} diff --git a/lib/rules/metadata/deliverers.js b/lib/rules/metadata/deliverers.js index 7efac0f91..d6e8884f1 100644 --- a/lib/rules/metadata/deliverers.js +++ b/lib/rules/metadata/deliverers.js @@ -3,10 +3,14 @@ */ // 'self.name' would be 'metadata.deliverers' -exports.name = 'metadata.deliverers'; +export const name = 'metadata.deliverers'; -exports.check = async function (sr, done) { +/** + * @param sr + * @param done + */ +export async function check(sr, done) { const ids = await sr.getDelivererIDs(); done({ delivererIDs: ids }); -}; +} diff --git a/lib/rules/metadata/dl.js b/lib/rules/metadata/dl.js index ba543f8e6..85ce91f7c 100644 --- a/lib/rules/metadata/dl.js +++ b/lib/rules/metadata/dl.js @@ -2,15 +2,21 @@ * Pseudo-rule for metadata extraction: dl. */ +import { get } from '../../throttled-ua.js'; + const latestRule = { name: 'metadata.dl', section: 'front-matter', rule: 'docIDLatestVersion', }; -exports.name = 'metadata.dl'; +export const name = 'metadata.dl'; -exports.check = async function (sr, done) { +/** + * @param sr + * @param done + */ +export async function check(sr, done) { const dts = sr.extractHeaders(); const result = {}; let shortname; @@ -69,9 +75,8 @@ exports.check = async function (sr, done) { (month[1] ? month : `0${month[0]}`) + (day[1] ? day : `0${day[0]}`); const endpoint = `https://api.w3.org/specifications/${latestShortname}/versions/${formattedDate}`; - const sua = require('../../throttled-ua'); - const req = sua.get(endpoint).set('User-Agent', ua); + const req = get(endpoint).set('User-Agent', ua); req.query({ apikey }); req.end((err, res) => { result.updated = !(err || !res.ok); @@ -80,4 +85,4 @@ exports.check = async function (sr, done) { } else { sr.throw('[EXCEPTION] The document date could not be parsed.'); } -}; +} diff --git a/lib/rules/metadata/docDate.js b/lib/rules/metadata/docDate.js index 41cb0a966..58565d89f 100644 --- a/lib/rules/metadata/docDate.js +++ b/lib/rules/metadata/docDate.js @@ -3,9 +3,13 @@ */ // 'self.name' would be 'metadata.docDate' -exports.name = 'metadata.docDate'; +export const name = 'metadata.docDate'; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const docDate = sr.getDocumentDate(); if (!docDate) { return done(); @@ -16,4 +20,4 @@ exports.check = function (sr, done) { docDate.getDate(), ].join('-'); return done({ docDate: d }); -}; +} diff --git a/lib/rules/metadata/editor-ids.js b/lib/rules/metadata/editor-ids.js index 7865e065a..24632fdaf 100644 --- a/lib/rules/metadata/editor-ids.js +++ b/lib/rules/metadata/editor-ids.js @@ -3,8 +3,12 @@ */ // 'self.name' would be 'metadata.editor-ids' -exports.name = 'metadata.editor-ids'; +export const name = 'metadata.editor-ids'; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { return done({ editorIDs: sr.getEditorIDs() }); -}; +} diff --git a/lib/rules/metadata/editor-names.js b/lib/rules/metadata/editor-names.js index d2eb13b9d..7cf6aff5e 100644 --- a/lib/rules/metadata/editor-names.js +++ b/lib/rules/metadata/editor-names.js @@ -3,9 +3,13 @@ */ // 'self.name' would be 'metadata.editor-names' -exports.name = 'metadata.editor-names'; +export const name = 'metadata.editor-names'; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const dts = sr.extractHeaders(); const result = []; if (dts.Editor) { @@ -18,4 +22,4 @@ exports.check = function (sr, done) { }); } return done({ editorNames: result }); -}; +} diff --git a/lib/rules/metadata/errata.js b/lib/rules/metadata/errata.js index 608a30b9f..78b819657 100644 --- a/lib/rules/metadata/errata.js +++ b/lib/rules/metadata/errata.js @@ -4,9 +4,13 @@ // 'self.name' would be 'metadata.errata' -exports.name = 'metadata.errata'; +export const name = 'metadata.errata'; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const errataRegex = /errata/i; const linkElement = sr.jsDocument.querySelectorAll( 'body div.head dl + p > a' @@ -16,4 +20,4 @@ exports.check = function (sr, done) { ); if (!errata.length || !errata[0].getAttribute('href')) done(); else done({ errata: errata[0].getAttribute('href') }); -}; +} diff --git a/lib/rules/metadata/informative.js b/lib/rules/metadata/informative.js index bdb6eb472..ad0438844 100644 --- a/lib/rules/metadata/informative.js +++ b/lib/rules/metadata/informative.js @@ -3,9 +3,13 @@ */ // 'self.name' would be 'metadata.informative' -exports.name = 'metadata.informative'; +export const name = 'metadata.informative'; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const sotd = sr.getSotDSection(); const expected = /This\s+document\s+is\s+informative\s+only\./; let isInformative = false; @@ -22,4 +26,4 @@ exports.check = function (sr, done) { return done({ informative: expected.test(sotd && sotd.textContent) || isInformative, }); -}; +} diff --git a/lib/rules/metadata/patent-policy.js b/lib/rules/metadata/patent-policy.js index f04c29ff4..88d98a6a7 100644 --- a/lib/rules/metadata/patent-policy.js +++ b/lib/rules/metadata/patent-policy.js @@ -4,9 +4,13 @@ // 'self.name' would be 'metadata.patent-policy' -exports.name = 'metadata.patent-policy'; +export const name = 'metadata.patent-policy'; -exports.check = async function (sr, done) { +/** + * @param sr + * @param done + */ +export async function check(sr, done) { const patentPolicies = await sr.getPatentPolicies(); return done({ patentPolicy: patentPolicies[0] }); -}; +} diff --git a/lib/rules/metadata/process.js b/lib/rules/metadata/process.js index fc5ecaa3b..cc465667d 100644 --- a/lib/rules/metadata/process.js +++ b/lib/rules/metadata/process.js @@ -8,9 +8,13 @@ // , rule: 'whichProcess' // }; -exports.name = 'metadata.process'; +export const name = 'metadata.process'; -exports.check = function (sr, done) { +/** + * @param sr + * @param done + */ +export function check(sr, done) { const processDocument = sr.jsDocument.querySelector( 'a#w3c_process_revision' ); @@ -18,4 +22,4 @@ exports.check = function (sr, done) { return done(); } return done({ process: processDocument.getAttribute('href') }); -}; +} diff --git a/lib/rules/metadata/profile.js b/lib/rules/metadata/profile.js index 486a069b0..0d04ff7bd 100644 --- a/lib/rules/metadata/profile.js +++ b/lib/rules/metadata/profile.js @@ -3,16 +3,23 @@ */ // Internal packages: -const w3cApi = require('node-w3capi'); -const rules = require('../../rules.json'); -const util = require('../../util'); +import w3cApi from 'node-w3capi'; +import { allProfiles, importJSON } from '../../util.js'; +import { sortedProfiles } from '../../views.js'; +import { check as getTitle } from './title.js'; + +const rules = importJSON('../../rules.json', import.meta.url); w3cApi.apiKey = process.env.W3C_API_KEY; // 'self.name' would be 'metadata.profile' -exports.name = 'metadata.profile'; +export const name = 'metadata.profile'; -exports.check = async function (sr, done) { +/** + * @param sr + * @param done + */ +export async function check(sr, done) { let matchedLength = 0; let id; let profileNode; @@ -78,7 +85,6 @@ exports.check = async function (sr, done) { } // Get 'track/rectrack' of the document based on id - const { allProfiles } = util; const profileRex = new RegExp( `SUBM|(TR/(Registry|Recommendation|Note))/(${id}).js` ); @@ -123,7 +129,6 @@ exports.check = async function (sr, done) { } assembleMeta(id, sr); } else { - const getTitle = require('./title').check; let docTitle; await getTitle(sr, result => { docTitle = result && result.title; @@ -137,7 +142,6 @@ exports.check = async function (sr, done) { 'link[href^="https://www.w3.org/StyleSheets/TR/"]' ) ) { - const { sortedProfiles } = require('../../views'); let profileList = ''; sortedProfiles.forEach(category => { profileList += `${category.name}