Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/lint #37

Closed
wants to merge 11 commits into from
259 changes: 130 additions & 129 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,137 +1,138 @@
// @ts-check
import tsEslint from "typescript-eslint";
import eslint from "@eslint/js";
import sonarjs from "eslint-plugin-sonarjs";
import checkFile from "eslint-plugin-check-file";
import sonarjs from "eslint-plugin-sonarjs";
import tsEslint from "typescript-eslint";

export default tsEslint.config({
plugins: {
"@typescript-eslint": tsEslint.plugin,
"check-file": checkFile,
export default [
{
ignores: ["dist/**/*", "**/*.js", ".github/*.ts", "cypress.config.ts"],
},
// static\dist\main.js
ignores: [".github/*.ts", "static/dist/*.js", "static/dist/*.ts", "static/dist/*.d.ts", "cypress.config.ts", "coverage/*"],
extends: [eslint.configs.recommended, ...tsEslint.configs.recommended, sonarjs.configs.recommended],
languageOptions: {
parser: tsEslint.parser,
parserOptions: {
projectService: {
defaultProject: "tsconfig.json",
allowDefaultProject: ["*.mjs"],
},
tsconfigRootDir: import.meta.dirname,
eslint.configs.recommended,
...tsEslint.configs.recommended,
sonarjs.configs.recommended,
{
plugins: {
"@typescript-eslint": tsEslint.plugin,
"check-file": checkFile,
},
},
rules: {
"check-file/filename-naming-convention": [
"error",
{
"**/*.{js,ts}": "+([-._a-z0-9])",
},
],
"prefer-arrow-callback": [
"warn",
{
allowNamedFunctions: true,
},
],
"func-style": [
"warn",
"declaration",
{
allowArrowFunctions: false,
},
],
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"constructor-super": "error",
"no-invalid-this": "off",
"@typescript-eslint/no-invalid-this": ["error"],
"no-restricted-syntax": ["error", "ForInStatement"],
"use-isnan": "error",
"no-unneeded-ternary": "error",
"no-nested-ternary": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
args: "after-used",
ignoreRestSiblings: true,
vars: "all",
varsIgnorePattern: "^_",
argsIgnorePattern: "^_",
languageOptions: {
parser: tsEslint.parser,
parserOptions: {
project: "./tsconfig.json",
tsconfigRootDir: import.meta.dirname,
},
],
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"sonarjs/no-all-duplicated-branches": "error",
"sonarjs/no-collection-size-mischeck": "error",
"sonarjs/no-duplicated-branches": "error",
"sonarjs/no-element-overwrite": "error",
"sonarjs/no-identical-conditions": "error",
"sonarjs/no-identical-expressions": "error",
"sonarjs/new-cap": "off",
"sonarjs/different-types-comparison": "off",
"sonarjs/sonar-prefer-regexp-exec": "off",
"sonarjs/function-return-type": "off",
"sonarjs/no-misleading-array-reverse": "off",
"sonarjs/slow-regex": "off",
"@typescript-eslint/naming-convention": [
"error",
{
selector: "interface",
format: ["StrictPascalCase"],
custom: {
regex: "^I[A-Z]",
match: false,
},
rules: {
"check-file/filename-naming-convention": [
"error",
{
"**/*.{js,ts}": "+([-._a-z0-9])",
},
},
{
selector: "memberLike",
modifiers: ["private"],
format: ["strictCamelCase"],
leadingUnderscore: "require",
},
{
selector: "typeLike",
format: ["StrictPascalCase"],
},
{
selector: "typeParameter",
format: ["StrictPascalCase"],
prefix: ["T"],
},
{
selector: "variable",
format: ["strictCamelCase", "UPPER_CASE"],
leadingUnderscore: "allow",
trailingUnderscore: "allow",
},
{
selector: "variable",
format: ["strictCamelCase"],
leadingUnderscore: "allow",
trailingUnderscore: "allow",
},
{
selector: "variable",
modifiers: ["destructured"],
format: null,
},
{
selector: "variable",
types: ["boolean"],
format: ["StrictPascalCase"],
prefix: ["is", "should", "has", "can", "did", "will", "does"],
},
{
selector: "variableLike",
format: ["strictCamelCase"],
},
{
selector: ["function", "variable"],
format: ["strictCamelCase"],
},
],
],
"prefer-arrow-callback": [
"warn",
{
allowNamedFunctions: true,
},
],
"func-style": [
"warn",
"declaration",
{
allowArrowFunctions: false,
},
],
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/no-non-null-assertion": "error",
"constructor-super": "error",
"no-invalid-this": "off",
"@typescript-eslint/no-invalid-this": ["error"],
"no-restricted-syntax": ["error", "ForInStatement"],
"use-isnan": "error",
"no-unneeded-ternary": "error",
"no-nested-ternary": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
args: "after-used",
ignoreRestSiblings: true,
vars: "all",
varsIgnorePattern: "^_",
argsIgnorePattern: "^_",
},
],
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/restrict-plus-operands": "error",
"sonarjs/no-all-duplicated-branches": "error",
"sonarjs/no-collection-size-mischeck": "error",
"sonarjs/no-duplicated-branches": "error",
"sonarjs/no-element-overwrite": "error",
"sonarjs/no-identical-conditions": "error",
"sonarjs/no-identical-expressions": "error",
"sonarjs/new-cap": "off",
"sonarjs/different-types-comparison": "off",
"sonarjs/sonar-prefer-regexp-exec": "off",
"sonarjs/function-return-type": "off",
"sonarjs/no-misleading-array-reverse": "off",
"sonarjs/slow-regex": "off",
"@typescript-eslint/naming-convention": [
"error",
{
selector: "interface",
format: ["StrictPascalCase"],
custom: {
regex: "^I[A-Z]",
match: false,
},
},
{
selector: "memberLike",
modifiers: ["private"],
format: ["strictCamelCase"],
leadingUnderscore: "require",
},
{
selector: "typeLike",
format: ["StrictPascalCase"],
},
{
selector: "typeParameter",
format: ["StrictPascalCase"],
prefix: ["T"],
},
{
selector: "variable",
format: ["strictCamelCase", "UPPER_CASE"],
leadingUnderscore: "allow",
trailingUnderscore: "allow",
},
{
selector: "variable",
format: ["strictCamelCase"],
leadingUnderscore: "allow",
trailingUnderscore: "allow",
},
{
selector: "variable",
modifiers: ["destructured"],
format: null,
},
{
selector: "variable",
types: ["boolean"],
format: ["StrictPascalCase"],
prefix: ["is", "should", "has", "can", "did", "will", "does"],
},
{
selector: "variableLike",
format: ["strictCamelCase"],
},
{
selector: ["function", "variable"],
format: ["strictCamelCase"],
},
],
},
},
});
];
2 changes: 1 addition & 1 deletion static/scripts/fetch-manifest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Octokit } from "@octokit/rest";
import { CONFIG_FULL_PATH, CONFIG_ORG_REPO, DEV_CONFIG_FULL_PATH } from "@ubiquity-os/plugin-sdk/constants";
import { Manifest, ManifestPreDecode } from "../types/plugins";
import { DEV_CONFIG_FULL_PATH, CONFIG_FULL_PATH, CONFIG_ORG_REPO } from "@ubiquity-os/plugin-sdk/constants";
import { getOfficialPluginConfig } from "../utils/storage";

