mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 07:05:24 +00:00
feat: type the plugin host record, move plugin strings out of core and add lint checks
This commit is contained in:
1 parent
bba06f7ff6
commit
b8bbcd2196
626 files changed
+23884
-4590
No files matched your search
@@ -0,0 +1,281 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* @termix/plugin-sdk/ui is public API, implemented by
|
||||
* src/ui/plugin-host/sdk-ui.ts. Adding to it is a contract change and
|
||||
* removing from it is a breaking one, so neither should happen by accident.
|
||||
*
|
||||
* Resolves every name the module exports (through its `export *` lines too)
|
||||
* and fails when that differs from ALLOWED. A new export goes on the list in
|
||||
* the same change, which is what makes it a deliberate one. Only generic
|
||||
* shell pieces belong here: anything one feature needs lives in its plugin.
|
||||
*
|
||||
* --list prints what the module exports now.
|
||||
*/
|
||||
|
||||
const path = require("node:path");
|
||||
|
||||
const ROOT = path.resolve(__dirname, "..");
|
||||
const SDK_UI = path.join(ROOT, "src", "ui", "plugin-host", "sdk-ui.ts");
|
||||
const TSCONFIG = path.join(ROOT, "tsconfig.app.json");
|
||||
|
||||
const ALLOWED = [
|
||||
"ActionSlot",
|
||||
"Alert",
|
||||
"AlertDescription",
|
||||
"AlertDialog",
|
||||
"AlertDialogAction",
|
||||
"AlertDialogCancel",
|
||||
"AlertDialogContent",
|
||||
"AlertDialogDescription",
|
||||
"AlertDialogFooter",
|
||||
"AlertDialogHeader",
|
||||
"AlertDialogOverlay",
|
||||
"AlertDialogPortal",
|
||||
"AlertDialogTitle",
|
||||
"AlertDialogTrigger",
|
||||
"AlertTitle",
|
||||
"Badge",
|
||||
"BarSeries",
|
||||
"BarSeriesItem",
|
||||
"BarSeriesProps",
|
||||
"BrowserSignInDialog",
|
||||
"Button",
|
||||
"ButtonProps",
|
||||
"Card",
|
||||
"CardAction",
|
||||
"CardContent",
|
||||
"CardDescription",
|
||||
"CardFooter",
|
||||
"CardGridCanvas",
|
||||
"CardHeader",
|
||||
"CardTitle",
|
||||
"Checkbox",
|
||||
"ColumnCountStepper",
|
||||
"ComponentSlot",
|
||||
"ConnectionLogPanel",
|
||||
"ConnectionLogProvider",
|
||||
"ConnectionOrigin",
|
||||
"ConnectionScreen",
|
||||
"ConnectionStage",
|
||||
"ConnectionStatus",
|
||||
"CustomKeybinding",
|
||||
"Dialog",
|
||||
"DialogClose",
|
||||
"DialogContent",
|
||||
"DialogDescription",
|
||||
"DialogFooter",
|
||||
"DialogHeader",
|
||||
"DialogOverlay",
|
||||
"DialogPortal",
|
||||
"DialogTitle",
|
||||
"DialogTrigger",
|
||||
"DropdownMenu",
|
||||
"DropdownMenuCheckboxItem",
|
||||
"DropdownMenuContent",
|
||||
"DropdownMenuGroup",
|
||||
"DropdownMenuItem",
|
||||
"DropdownMenuLabel",
|
||||
"DropdownMenuPortal",
|
||||
"DropdownMenuRadioGroup",
|
||||
"DropdownMenuRadioItem",
|
||||
"DropdownMenuSeparator",
|
||||
"DropdownMenuShortcut",
|
||||
"DropdownMenuSub",
|
||||
"DropdownMenuSubContent",
|
||||
"DropdownMenuSubTrigger",
|
||||
"DropdownMenuTrigger",
|
||||
"EmptyState",
|
||||
"FOLDER_COLORS",
|
||||
"FakeSwitch",
|
||||
"FullScreenAppPhase",
|
||||
"FullScreenAppWrapper",
|
||||
"GridCardCatalogEntry",
|
||||
"GridColSpan",
|
||||
"GridLayout",
|
||||
"GridSlot",
|
||||
"HostFeatureFields",
|
||||
"HostFeatureFieldsProps",
|
||||
"HostKeyVerificationDialog",
|
||||
"Input",
|
||||
"Kbd",
|
||||
"KbdKey",
|
||||
"KbdSeparator",
|
||||
"KeyCombo",
|
||||
"KeybindingAction",
|
||||
"KeybindingActionType",
|
||||
"Label",
|
||||
"LineChart",
|
||||
"LineChartSeries",
|
||||
"LocalCollectedFile",
|
||||
"LocalDirectoryListing",
|
||||
"LocalFileEntry",
|
||||
"LocalFsHomeInfo",
|
||||
"LocalFsResult",
|
||||
"LocalTransferOrigin",
|
||||
"LocalTransferProgress",
|
||||
"LocalTrashResult",
|
||||
"LocalWalkFile",
|
||||
"LocalWalkResult",
|
||||
"LogContext",
|
||||
"LogEntry",
|
||||
"MFAPromptMode",
|
||||
"ManagerCardError",
|
||||
"ManagerCardShell",
|
||||
"ManagerSearch",
|
||||
"MetricCard",
|
||||
"MiniStat",
|
||||
"PassphraseDialog",
|
||||
"PasswordInput",
|
||||
"PluginComponent",
|
||||
"PluginViewPlaceholder",
|
||||
"Popover",
|
||||
"PopoverAnchor",
|
||||
"PopoverContent",
|
||||
"PopoverTrigger",
|
||||
"RadialGauge",
|
||||
"RadialGaugeProps",
|
||||
"RecentActivityItem",
|
||||
"RobustClipboardProvider",
|
||||
"SSHAuthDialog",
|
||||
"ScrollArea",
|
||||
"ScrollBar",
|
||||
"SectionCard",
|
||||
"Select",
|
||||
"Select2",
|
||||
"SelectContent",
|
||||
"SelectGroup",
|
||||
"SelectItem",
|
||||
"SelectLabel",
|
||||
"SelectScrollDownButton",
|
||||
"SelectScrollUpButton",
|
||||
"SelectSeparator",
|
||||
"SelectTrigger",
|
||||
"SelectValue",
|
||||
"Separator",
|
||||
"SettingRow",
|
||||
"Sheet",
|
||||
"SheetClose",
|
||||
"SheetContent",
|
||||
"SheetDescription",
|
||||
"SheetFooter",
|
||||
"SheetHeader",
|
||||
"SheetTitle",
|
||||
"SheetTrigger",
|
||||
"Skeleton",
|
||||
"Slider",
|
||||
"Sparkline",
|
||||
"SparklineProps",
|
||||
"StatRow",
|
||||
"Switch",
|
||||
"TOTPDialog",
|
||||
"Textarea",
|
||||
"TextareaProps",
|
||||
"Tooltip",
|
||||
"TooltipContent",
|
||||
"TooltipProvider",
|
||||
"TooltipTrigger",
|
||||
"UptimeInfo",
|
||||
"VersionInfo",
|
||||
"WebSocketConnectionTarget",
|
||||
"WidgetTitle",
|
||||
"badgeVariants",
|
||||
"buildOriginWsUrl",
|
||||
"buttonVariants",
|
||||
"cn",
|
||||
"copyToClipboard",
|
||||
"createFrontendLogger",
|
||||
"createQuickConnectHost",
|
||||
"findMatchingKeybinding",
|
||||
"getAdaptiveResourceBudget",
|
||||
"getBasePath",
|
||||
"getDatabaseHealth",
|
||||
"getDeviceId",
|
||||
"getPollingEnvironmentMultiplier",
|
||||
"getRecentActivity",
|
||||
"getUptime",
|
||||
"getVersionInfo",
|
||||
"globalShortcutHandler",
|
||||
"guacStateToStage",
|
||||
"guacStateToStatus",
|
||||
"hydrateLocalSharedHostAuth",
|
||||
"isElectron",
|
||||
"isMacPlatform",
|
||||
"isQuickConnectHost",
|
||||
"isTabJumpHotkey",
|
||||
"linkedServerUrl",
|
||||
"markAdaptiveResourceUsed",
|
||||
"pluginWsUrl",
|
||||
"readFromClipboard",
|
||||
"resolveConnectionOrigin",
|
||||
"resolveRemoteHostId",
|
||||
"runAdaptiveBackgroundTask",
|
||||
"runAdaptivePolling",
|
||||
"runVisibleInterval",
|
||||
"useAdaptivePolling",
|
||||
"useAppTheme",
|
||||
"useConfirmation",
|
||||
"useConnectionLog",
|
||||
"useIsMobile",
|
||||
"useOptionalConnectionLog",
|
||||
"useTabs",
|
||||
"useTabsSafe",
|
||||
];
|
||||
|
||||
/** Every name a module exports, resolved the way the compiler sees it. */
|
||||
function exportedNames(file = SDK_UI, tsconfig = TSCONFIG) {
|
||||
const ts = require("typescript");
|
||||
const parsed = ts.getParsedCommandLineOfConfigFile(
|
||||
tsconfig,
|
||||
{},
|
||||
{ ...ts.sys, onUnRecoverableConfigFileDiagnostic: () => {} },
|
||||
);
|
||||
const program = ts.createProgram([file], {
|
||||
...(parsed?.options ?? {}),
|
||||
noEmit: true,
|
||||
});
|
||||
const checker = program.getTypeChecker();
|
||||
const source = program.getSourceFile(file);
|
||||
const symbol = source && checker.getSymbolAtLocation(source);
|
||||
if (!symbol) throw new Error(`Cannot read the exports of ${file}`);
|
||||
return checker
|
||||
.getExportsOfModule(symbol)
|
||||
.map((entry) => entry.getName())
|
||||
.sort();
|
||||
}
|
||||
|
||||
/** What the module adds to, and drops from, the allowlist. */
|
||||
function compare(names, allowed = ALLOWED) {
|
||||
const allowedSet = new Set(allowed);
|
||||
const nameSet = new Set(names);
|
||||
return {
|
||||
added: names.filter((name) => !allowedSet.has(name)),
|
||||
removed: allowed.filter((name) => !nameSet.has(name)),
|
||||
};
|
||||
}
|
||||
|
||||
function main() {
|
||||
const names = exportedNames();
|
||||
if (process.argv.includes("--list")) {
|
||||
console.log(names.join("\n"));
|
||||
return;
|
||||
}
|
||||
const { added, removed } = compare(names);
|
||||
if (added.length === 0 && removed.length === 0) return;
|
||||
if (added.length > 0) {
|
||||
console.error(
|
||||
"@termix/plugin-sdk/ui exports names that are not on the allowlist in scripts/check-sdk-ui-exports.cjs:",
|
||||
);
|
||||
for (const name of added) console.error(` + ${name}`);
|
||||
}
|
||||
if (removed.length > 0) {
|
||||
console.error(
|
||||
"@termix/plugin-sdk/ui no longer exports these allowlisted names (a breaking change for plugins):",
|
||||
);
|
||||
for (const name of removed) console.error(` - ${name}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (require.main === module) main();
|
||||
|
||||
module.exports = { ALLOWED, compare, exportedNames };
|
||||
Reference in new issue
Block a user