mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 14:15:24 +00:00
144 lines
4.5 KiB
JavaScript
144 lines
4.5 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Builds src/ui/settings/settings-search-index.ts: the i18n keys each core
|
|
* settings section shows, so the Settings search can match on any label in
|
|
* a section without mounting it. Run it after changing a settings section.
|
|
*
|
|
* --check fails when the committed file is out of date.
|
|
*/
|
|
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
|
|
const ROOT = path.resolve(__dirname, "..");
|
|
const SIDEBAR = path.join(ROOT, "src", "ui", "sidebar");
|
|
const OUT = path.join(
|
|
ROOT,
|
|
"src",
|
|
"ui",
|
|
"settings",
|
|
"settings-search-index.ts",
|
|
);
|
|
|
|
function keysIn(text) {
|
|
return [
|
|
...new Set([...text.matchAll(/\bt\(\s*"([\w.-]+)"/g)].map((m) => m[1])),
|
|
];
|
|
}
|
|
|
|
function read(file) {
|
|
return fs.readFileSync(path.join(SIDEBAR, file), "utf8");
|
|
}
|
|
|
|
/** The body of one exported or local function, by name. */
|
|
function functionBody(source, name) {
|
|
const start = source.search(new RegExp(`function ${name}\\b`));
|
|
if (start < 0) throw new Error(`No function ${name}`);
|
|
const next = source.slice(start + 1).search(/\n(export )?function \w+/);
|
|
return next < 0 ? source.slice(start) : source.slice(start, start + 1 + next);
|
|
}
|
|
|
|
/** Profile sections, split on their AccordionSection ids. */
|
|
function profileSections() {
|
|
const source = read("UserProfilePanel.tsx");
|
|
const lines = source.split("\n");
|
|
const starts = [];
|
|
lines.forEach((line, i) => {
|
|
if (/^\s{6}<AccordionSection\b/.test(line)) starts.push(i);
|
|
});
|
|
const out = {};
|
|
starts.forEach((start, k) => {
|
|
const end = k + 1 < starts.length ? starts[k + 1] : lines.length;
|
|
const chunk = lines.slice(start, end).join("\n");
|
|
const id = (chunk.match(/\bid="([^"]+)"/) || [])[1];
|
|
if (id) out[id] = keysIn(chunk);
|
|
});
|
|
out.interface = [
|
|
...new Set([
|
|
...(out.interface ?? []),
|
|
...keysIn(read("InterfacePresetSettings.tsx")),
|
|
]),
|
|
];
|
|
out.security = [
|
|
...new Set([
|
|
...(out.security ?? []),
|
|
...keysIn(read("AuthEnrollmentSections.tsx")),
|
|
...keysIn(functionBody(source, "PasswordChangeSection")),
|
|
]),
|
|
];
|
|
out["api-keys"] = [
|
|
...new Set([
|
|
...(out["api-keys"] ?? []),
|
|
...keysIn(functionBody(source, "NewApiKeyDialog")),
|
|
]),
|
|
];
|
|
out.keybindings = keysIn(
|
|
fs.readFileSync(
|
|
path.join(ROOT, "src", "ui", "settings", "KeybindingsSettings.tsx"),
|
|
"utf8",
|
|
),
|
|
);
|
|
return out;
|
|
}
|
|
|
|
function adminSections() {
|
|
const settings = read("AdminSettingsSections.tsx");
|
|
const management = read("AdminManagementSections.tsx");
|
|
return {
|
|
"admin-general": [
|
|
...new Set([
|
|
...keysIn(functionBody(settings, "AdminGeneralSettingsSection")),
|
|
...keysIn(read("AdminPluginDeveloperMode.tsx")),
|
|
]),
|
|
],
|
|
"admin-users": [
|
|
...new Set([
|
|
...keysIn(functionBody(management, "AdminUsersSection")),
|
|
...keysIn(read("AdminUserDialogs.tsx")),
|
|
]),
|
|
],
|
|
"admin-sessions": keysIn(functionBody(management, "AdminSessionsSection")),
|
|
"admin-roles": keysIn(functionBody(management, "AdminRolesSection")),
|
|
"admin-host-defaults": [
|
|
...new Set([
|
|
...keysIn(functionBody(settings, "AdminHostDefaultsSection")),
|
|
...keysIn(read("AdminHostTags.tsx")),
|
|
]),
|
|
],
|
|
"admin-branding": keysIn(read("AdminBrandingSection.tsx")),
|
|
"admin-database": keysIn(functionBody(settings, "AdminDatabaseSection")),
|
|
"admin-ssl": keysIn(functionBody(settings, "AdminSSLSection")),
|
|
"admin-api-keys": keysIn(read("AdminApiKeysSection.tsx")),
|
|
"admin-audit-log": keysIn(read("AdminAuditLogSection.tsx")),
|
|
};
|
|
}
|
|
|
|
function render() {
|
|
const index = { ...profileSections(), ...adminSections() };
|
|
const body = Object.entries(index)
|
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
.map(
|
|
([id, keys]) =>
|
|
` ${JSON.stringify(id)}: [\n${keys
|
|
.sort()
|
|
.map((key) => ` ${JSON.stringify(key)},`)
|
|
.join("\n")}\n ],`,
|
|
)
|
|
.join("\n");
|
|
return `// Generated by scripts/generate-settings-search-index.cjs. Do not edit.\n\n/** The i18n keys each core settings section shows, for search. */\nexport const SETTINGS_SEARCH_INDEX: Record<string, string[]> = {\n${body}\n};\n`;
|
|
}
|
|
|
|
const next = render();
|
|
if (process.argv.includes("--check")) {
|
|
const current = fs.existsSync(OUT) ? fs.readFileSync(OUT, "utf8") : "";
|
|
if (current !== next) {
|
|
console.error(
|
|
"src/ui/settings/settings-search-index.ts is out of date. Run: node scripts/generate-settings-search-index.cjs",
|
|
);
|
|
process.exit(1);
|
|
}
|
|
} else {
|
|
fs.writeFileSync(OUT, next);
|
|
console.log(`Wrote ${path.relative(ROOT, OUT)}`);
|
|
}
|