From 8317e937502495d4153dd62f9c8415bbe4b36d3b Mon Sep 17 00:00:00 2001
From: Yosuke Ota <otameshiyo23@gmail.com>
Date: Mon, 2 Dec 2024 08:01:21 +0900
Subject: [PATCH] Add update-resources script (#2171)

Co-authored-by: Flo Edelmann <git@flo-edelmann.de>
---
 .../workflows/check-for-resources-update.yml  |  30 ++++
 lib/utils/deprecated-html-elements.json       |   8 +-
 lib/utils/html-elements.json                  | 164 +++++++++---------
 lib/utils/svg-elements.json                   |   6 -
 package.json                                  |   2 +
 .../lib/rules/no-reserved-component-names.js  |  12 --
 tools/lib/http.js                             |   6 +
 tools/update-html-resources.js                | 105 +++++++++++
 tools/update-resources.js                     |   4 +
 tools/update-vue3-export-names.js             |  33 +---
 tools/update.js                               |   4 -
 11 files changed, 231 insertions(+), 143 deletions(-)
 create mode 100644 .github/workflows/check-for-resources-update.yml
 create mode 100644 tools/lib/http.js
 create mode 100644 tools/update-html-resources.js
 create mode 100644 tools/update-resources.js

diff --git a/.github/workflows/check-for-resources-update.yml b/.github/workflows/check-for-resources-update.yml
new file mode 100644
index 000000000..a9b2460e8
--- /dev/null
+++ b/.github/workflows/check-for-resources-update.yml
@@ -0,0 +1,30 @@
+name: Check for utils resources update
+on:
+  workflow_dispatch: null
+  schedule:
+    - cron: 0 0 * * 0 # At 00:00 on Sunday, see https://crontab.guru/#0_0_*_*_0
+
+permissions:
+    contents: write
+    pull-requests: write
+
+jobs:
+  check-for-resources-update:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+      - name: Install Node.js
+        uses: actions/setup-node@v3
+        with:
+          node-version: 18
+      - name: Install Packages
+        run: npm install
+      - name: Update
+        run: npm run update-resources
+      - uses: peter-evans/create-pull-request@v7
+        with:
+          commit-message: Updates resources
+          branch: update-resources
+          branch-suffix: timestamp
+          title: Updates resources
diff --git a/lib/utils/deprecated-html-elements.json b/lib/utils/deprecated-html-elements.json
index 1d9d67968..63a3f7162 100644
--- a/lib/utils/deprecated-html-elements.json
+++ b/lib/utils/deprecated-html-elements.json
@@ -6,14 +6,10 @@
   "big",
   "blink",
   "center",
-  "command",
-  "content",
   "dir",
-  "element",
   "font",
   "frame",
   "frameset",
-  "image",
   "isindex",
   "keygen",
   "listing",
@@ -24,8 +20,10 @@
   "nobr",
   "noembed",
   "noframes",
+  "param",
   "plaintext",
-  "shadow",
+  "rb",
+  "rtc",
   "spacer",
   "strike",
   "tt",
diff --git a/lib/utils/html-elements.json b/lib/utils/html-elements.json
index 6911e3482..829b6f841 100644
--- a/lib/utils/html-elements.json
+++ b/lib/utils/html-elements.json
@@ -1,120 +1,116 @@
 [
-  "html",
-  "body",
-  "base",
-  "head",
-  "link",
-  "meta",
-  "style",
-  "title",
+  "a",
+  "abbr",
   "address",
+  "area",
   "article",
   "aside",
+  "audio",
+  "b",
+  "base",
+  "bdi",
+  "bdo",
+  "blockquote",
+  "body",
+  "br",
+  "button",
+  "canvas",
+  "caption",
+  "cite",
+  "code",
+  "col",
+  "colgroup",
+  "data",
+  "datalist",
+  "dd",
+  "del",
+  "details",
+  "dfn",
+  "dialog",
+  "div",
+  "dl",
+  "dt",
+  "em",
+  "embed",
+  "fencedframe",
+  "fieldset",
+  "figcaption",
+  "figure",
   "footer",
-  "header",
+  "form",
   "h1",
   "h2",
   "h3",
   "h4",
   "h5",
   "h6",
+  "head",
+  "header",
   "hgroup",
-  "nav",
-  "section",
-  "div",
-  "dd",
-  "dl",
-  "dt",
-  "figcaption",
-  "figure",
   "hr",
+  "html",
+  "i",
+  "iframe",
   "img",
+  "input",
+  "ins",
+  "kbd",
+  "label",
+  "legend",
   "li",
+  "link",
   "main",
+  "map",
+  "mark",
+  "menu",
+  "meta",
+  "meter",
+  "nav",
+  "noscript",
+  "object",
   "ol",
+  "optgroup",
+  "option",
+  "output",
   "p",
+  "picture",
+  "portal",
   "pre",
-  "ul",
-  "a",
-  "b",
-  "abbr",
-  "bdi",
-  "bdo",
-  "br",
-  "cite",
-  "code",
-  "data",
-  "dfn",
-  "em",
-  "i",
-  "kbd",
-  "mark",
+  "progress",
   "q",
   "rp",
   "rt",
-  "rtc",
   "ruby",
   "s",
   "samp",
+  "script",
+  "search",
+  "section",
+  "select",
+  "slot",
   "small",
+  "source",
   "span",
   "strong",
+  "style",
   "sub",
+  "summary",
   "sup",
-  "time",
-  "u",
-  "var",
-  "wbr",
-  "area",
-  "audio",
-  "map",
-  "track",
-  "video",
-  "embed",
-  "object",
-  "param",
-  "source",
-  "canvas",
-  "script",
-  "noscript",
-  "del",
-  "ins",
-  "caption",
-  "col",
-  "colgroup",
   "table",
-  "thead",
   "tbody",
-  "tfoot",
   "td",
+  "template",
+  "textarea",
+  "tfoot",
   "th",
+  "thead",
+  "time",
+  "title",
   "tr",
-  "button",
-  "datalist",
-  "fieldset",
-  "form",
-  "input",
-  "label",
-  "legend",
-  "meter",
-  "optgroup",
-  "option",
-  "output",
-  "progress",
-  "select",
-  "textarea",
-  "details",
-  "dialog",
-  "menu",
-  "menuitem",
-  "summary",
-  "content",
-  "element",
-  "shadow",
-  "template",
-  "slot",
-  "blockquote",
-  "iframe",
-  "noframes",
-  "picture"
+  "track",
+  "u",
+  "ul",
+  "var",
+  "video",
+  "wbr"
 ]
diff --git a/lib/utils/svg-elements.json b/lib/utils/svg-elements.json
index 7e5ba6052..f214aad24 100644
--- a/lib/utils/svg-elements.json
+++ b/lib/utils/svg-elements.json
@@ -3,13 +3,10 @@
   "animate",
   "animateMotion",
   "animateTransform",
-  "audio",
-  "canvas",
   "circle",
   "clipPath",
   "defs",
   "desc",
-  "discard",
   "ellipse",
   "feBlend",
   "feColorMatrix",
@@ -39,7 +36,6 @@
   "filter",
   "foreignObject",
   "g",
-  "iframe",
   "image",
   "line",
   "linearGradient",
@@ -64,8 +60,6 @@
   "textPath",
   "title",
   "tspan",
-  "unknown",
   "use",
-  "video",
   "view"
 ]
