help-beta: Add prettier plugin for astro files.

Even though we have separate packages for `help-beta`, we have opted to
put the prettier plugin and config for astro files in the main project
itself, so that linting needs to be configured only at one place.
This commit is contained in:
Shubham Padia
2025-06-30 07:28:40 +00:00
committed by Tim Abbott
parent b630c1d175
commit f37ffd8937
9 changed files with 274 additions and 201 deletions

View File

@@ -1,8 +1,9 @@
---
import EmojiCodes from '../../../static/generated/emoji/emoji_codes.json';
import EmojiCodes from "../../../static/generated/emoji/emoji_codes.json";
const nameToCodePoint: {[key: string]: string} = EmojiCodes["name_to_codepoint"];
const rowHTML = (emoticon: string, codepoint: string, name: string) => (`
const nameToCodePoint: {[key: string]: string} =
EmojiCodes["name_to_codepoint"];
const rowHTML = (emoticon: string, codepoint: string, name: string) => `
<tr>
<td><code>${emoticon}</code></td>
<td>
@@ -12,14 +13,15 @@ const rowHTML = (emoticon: string, codepoint: string, name: string) => (`
class="emoji-big">
</td>
</tr>
`);
`;
let body = "";
const emoticonConversions: {[key: string]: string} = EmojiCodes["emoticon_conversions"]
const emoticonConversions: {[key: string]: string} =
EmojiCodes["emoticon_conversions"];
Object.keys(emoticonConversions).forEach((name: string) => {
const emoticon: string = emoticonConversions[name]!;
body += rowHTML(name, nameToCodePoint[emoticon.slice(1, -1)]!, emoticon)
})
body += rowHTML(name, nameToCodePoint[emoticon.slice(1, -1)]!, emoticon);
});
---
<table>

View File

@@ -13,13 +13,18 @@ const tree_with_removed_newlines = {
}
return true;
}),
}
};
const first_element = tree_with_removed_newlines.children[0];
assert(first_element?.type === "element" && ["ol", "ul"].includes(first_element.tagName));
assert(
first_element?.type === "element" &&
["ol", "ul"].includes(first_element.tagName),
);
const flattened = {
...first_element,
children: tree_with_removed_newlines.children.flatMap((other) => {
assert(other.type === "element" && other.tagName === first_element.tagName);
assert(
other.type === "element" && other.tagName === first_element.tagName,
);
return other.children;
}),
};

View File

@@ -1,5 +1,5 @@
---
import ZulipIconsKeyboard from "~icons/zulip-icon/keyboard"
import ZulipIconsKeyboard from "~icons/zulip-icon/keyboard";
let {title} = Astro.props;
if (!title) {
@@ -17,7 +17,10 @@ Link: https://github.com/withastro/starlight/pull/2261
-->
<aside aria-label={title} class={`starlight-aside starlight-aside--tip`}>
<p class="starlight-aside__title" aria-hidden="true">
<ZulipIconsKeyboard fill="currentColor" class="starlight-aside__icon" />{title}
<ZulipIconsKeyboard
fill="currentColor"
class="starlight-aside__icon"
/>{title}
</p>
<div class="starlight-aside__content">
<slot />

View File

@@ -17,142 +17,142 @@ import RawZulipIconInfo from "~icons/zulip-icon/info?raw";
import RawZulipIconHelp from "~icons/zulip-icon/help?raw";
const PERSONAL_SETTINGS_TYPE = "Personal settings";
const ORGANIZATION_SETTINGS_TYPE = "Organization settings"
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]: {
setting_type: string,
setting_name: string,
setting_link: 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
// be used to get to that setting
"profile": {
profile: {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Profile",
setting_link: "/#settings/profile"
setting_link: "/#settings/profile",
},
"account-and-privacy": {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Account & privacy",
setting_link: "/#settings/account-and-privacy"
setting_link: "/#settings/account-and-privacy",
},
"preferences": {
preferences: {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Preferences",
setting_link: "/#settings/preferences"
setting_link: "/#settings/preferences",
},
"notifications": {
notifications: {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Notifications",
setting_link: "/#settings/notifications"
setting_link: "/#settings/notifications",
},
"your-bots": {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Bots",
setting_link: "/#settings/your-bots"
setting_link: "/#settings/your-bots",
},
"alert-words": {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Alert words",
setting_link: "/#settings/alert-words"
setting_link: "/#settings/alert-words",
},
"uploaded-files": {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Uploaded files",
setting_link: "/#settings/uploaded-files"
setting_link: "/#settings/uploaded-files",
},
"topics": {
topics: {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Topics",
setting_link: "/#settings/topics"
setting_link: "/#settings/topics",
},
"muted-users": {
setting_type: PERSONAL_SETTINGS_TYPE,
setting_name: "Muted users",
setting_link: "/#settings/muted-users"
setting_link: "/#settings/muted-users",
},
"organization-profile": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Organization profile",
setting_link: "/#organization/organization-profile"
setting_link: "/#organization/organization-profile",
},
"organization-settings": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Organization settings",
setting_link: "/#organization/organization-settings"
setting_link: "/#organization/organization-settings",
},
"organization-permissions": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Organization permissions",
setting_link: "/#organization/organization-permissions"
setting_link: "/#organization/organization-permissions",
},
"default-user-settings": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Default user settings",
setting_link: "/#organization/organization-level-user-defaults"
setting_link: "/#organization/organization-level-user-defaults",
},
"emoji-settings": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Custom emoji",
setting_link: "/#organization/emoji-settings"
setting_link: "/#organization/emoji-settings",
},
"auth-methods": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Authentication methods",
setting_link: "/#organization/auth-methods"
setting_link: "/#organization/auth-methods",
},
"users": {
users: {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Users",
setting_link: "/#organization/users/active"
setting_link: "/#organization/users/active",
},
"deactivated": {
deactivated: {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Users",
setting_link: "/#organization/users/deactivated"
setting_link: "/#organization/users/deactivated",
},
"invitations": {
invitations: {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Users",
setting_link: "/#organization/users/invitations"
setting_link: "/#organization/users/invitations",
},
"bot-list-admin": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Bots",
setting_link: "/#organization/bot-list-admin"
setting_link: "/#organization/bot-list-admin",
},
"default-channels-list": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Default channels",
setting_link: "/#organization/default-channels-list"
setting_link: "/#organization/default-channels-list",
},
"linkifier-settings": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Linkifiers",
setting_link: "/#organization/linkifier-settings"
setting_link: "/#organization/linkifier-settings",
},
"playground-settings": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Code playgrounds",
setting_link: "/#organization/playground-settings"
setting_link: "/#organization/playground-settings",
},
"profile-field-settings": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Custom profile fields",
setting_link: "/#organization/profile-field-settings"
setting_link: "/#organization/profile-field-settings",
},
"data-exports-admin": {
setting_type: ORGANIZATION_SETTINGS_TYPE,
setting_name: "Data exports",
setting_link: "/#organization/data-exports-admin"
}
setting_link: "/#organization/data-exports-admin",
},
};
type RelativeLinkInfo = {
@@ -165,7 +165,7 @@ const default_template_for_relative_links = `
<li>Click on the <strong>gear</strong> (${RawZulipIconGear}) icon in the upper right corner of the web or desktop app.</li>
<li>Select {item}.</li>
</ol>
`
`;
const relative_link_mapping: Record<
string,
@@ -288,7 +288,6 @@ const relative_link_mapping: Record<
},
};
const getSettingsMarkdown = (setting_type: string, setting_name: string) => `
<ol>
<li>
@@ -302,17 +301,14 @@ const getSettingsMarkdown = (setting_type: string, setting_name: string) => `
On the left, click <b>${setting_name}</b>.
</li>
</ol>
`
`;
const getSettingsHTML = (
setting_key: string,
SHOW_RELATIVE_LINKS: boolean
SHOW_RELATIVE_LINKS: boolean,
): string => {
const {
setting_type,
setting_name,
setting_link,
} = setting_link_mapping[setting_key]!;
const {setting_type, setting_name, setting_link} =
setting_link_mapping[setting_key]!;
if (!SHOW_RELATIVE_LINKS) {
return getSettingsMarkdown(setting_type, setting_name);
@@ -326,23 +322,29 @@ const getSettingsHTML = (
// As for the the case of "Users", it refers to the Users tab in
// organization settings. Since the users tab has multiple sub tabs
// like active, deactivated etc., we need a way to point to them.
const label = (setting_name === "Bots" || setting_name === "Users")
const label =
setting_name === "Bots" || setting_name === "Users"
? `Navigate to the ${relativeLink} tab of the <b>${setting_type}</b> menu.`
: `Go to ${relativeLink}.`;
return `<ol>
<li>${label}</li>
</ol>`;
}
};
const RELATIVE_NAVIGATION_HANDLERS_BY_TYPE: Record<string, (key: string) => string> = {};
const RELATIVE_NAVIGATION_HANDLERS_BY_TYPE: Record<
string,
(key: string) => string
> = {};
for (const type in relative_link_mapping) {
const {data, template, is_link_relative} = relative_link_mapping[type]!;
RELATIVE_NAVIGATION_HANDLERS_BY_TYPE[type] = (key: string) => {
const {label, relative_link} = data[key]!;
const formattedItem = is_link_relative() ? `<a href="${relative_link}">${label}</a>` : `<strong>${label}</strong>`;
const formattedItem = is_link_relative()
? `<a href="${relative_link}">${label}</a>`
: `<strong>${label}</strong>`;
return template.replace("{item}", formattedItem);
};
}
@@ -350,8 +352,13 @@ for (const type in relative_link_mapping) {
const {identifier} = Astro.props;
const navigation_link_type = identifier.split("/")[0];
if (navigation_link_type !== "settings" && navigation_link_type !== "relative" ) {
throw new Error("Invalid navigation link type. Only `settings` or `relative` is allowed.");
if (
navigation_link_type !== "settings" &&
navigation_link_type !== "relative"
) {
throw new Error(
"Invalid navigation link type. Only `settings` or `relative` is allowed.",
);
}
let resultHTML: string | undefined;
@@ -363,6 +370,6 @@ if (navigation_link_type === "settings") {
resultHTML = RELATIVE_NAVIGATION_HANDLERS_BY_TYPE[link_type]!(key);
}
assert(resultHTML !== undefined);
---
<Fragment set:html={resultHTML} />

View File

@@ -148,6 +148,7 @@
"openapi-examples-validator": "^6.0.1",
"preact": "^10.24.3",
"prettier": "~3.5.3",
"prettier-plugin-astro": "^0.14.1",
"puppeteer": "^24.1.1",
"source-map": "npm:source-map-js@^1.2.1",
"stylelint": "^16.2.0",

41
pnpm-lock.yaml generated
View File

@@ -464,6 +464,9 @@ importers:
prettier:
specifier: ~3.5.3
version: 3.5.3
prettier-plugin-astro:
specifier: ^0.14.1
version: 0.14.1
puppeteer:
specifier: ^24.1.1
version: 24.10.2(typescript@5.8.3)
@@ -511,7 +514,7 @@ importers:
dependencies:
'@astrojs/check':
specifier: ^0.9.3
version: 0.9.4(prettier@3.5.3)(typescript@5.8.3)
version: 0.9.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)
'@astrojs/starlight':
specifier: ^0.34.2
version: 0.34.4(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))
@@ -7571,6 +7574,10 @@ packages:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
prettier-plugin-astro@0.14.1:
resolution: {integrity: sha512-RiBETaaP9veVstE4vUwSIcdATj6dKmXljouXc/DDNwBSPTp8FRkLGDSGFClKsAFeeg+13SB0Z1JZvbD76bigJw==}
engines: {node: ^14.15.0 || >=16.0.0}
prettier@2.8.7:
resolution: {integrity: sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==}
engines: {node: '>=10.13.0'}
@@ -8012,6 +8019,9 @@ packages:
rw@1.3.3:
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
s.color@0.0.15:
resolution: {integrity: sha512-AUNrbEUHeKY8XsYr/DYpl+qk5+aM+DChopnWOPEzn8YKzOhv4l2zH6LzZms3tOZP3wwdOyc0RmTciyi46HLIuA==}
safe-array-concat@1.1.3:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'}
@@ -8037,6 +8047,9 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sass-formatter@0.7.9:
resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==}
sass@1.89.2:
resolution: {integrity: sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==}
engines: {node: '>=14.0.0'}
@@ -8455,6 +8468,9 @@ packages:
stylis@4.2.0:
resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
suf-log@2.5.3:
resolution: {integrity: sha512-KvC8OPjzdNOe+xQ4XWJV2whQA0aM1kGVczMQ8+dStAO6KfEB140JEVQ9dE76ONZ0/Ylf67ni4tILPJB41U0eow==}
supercluster@7.1.5:
resolution: {integrity: sha512-EulshI3pGUM66o6ZdH3ReiFcvHpM3vAigyK+vcxdjpJyEbIIrtbmBdY23mGgnI24uXiGFvrGq9Gkum/8U7vJWg==}
@@ -9679,9 +9695,9 @@ snapshots:
'@csstools/css-tokenizer': 3.0.4
lru-cache: 10.4.3
'@astrojs/check@0.9.4(prettier@3.5.3)(typescript@5.8.3)':
'@astrojs/check@0.9.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)':
dependencies:
'@astrojs/language-server': 2.15.4(prettier@3.5.3)(typescript@5.8.3)
'@astrojs/language-server': 2.15.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)
chokidar: 4.0.3
kleur: 4.1.5
typescript: 5.8.3
@@ -9694,7 +9710,7 @@ snapshots:
'@astrojs/internal-helpers@0.6.1': {}
'@astrojs/language-server@2.15.4(prettier@3.5.3)(typescript@5.8.3)':
'@astrojs/language-server@2.15.4(prettier-plugin-astro@0.14.1)(prettier@3.5.3)(typescript@5.8.3)':
dependencies:
'@astrojs/compiler': 2.12.2
'@astrojs/yaml2ts': 0.2.2
@@ -9716,6 +9732,7 @@ snapshots:
vscode-uri: 3.1.0
optionalDependencies:
prettier: 3.5.3
prettier-plugin-astro: 0.14.1
transitivePeerDependencies:
- typescript
@@ -18087,6 +18104,12 @@ snapshots:
prelude-ls@1.2.1: {}
prettier-plugin-astro@0.14.1:
dependencies:
'@astrojs/compiler': 2.12.2
prettier: 3.5.3
sass-formatter: 0.7.9
prettier@2.8.7:
optional: true
@@ -18705,6 +18728,8 @@ snapshots:
rw@1.3.3: {}
s.color@0.0.15: {}
safe-array-concat@1.1.3:
dependencies:
call-bind: 1.0.8
@@ -18732,6 +18757,10 @@ snapshots:
safer-buffer@2.1.2: {}
sass-formatter@0.7.9:
dependencies:
suf-log: 2.5.3
sass@1.89.2:
dependencies:
chokidar: 4.0.3
@@ -19312,6 +19341,10 @@ snapshots:
stylis@4.2.0: {}
suf-log@2.5.3:
dependencies:
s.color: 0.0.15
supercluster@7.1.5:
dependencies:
kdbush: 3.0.0