/**
Expand Down
50 changes: 35 additions & 15 deletions static/scripts/rendering/config-editor.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import MarkdownIt from "markdown-it";
import { Manifest, Plugin } from "../../types/plugins";
import { controlButtons } from "./control-buttons";
import { getManifestCache } from "../../utils/storage";
import { extractPluginIdentifier } from "../../utils/strings";
import { ManifestRenderer } from "../render-manifest";
import { controlButtons } from "./control-buttons";
import { processProperties } from "./input-parsing";
import { addTrackedEventListener, getTrackedEventListeners, normalizePluginName, removeTrackedEventListener, updateGuiTitle } from "./utils";
import { addTrackedEventListener, getTrackedEventListeners, removeTrackedEventListener, updateGuiTitle } from "./utils";
import { handleResetToDefault, writeNewConfig } from "./write-add-remove";
import MarkdownIt from "markdown-it";
import { getManifestCache } from "../../utils/storage";
const md = new MarkdownIt();

/**
Expand Down Expand Up @@ -84,8 +85,36 @@ export function renderConfigEditor(renderer: ManifestRenderer, pluginManifest: M
}

const parsedConfig = renderer.configParser.parseConfig(renderer.configParser.repoConfig || localStorage.getItem("config"));
// for when `resetToDefault` is called and no plugin gets passed in, we still want to show the remove button
const isInstalled = parsedConfig.plugins?.find((p) => p.uses[0].plugin.includes(normalizePluginName(pluginManifest?.name || "")));

// Get the repository URL for the current plugin from the manifest cache
const manifestCache = getManifestCache();
const pluginUrls = Object.keys(manifestCache);
const pluginUrl = pluginUrls.find((url) => {
return manifestCache[url].name === pluginManifest?.name;
});

if (!pluginUrl) {
throw new Error("Plugin URL not found");
}

const manifestPluginId = extractPluginIdentifier(pluginUrl);

// Check if plugin is installed by looking for any URL that matches
const isInstalled = parsedConfig.plugins?.find((p) => {
const installedUrl = p.uses[0].plugin;

// If the installed plugin is a GitHub URL, extract its identifier
const installedPluginId = extractPluginIdentifier(installedUrl);

// If both are GitHub URLs, compare the repo names
const isBothGithubUrls = pluginUrl.includes("github") && installedUrl.includes("github");
if (isBothGithubUrls) {
return manifestPluginId === installedPluginId;
}

// Otherwise check if the installed URL contains the repo name
return installedUrl.toLowerCase().includes(manifestPluginId.toLowerCase());
});

loadListeners({
renderer,
Expand All @@ -105,15 +134,6 @@ export function renderConfigEditor(renderer: ManifestRenderer, pluginManifest: M
}

resetToDefaultButton.hidden = !!(plugin || isInstalled);
const manifestCache = getManifestCache();
const pluginUrls = Object.keys(manifestCache);
const pluginUrl = pluginUrls.find((url) => {
return manifestCache[url].name === pluginManifest?.name;
});

if (!pluginUrl) {
throw new Error("Plugin URL not found");
}
const readme = manifestCache[pluginUrl].readme;

if (readme) {
Expand Down
27 changes: 22 additions & 5 deletions static/scripts/rendering/plugin-select.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ManifestCache, ManifestPreDecode, Plugin } from "../../types/plugins";
import { createElement } from "../../utils/element-helpers";
import { getManifestCache } from "../../utils/storage";
import { STRINGS } from "../../utils/strings";
import { STRINGS, extractPluginIdentifier } from "../../utils/strings";
import { ManifestRenderer } from "../render-manifest";
import { renderConfigEditor } from "./config-editor";
import { controlButtons } from "./control-buttons";
import { closeAllSelect, normalizePluginName, updateGuiTitle } from "./utils";
import { closeAllSelect, updateGuiTitle } from "./utils";

/**
* Renders a dropdown of plugins taken from the marketplace with an installed indicator.
Expand Down Expand Up @@ -62,9 +62,26 @@ export function renderPluginSelector(renderer: ManifestRenderer): void {
if (!cleanManifestCache[url]?.name) {
return;
}
const normalizedName = normalizePluginName(cleanManifestCache[url].name);
const reg = new RegExp(normalizedName, "i");
const installedPlugin: Plugin | undefined = installedPlugins.find((plugin) => plugin.uses[0].plugin.match(reg));

const manifestPluginId = extractPluginIdentifier(url);

// Check if plugin is installed by looking for any URL that matches
const installedPlugin: Plugin | undefined = installedPlugins.find((plugin) => {
const installedUrl = plugin.uses[0].plugin;

// If the installed plugin is a GitHub URL, extract its identifier
const installedPluginId = extractPluginIdentifier(installedUrl);

// If both are GitHub URLs, compare the repo names
const isBothGithubUrls = url.includes("github") && installedUrl.includes("github");
if (isBothGithubUrls) {
return manifestPluginId === installedPluginId;
}

// Otherwise check if the installed URL contains the repo name
return installedUrl.toLowerCase().includes(manifestPluginId.toLowerCase());
});

const defaultForInstalled: ManifestPreDecode | null = cleanManifestCache[url];
const optionText = defaultForInstalled.name;
const indicator = installedPlugin ? "🟢" : "🔴";
Expand Down
Loading
Loading