diff --git a/package.json b/package.json
index 0c75e65c7..48cd643c4 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
     "preversion": "npm test && git add .",
     "version": "env-cmd -e version npm run update && npm run lint -- --fix && git add .",
     "update": "node ./tools/update.js",
+    "update-resources": "node ./tools/update-resources.js",
     "docs:watch": "vitepress dev docs",
     "predocs:build": "npm run update",
     "docs:build": "vitepress build docs"
@@ -90,6 +91,7 @@
     "eslint-plugin-vue": "file:.",
     "espree": "^9.6.1",
     "events": "^3.3.0",
+    "jsdom": "^22.0.0",
     "markdownlint-cli": "^0.42.0",
     "mocha": "^10.7.3",
     "nyc": "^17.1.0",
diff --git a/tests/lib/rules/no-reserved-component-names.js b/tests/lib/rules/no-reserved-component-names.js
index 231e1f98d..809d35103 100644
--- a/tests/lib/rules/no-reserved-component-names.js
+++ b/tests/lib/rules/no-reserved-component-names.js
@@ -247,12 +247,6 @@ const invalidElements = [
   'menuitem',
   'summary',
   'Summary',
-  'content',
-  'Content',
-  'element',
-  'Element',
-  'shadow',
-  'Shadow',
   'template',
   'Template',
   'slot',
@@ -278,8 +272,6 @@ const invalidElements = [
   'Defs',
   'desc',
   'Desc',
-  'discard',
-  'Discard',
   'ellipse',
   'Ellipse',
   'feBlend',
@@ -351,8 +343,6 @@ const invalidElements = [
   'textPath',
   'tspan',
   'Tspan',
-  'unknown',
-  'Unknown',
   'use',
   'Use',
   'view',
@@ -373,8 +363,6 @@ const invalidElements = [
   'Blink',
   'center',
   'Center',
-  'command',
-  'Command',
   'dir',
   'Dir',
   'font',
diff --git a/tools/lib/http.js b/tools/lib/http.js
new file mode 100644
index 000000000..27ff970f4
--- /dev/null
+++ b/tools/lib/http.js
@@ -0,0 +1,6 @@
+module.exports = {
+  httpGet
+}
+function httpGet(url) {
+  return fetch(url).then((res) => res.text())
+}
diff --git a/tools/update-html-resources.js b/tools/update-html-resources.js
new file mode 100644
index 000000000..fcbdacbb0
--- /dev/null
+++ b/tools/update-html-resources.js
@@ -0,0 +1,105 @@
+'use strict'
+
+const fs = require('fs')
+const jsdom = require('jsdom')
+const { httpGet } = require('./lib/http')
+
+main()
+
+async function main() {
+  const [bcdJson, obsoleteHtml] = await Promise.all([
+    httpGet('https://unpkg.com/@mdn/browser-compat-data/data.json'),
+    httpGet('https://html.spec.whatwg.org/multipage/obsolete.html')
+  ])
+  const bcd = JSON.parse(bcdJson)
+
+  updateDeprecatedHTMLElements()
+  updateHTMLElements()
+  updateSVGElements()
+
+  // ------------------------------------------------------------------------------
+  // Update deprecated-html-elements.json
+  // ------------------------------------------------------------------------------
+  function updateDeprecatedHTMLElements() {
+    const DEPRECATED_HTML_ELEMENTS_PATH = require.resolve(
+      '../lib/utils/deprecated-html-elements.json'
+    )
+    const elements = new Set()
+
+    const domDl = jsdom.JSDOM.fragment(obsoleteHtml).querySelector(
+      '[id="non-conforming-features"] ~ dl'
+    )
+    for (const code of domDl.querySelectorAll('dt code')) {
+      const name = code.textContent.trim()
+      if (name) elements.add(name)
+    }
+
+    if (elements.size === 0) {
+      throw new Error('No deprecated HTML elements found')
+    }
+
+    fs.writeFileSync(
+      DEPRECATED_HTML_ELEMENTS_PATH,
+      `${JSON.stringify([...elements].sort(), null, 2)}\n`,
+      'utf8'
+    )
+  }
+
+  // ------------------------------------------------------------------------------
+  // Update html-elements.json
+  // ------------------------------------------------------------------------------
+  function updateHTMLElements() {
+    const HTML_ELEMENTS_PATH = require.resolve(
+      '../lib/utils/html-elements.json'
+    )
+    const elements = new Set()
+    const deprecatedHtmlElements = new Set(
+      require('../lib/utils/deprecated-html-elements.json')
+    )
+
+    for (const [name, element] of Object.entries(bcd.html.elements)) {
+      if (deprecatedHtmlElements.has(name)) {
+        continue
+      }
+      if (element.__compat.status.deprecated) {
+        continue
+      }
+      elements.add(name)
+    }
+
+    if (elements.size === 0) {
+      throw new Error('No HTML elements found')
+    }
+
+    fs.writeFileSync(
+      HTML_ELEMENTS_PATH,
+      `${JSON.stringify([...elements].sort(), null, 2)}\n`,
+      'utf8'
+    )
+  }
+
+  // ------------------------------------------------------------------------------
+  // Update svg-elements.json
+  // ------------------------------------------------------------------------------
+  function updateSVGElements() {
+    const SVG_ELEMENTS_PATH = require.resolve('../lib/utils/svg-elements.json')
+    const elements = new Set()
+
+    for (const [name, element] of Object.entries(bcd.svg.elements)) {
+      if (element.__compat.status.deprecated) {
+        continue
+      }
+      elements.add(name)
+    }
+
+    if (elements.size === 0) {
+      throw new Error('No SVG elements found')
+    }
+
+    fs.writeFileSync(
+      SVG_ELEMENTS_PATH,
+      `${JSON.stringify([...elements].sort(), null, 2)}\n`,
+      'utf8'
+    )
+  }
+}
diff --git a/tools/update-resources.js b/tools/update-resources.js
new file mode 100644
index 000000000..a157c61ef
--- /dev/null
+++ b/tools/update-resources.js
@@ -0,0 +1,4 @@
+'use strict'
+
+require('./update-vue3-export-names')
+require('./update-html-resources')
diff --git a/tools/update-vue3-export-names.js b/tools/update-vue3-export-names.js
index 37e07e03d..0dabecb3a 100644
--- a/tools/update-vue3-export-names.js
+++ b/tools/update-vue3-export-names.js
@@ -6,9 +6,8 @@
 
 const fs = require('fs')
 const path = require('path')
-const https = require('https')
-const { URL } = require('url')
 const tsParser = require('@typescript-eslint/parser')
+const { httpGet } = require('./lib/http')
 
 main()
 
@@ -144,33 +143,3 @@ async function resolveTypeContents(m) {
   }
   return await httpGet(`https://unpkg.com/${m}/${typesPath}`)
 }
-
-function httpGet(url) {
-  return new Promise((resolve, reject) => {
-    let result = ''
-    https
-      .get(url, (res) => {
-        if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400) {
-          // redirect
-          let redirectUrl = res.headers.location
-          if (!redirectUrl.startsWith('http')) {
-            const baseUrl = new URL(url)
-            baseUrl.pathname = redirectUrl
-            redirectUrl = String(baseUrl)
-          }
-          res.destroy()
-          resolve(httpGet(redirectUrl))
-          return
-        }
-        res.setEncoding('utf8')
-        res.on('data', (chunk) => {
-          result += String(chunk)
-        })
-        res.on('end', () => {
-          resolve(result)
-        })
-        res.on('error', reject)
-      })
-      .on('error', reject)
-  })
-}
diff --git a/tools/update.js b/tools/update.js
index de792d507..64da1be1b 100644
--- a/tools/update.js
+++ b/tools/update.js
@@ -11,7 +11,3 @@ require('./update-lib-flat-configs')
 require('./update-lib-index')
 require('./update-docs')
 require('./update-docs-rules-index')
-
-if (process.env.IN_VERSION_SCRIPT) {
-  require('./update-vue3-export-names')
-}