View File

@@ -1,6 +1,7 @@
export default {
bracketSpacing: false,
trailingComma: "all",
plugins: ["prettier-plugin-astro"],
overrides: [
{
files: ["tsconfig.json"],
@@ -15,5 +16,11 @@ export default {
embeddedLanguageFormatting: "off",
},
},
{
files: "*.astro",
options: {
parser: "astro",
},
},
],
};

View File

@@ -56,6 +56,7 @@ def run() -> None:
"yml",
],
"frontend": [
"astro",
"cjs",
"css",
"cts",
@@ -166,7 +167,21 @@ def run() -> None:
linter_config.external_linter(
"prettier",
["node_modules/.bin/prettier", "--cache", "--check", "--log-level=warn"],
["cjs", "css", "cts", "flow", "js", "json", "md", "mjs", "mts", "ts", "yaml", "yml"],
[
"astro",
"cjs",
"css",
"cts",
"flow",
"js",
"json",
"md",
"mjs",
"mts",
"ts",
"yaml",
"yml",
],
fix_arg=["--write"],
description="Formats CSS, JavaScript, YAML",
)

View File

@@ -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, 3) # bumped 2025-06-25 to upgrade JavaScript dependencies
PROVISION_VERSION = (333, 4) # bumped 2025-06-30 to add prettier-plugin-astro