From aebbdee5b5fac7481bfb1d3eaf71f803b505c31a Mon Sep 17 00:00:00 2001 From: Shubham Padia Date: Mon, 30 Jun 2025 09:36:51 +0000 Subject: [PATCH] help-beta: Add eslint plugin for astro files. --- eslint.config.js | 2 + .../src/components/EmoticonTranslations.astro | 11 ++- help-beta/src/components/FlattenList.astro | 5 +- help-beta/src/components/KeyboardTip.astro | 1 + .../src/components/NavigationSteps.astro | 39 +++++---- package.json | 2 + pnpm-lock.yaml | 83 +++++++++++++++++++ tools/lint | 2 +- version.py | 2 +- 9 files changed, 120 insertions(+), 27 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 74064f9148..75b6c4d067 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -2,6 +2,7 @@ import {FlatCompat} from "@eslint/eslintrc"; import js from "@eslint/js"; import confusingBrowserGlobals from "confusing-browser-globals"; import prettier from "eslint-config-prettier"; +import {configs as astroConfigs} from "eslint-plugin-astro"; import formatjs from "eslint-plugin-formatjs"; import importPlugin from "eslint-plugin-import"; import noJquery from "eslint-plugin-no-jquery"; @@ -291,4 +292,5 @@ export default tseslint.config( "unicorn/prefer-string-replace-all": "off", }, }, + ...astroConfigs.recommended, ); diff --git a/help-beta/src/components/EmoticonTranslations.astro b/help-beta/src/components/EmoticonTranslations.astro index 5d1bc2f307..e30d1e0a35 100644 --- a/help-beta/src/components/EmoticonTranslations.astro +++ b/help-beta/src/components/EmoticonTranslations.astro @@ -1,8 +1,7 @@ --- import EmojiCodes from "../../../static/generated/emoji/emoji_codes.json"; -const nameToCodePoint: {[key: string]: string} = - EmojiCodes["name_to_codepoint"]; +const nameToCodePoint: Record = EmojiCodes.name_to_codepoint; const rowHTML = (emoticon: string, codepoint: string, name: string) => ` ${emoticon} @@ -16,12 +15,12 @@ const rowHTML = (emoticon: string, codepoint: string, name: string) => ` `; let body = ""; -const emoticonConversions: {[key: string]: string} = - EmojiCodes["emoticon_conversions"]; -Object.keys(emoticonConversions).forEach((name: string) => { +const emoticonConversions: Record = + EmojiCodes.emoticon_conversions; +for (const name of Object.keys(emoticonConversions)) { const emoticon: string = emoticonConversions[name]!; body += rowHTML(name, nameToCodePoint[emoticon.slice(1, -1)]!, emoticon); -}); +} --- diff --git a/help-beta/src/components/FlattenList.astro b/help-beta/src/components/FlattenList.astro index 8fc6cf320e..25c5bf16c7 100644 --- a/help-beta/src/components/FlattenList.astro +++ b/help-beta/src/components/FlattenList.astro @@ -1,5 +1,6 @@ --- import assert from "node:assert/strict"; + import {fromHtml} from "hast-util-from-html"; import {toHtml} from "hast-util-to-html"; @@ -15,14 +16,14 @@ const tree_with_removed_newlines = { }), }; const first_element = tree_with_removed_newlines.children[0]; -assert( +assert.ok( first_element?.type === "element" && ["ol", "ul"].includes(first_element.tagName), ); const flattened = { ...first_element, children: tree_with_removed_newlines.children.flatMap((other) => { - assert( + assert.ok( other.type === "element" && other.tagName === first_element.tagName, ); return other.children; diff --git a/help-beta/src/components/KeyboardTip.astro b/help-beta/src/components/KeyboardTip.astro index 6aa63ce5e1..2916a36ad6 100644 --- a/help-beta/src/components/KeyboardTip.astro +++ b/help-beta/src/components/KeyboardTip.astro @@ -1,4 +1,5 @@ --- +/* eslint-disable-next-line import/extensions */ import ZulipIconsKeyboard from "~icons/zulip-icon/keyboard"; let {title} = Astro.props; diff --git a/help-beta/src/components/NavigationSteps.astro b/help-beta/src/components/NavigationSteps.astro index 8a2eaf0d65..92447ddd77 100644 --- a/help-beta/src/components/NavigationSteps.astro +++ b/help-beta/src/components/NavigationSteps.astro @@ -1,20 +1,24 @@ --- -import {SHOW_RELATIVE_LINKS, SHOW_BILLING_HELP_LINKS} from "astro:env/client"; import assert from "node:assert"; -import RawZulipIconGear from "~icons/zulip-icon/gear?raw"; -import RawZulipIconHash from "~icons/zulip-icon/hash?raw"; -import RawZulipIconTool from "~icons/zulip-icon/tool?raw"; -import RawZulipIconBuilding from "~icons/zulip-icon/building?raw"; -import RawZulipIconUserGroupCog from "~icons/zulip-icon/user-group-cog?raw"; + +import {SHOW_BILLING_HELP_LINKS, SHOW_RELATIVE_LINKS} from "astro:env/client"; + +/* eslint-disable import/extensions */ import RawZulipIconBarChart from "~icons/zulip-icon/bar-chart?raw"; -import RawZulipIconGitPullRequest from "~icons/zulip-icon/git-pull-request?raw"; -import RawZulipIconRocket from "~icons/zulip-icon/rocket?raw"; +import RawZulipIconBuilding from "~icons/zulip-icon/building?raw"; import RawZulipIconCreditCard from "~icons/zulip-icon/credit-card?raw"; -import RawZulipIconKeyboard from "~icons/zulip-icon/keyboard?raw"; import RawZulipIconEdit from "~icons/zulip-icon/edit?raw"; -import RawZulipIconManageSearch from "~icons/zulip-icon/manage-search?raw"; -import RawZulipIconInfo from "~icons/zulip-icon/info?raw"; +import RawZulipIconGear from "~icons/zulip-icon/gear?raw"; +import RawZulipIconGitPullRequest from "~icons/zulip-icon/git-pull-request?raw"; +import RawZulipIconHash from "~icons/zulip-icon/hash?raw"; import RawZulipIconHelp from "~icons/zulip-icon/help?raw"; +import RawZulipIconInfo from "~icons/zulip-icon/info?raw"; +import RawZulipIconKeyboard from "~icons/zulip-icon/keyboard?raw"; +import RawZulipIconManageSearch from "~icons/zulip-icon/manage-search?raw"; +import RawZulipIconRocket from "~icons/zulip-icon/rocket?raw"; +import RawZulipIconTool from "~icons/zulip-icon/tool?raw"; +import RawZulipIconUserGroupCog from "~icons/zulip-icon/user-group-cog?raw"; +/* eslint-enable import/extensions */ const PERSONAL_SETTINGS_TYPE = "Personal settings"; const ORGANIZATION_SETTINGS_TYPE = "Organization settings"; @@ -22,13 +26,14 @@ const ORGANIZATION_SETTINGS_TYPE = "Organization settings"; // This list has been transformed one-off from `help_settings_links.py`, we // have added a comment in that file to update this list in case of any // changes. -const setting_link_mapping: { - [key: string]: { +const setting_link_mapping: Record< + string, + { setting_type: string; setting_name: string; setting_link: string; - }; -} = { + } +> = { // a mapping from the setting identifier that is the same as the final URL // breadcrumb to that setting to the name of its setting type, the setting // name as it appears in the user interface, and a relative link that can @@ -337,7 +342,7 @@ const RELATIVE_NAVIGATION_HANDLERS_BY_TYPE: Record< (key: string) => string > = {}; -for (const type in relative_link_mapping) { +for (const type of Object.keys(relative_link_mapping)) { const {data, template, is_link_relative} = relative_link_mapping[type]!; RELATIVE_NAVIGATION_HANDLERS_BY_TYPE[type] = (key: string) => { @@ -369,7 +374,7 @@ if (navigation_link_type === "settings") { const key = identifier.split("/")[2]; resultHTML = RELATIVE_NAVIGATION_HANDLERS_BY_TYPE[link_type]!(key); } -assert(resultHTML !== undefined); +assert.ok(resultHTML !== undefined); --- diff --git a/package.json b/package.json index d5bfc73002..ef88a5a1cf 100644 --- a/package.json +++ b/package.json @@ -124,6 +124,7 @@ "@types/winchan": "^0.2.0", "@typescript-eslint/eslint-plugin": "^8.2.0", "@typescript-eslint/parser": "^8.2.0", + "astro-eslint-parser": "^1.2.2", "babel-plugin-istanbul": "^7.0.0", "callsites": "^4.2.0", "cldr-annotations-derived-full": "^47.0.0", @@ -137,6 +138,7 @@ "eslint": "^9.15.0", "eslint-config-prettier": "^10.0.1", "eslint-import-resolver-webpack": "^0.13.4", + "eslint-plugin-astro": "^1.3.1", "eslint-plugin-formatjs": "^5.0.0", "eslint-plugin-import": "^2.22.0", "eslint-plugin-no-jquery": "^3.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index acdfa07a7b..ddd8163fde 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -392,6 +392,9 @@ importers: '@typescript-eslint/parser': specifier: ^8.2.0 version: 8.35.0(eslint@9.29.0(jiti@1.21.7))(typescript@5.8.3) + astro-eslint-parser: + specifier: ^1.2.2 + version: 1.2.2 babel-plugin-istanbul: specifier: ^7.0.0 version: 7.0.0 @@ -431,6 +434,9 @@ importers: eslint-import-resolver-webpack: specifier: ^0.13.4 version: 0.13.10(eslint-plugin-import@2.32.0)(webpack@5.99.9) + eslint-plugin-astro: + specifier: ^1.3.1 + version: 1.3.1(eslint@9.29.0(jiti@1.21.7)) eslint-plugin-formatjs: specifier: ^5.0.0 version: 5.4.0(eslint@9.29.0(jiti@1.21.7))(typescript@5.8.3) @@ -2352,6 +2358,10 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@pkgr/core@0.2.7': + resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@plotly/d3-sankey-circular@0.33.1': resolution: {integrity: sha512-FgBV1HEvCr3DV7RHhDsPXyryknucxtfnLwPtCKKxdolKyTFYoLX/ibEfX39iFYIL7DYbVeRtP43dbFcrHNE+KQ==} @@ -3291,6 +3301,10 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true + astro-eslint-parser@1.2.2: + resolution: {integrity: sha512-JepyLROIad6f44uyqMF6HKE2QbunNzp3mYKRcPoDGt0QkxXmH222FAFC64WTyQu2Kg8NNEXHTN/sWuUId9sSxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + astro-expressive-code@0.41.2: resolution: {integrity: sha512-HN0jWTnhr7mIV/2e6uu4PPRNNo/k4UEgTLZqbp3MrHU+caCARveG2yZxaZVBmxyiVdYqW5Pd3u3n2zjnshixbw==} peerDependencies: @@ -3301,6 +3315,12 @@ packages: engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true + astrojs-compiler-sync@1.1.1: + resolution: {integrity: sha512-0mKvB9sDQRIZPsEJadw6OaFbGJ92cJPPR++ICca9XEyiUAZqgVuk25jNmzHPT0KF80rI94trSZrUR5iHFXGGOQ==} + engines: {node: ^18.18.0 || >=20.9.0} + peerDependencies: + '@astrojs/compiler': '>=0.27.0' + async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} @@ -4630,6 +4650,12 @@ packages: engines: {node: '>=6.0'} hasBin: true + eslint-compat-utils@0.6.5: + resolution: {integrity: sha512-vAUHYzue4YAa2hNACjB8HvUQj5yehAZgiClyFVVom9cP8z5NSFq3PwB/TtJslN2zAMgRX6FCFCjYBbQh71g5RQ==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + eslint-config-prettier@10.1.5: resolution: {integrity: sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==} hasBin: true @@ -4667,6 +4693,12 @@ packages: eslint-import-resolver-webpack: optional: true + eslint-plugin-astro@1.3.1: + resolution: {integrity: sha512-2XaLCMQm8htW1UvJvy1Zcmg8l0ziskitiUfJTn/w1Mk7r4Mxj0fZeNpN6UTNrm64XBIXSa5h8UCGrg8mdu47+g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.57.0' + eslint-plugin-formatjs@5.4.0: resolution: {integrity: sha512-ezZdP9i8qjOqZP1PdIjjwL6kLPYFWcqkvlhm/sBbFWkf1xZ00wurXr2+p9YQi+dXQdZvJN4KtvOFHU/hfqx2BQ==} peerDependencies: @@ -8541,6 +8573,10 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + synckit@0.11.8: + resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==} + engines: {node: ^14.18.0 || >=16.0.0} + table@6.9.0: resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} engines: {node: '>=10.0.0'} @@ -11638,6 +11674,8 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@pkgr/core@0.2.7': {} + '@plotly/d3-sankey-circular@0.33.1': dependencies: d3-array: 1.2.4 @@ -12732,6 +12770,23 @@ snapshots: astring@1.9.0: {} + astro-eslint-parser@1.2.2: + dependencies: + '@astrojs/compiler': 2.12.2 + '@typescript-eslint/scope-manager': 8.35.0 + '@typescript-eslint/types': 8.35.0 + astrojs-compiler-sync: 1.1.1(@astrojs/compiler@2.12.2) + debug: 4.4.1 + entities: 6.0.1 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + fast-glob: 3.3.3 + is-glob: 4.0.3 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + astro-expressive-code@0.41.2(astro@5.10.1(@types/node@22.15.33)(encoding@0.1.13)(jiti@1.21.7)(rollup@4.44.0)(sass@1.89.2)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0)): dependencies: astro: 5.10.1(@types/node@22.15.33)(encoding@0.1.13)(jiti@1.21.7)(rollup@4.44.0)(sass@1.89.2)(terser@5.43.1)(typescript@5.8.3)(yaml@2.8.0) @@ -12837,6 +12892,11 @@ snapshots: - uploadthing - yaml + astrojs-compiler-sync@1.1.1(@astrojs/compiler@2.12.2): + dependencies: + '@astrojs/compiler': 2.12.2 + synckit: 0.11.8 + async-function@1.0.0: {} async@3.2.6: {} @@ -14313,6 +14373,11 @@ snapshots: optionalDependencies: source-map: source-map-js@1.2.1 + eslint-compat-utils@0.6.5(eslint@9.29.0(jiti@1.21.7)): + dependencies: + eslint: 9.29.0(jiti@1.21.7) + semver: 7.7.2 + eslint-config-prettier@10.1.5(eslint@9.29.0(jiti@1.21.7)): dependencies: eslint: 9.29.0(jiti@1.21.7) @@ -14353,6 +14418,20 @@ snapshots: transitivePeerDependencies: - supports-color + eslint-plugin-astro@1.3.1(eslint@9.29.0(jiti@1.21.7)): + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.29.0(jiti@1.21.7)) + '@jridgewell/sourcemap-codec': 1.5.0 + '@typescript-eslint/types': 8.35.0 + astro-eslint-parser: 1.2.2 + eslint: 9.29.0(jiti@1.21.7) + eslint-compat-utils: 0.6.5(eslint@9.29.0(jiti@1.21.7)) + globals: 15.15.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.0 + transitivePeerDependencies: + - supports-color + eslint-plugin-formatjs@5.4.0(eslint@9.29.0(jiti@1.21.7))(typescript@5.8.3): dependencies: '@formatjs/icu-messageformat-parser': 2.11.2 @@ -19440,6 +19519,10 @@ snapshots: symbol-tree@3.2.4: {} + synckit@0.11.8: + dependencies: + '@pkgr/core': 0.2.7 + table@6.9.0: dependencies: ajv: 8.17.1 diff --git a/tools/lint b/tools/lint index 602e8a8029..ce4856b49c 100755 --- a/tools/lint +++ b/tools/lint @@ -83,7 +83,7 @@ def run() -> None: linter_config.external_linter( "eslint", ["node_modules/.bin/eslint", "--max-warnings=0", "--cache"], - ["cjs", "cts", "js", "mjs", "mts", "ts"], + ["astro", "cjs", "cts", "js", "mjs", "mts", "ts"], fix_arg="--fix", description="Standard JavaScript style and formatting linter (config: eslint.config.js).", ) diff --git a/version.py b/version.py index c0221c9630..acd83c20da 100644 --- a/version.py +++ b/version.py @@ -49,4 +49,4 @@ API_FEATURE_LEVEL = 398 # historical commits sharing the same major version, in which case a # minor version bump suffices. -PROVISION_VERSION = (333, 4) # bumped 2025-06-30 to add prettier-plugin-astro +PROVISION_VERSION = (333, 5) # bumped 2025-06-30 to add eslint-plugin-astro