mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-08-28 17:21:05 +00:00
fix: restore verboseLog/parseCssColor after main merge and bump glob
CI merge with main dropped verboseInfo/parseCssColor exports and broke the Vite build. Restore the PR logger and colour helpers, reinstate the Jest color mock map, and update glob to v13 with overrides. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,6 +15,7 @@ export default {
|
|||||||
],
|
],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'^@/(.*)$': '<rootDir>/src/$1',
|
'^@/(.*)$': '<rootDir>/src/$1',
|
||||||
|
'^color$': '<rootDir>/src/test/mocks/color.ts',
|
||||||
'^webextension-polyfill$': '<rootDir>/src/test/mocks/webextension-polyfill.ts',
|
'^webextension-polyfill$': '<rootDir>/src/test/mocks/webextension-polyfill.ts',
|
||||||
},
|
},
|
||||||
setupFilesAfterEnv: ['<rootDir>/src/test/jest.setup.ts'],
|
setupFilesAfterEnv: ['<rootDir>/src/test/jest.setup.ts'],
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@
|
|||||||
* or `node lib/publish.js --b firefox`
|
* or `node lib/publish.js --b firefox`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const glob = require("glob");
|
const { globSync } = require("glob");
|
||||||
const semver = require("semver");
|
const semver = require("semver");
|
||||||
const { execSync } = require("child_process");
|
const { execSync } = require("child_process");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
@@ -98,7 +98,7 @@ function getLatestFiles(browser) {
|
|||||||
const pattern = `dist/betterseqtaplus@*-*${browser}.zip`;
|
const pattern = `dist/betterseqtaplus@*-*${browser}.zip`;
|
||||||
console.log("Glob pattern:", pattern);
|
console.log("Glob pattern:", pattern);
|
||||||
|
|
||||||
const files = glob.sync(pattern);
|
const files = globSync(pattern);
|
||||||
console.log("Files found for browser", browser, ":", files);
|
console.log("Files found for browser", browser, ":", files);
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
|
|||||||
+9
-1
@@ -58,7 +58,7 @@
|
|||||||
"dependency-cruiser": "^17.0.1",
|
"dependency-cruiser": "^17.0.1",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.33.0",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.31.0",
|
||||||
"glob": "^11.0.1",
|
"glob": "^13.0.6",
|
||||||
"jest": "^30.4.2",
|
"jest": "^30.4.2",
|
||||||
"jest-environment-jsdom": "^30.4.1",
|
"jest-environment-jsdom": "^30.4.1",
|
||||||
"mime-types": "^3.0.1",
|
"mime-types": "^3.0.1",
|
||||||
@@ -129,5 +129,13 @@
|
|||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
"vite": "^6.2.1",
|
"vite": "^6.2.1",
|
||||||
"webextension-polyfill": "^0.12.0"
|
"webextension-polyfill": "^0.12.0"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"glob": "^13.0.6"
|
||||||
|
},
|
||||||
|
"pnpm": {
|
||||||
|
"overrides": {
|
||||||
|
"glob": "^13.0.6"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { extractSolidColor, normalizeCssColorString } from "./parseCssColor";
|
import {
|
||||||
|
extractSolidColor,
|
||||||
|
normalizeCssColorString,
|
||||||
|
parseCssColor,
|
||||||
|
} from "./parseCssColor";
|
||||||
|
|
||||||
describe("normalizeCssColorString", () => {
|
describe("normalizeCssColorString", () => {
|
||||||
it("lowercases uppercase RGBA/RGB function names", () => {
|
it("lowercases uppercase RGBA/RGB function names", () => {
|
||||||
@@ -24,3 +28,19 @@ describe("extractSolidColor", () => {
|
|||||||
).toBe("rgba(201,61,0,1)");
|
).toBe("rgba(201,61,0,1)");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("parseCssColor", () => {
|
||||||
|
it("parses uppercase RGBA without throwing", () => {
|
||||||
|
const parsed = parseCssColor("RGBA(3, 29, 11, 0.58)");
|
||||||
|
expect(parsed.alpha()).toBeCloseTo(0.58, 2);
|
||||||
|
expect(parsed.red()).toBe(3);
|
||||||
|
expect(parsed.green()).toBe(29);
|
||||||
|
expect(parsed.blue()).toBe(11);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back when the value is not a colour", () => {
|
||||||
|
expect(parseCssColor("not-a-color", "#007bff").hex().toLowerCase()).toBe(
|
||||||
|
"#007bff",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
import Color from "color";
|
||||||
|
|
||||||
|
type ColorInstance = ReturnType<typeof Color>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SEQTA themes and user gradients often use uppercase `RGBA()` / `RGB()`.
|
* SEQTA themes and user gradients often use uppercase `RGBA()` / `RGB()`.
|
||||||
* The `color` package only accepts lowercase function names.
|
* The `color` package only accepts lowercase function names.
|
||||||
@@ -28,3 +32,34 @@ export function extractSolidColor(value: string): string | null {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Parse a CSS colour for the `color` library; never throws. */
|
||||||
|
export function parseCssColor(value: string, fallback = "#007bff"): ColorInstance {
|
||||||
|
const candidates = [
|
||||||
|
extractSolidColor(value),
|
||||||
|
normalizeCssColorString(value),
|
||||||
|
].filter((candidate): candidate is string => Boolean(candidate));
|
||||||
|
|
||||||
|
for (const candidate of candidates) {
|
||||||
|
try {
|
||||||
|
return Color(candidate);
|
||||||
|
} catch {
|
||||||
|
// try next strategy
|
||||||
|
}
|
||||||
|
|
||||||
|
const rgbaMatch = candidate.match(
|
||||||
|
/rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*([\d.]+))?\s*\)/i,
|
||||||
|
);
|
||||||
|
if (rgbaMatch) {
|
||||||
|
try {
|
||||||
|
const [, r, g, b, a] = rgbaMatch;
|
||||||
|
const rgb = Color.rgb(Number(r), Number(g), Number(b));
|
||||||
|
return a !== undefined ? rgb.alpha(Number(a)) : rgb;
|
||||||
|
} catch {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color(fallback);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
type ColorChannels = {
|
||||||
|
r: number;
|
||||||
|
g: number;
|
||||||
|
b: number;
|
||||||
|
a: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
function clampByte(value: number): number {
|
||||||
|
return Math.max(0, Math.min(255, Math.round(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
function clampAlpha(value: number): number {
|
||||||
|
return Math.max(0, Math.min(1, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
function toHexByte(value: number): string {
|
||||||
|
return clampByte(value).toString(16).padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
function createColor(channels: ColorChannels) {
|
||||||
|
const color = {
|
||||||
|
red: () => clampByte(channels.r),
|
||||||
|
green: () => clampByte(channels.g),
|
||||||
|
blue: () => clampByte(channels.b),
|
||||||
|
alpha: () => clampAlpha(channels.a),
|
||||||
|
hex: () =>
|
||||||
|
`#${toHexByte(channels.r)}${toHexByte(channels.g)}${toHexByte(channels.b)}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...color,
|
||||||
|
alpha: (value?: number) => {
|
||||||
|
if (value === undefined) return clampAlpha(channels.a);
|
||||||
|
return createColor({ ...channels, a: value });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseHex(input: string): ColorChannels | null {
|
||||||
|
const short = input.match(/^#([0-9a-f]{3})$/i);
|
||||||
|
if (short) {
|
||||||
|
const [r, g, b] = short[1].split("");
|
||||||
|
return {
|
||||||
|
r: parseInt(`${r}${r}`, 16),
|
||||||
|
g: parseInt(`${g}${g}`, 16),
|
||||||
|
b: parseInt(`${b}${b}`, 16),
|
||||||
|
a: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const long = input.match(/^#([0-9a-f]{6})$/i);
|
||||||
|
if (!long) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
r: parseInt(long[1].slice(0, 2), 16),
|
||||||
|
g: parseInt(long[1].slice(2, 4), 16),
|
||||||
|
b: parseInt(long[1].slice(4, 6), 16),
|
||||||
|
a: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRgb(input: string): ColorChannels | null {
|
||||||
|
const match = input.match(
|
||||||
|
/rgba?\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*([\d.]+))?\s*\)/i,
|
||||||
|
);
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
r: Number(match[1]),
|
||||||
|
g: Number(match[2]),
|
||||||
|
b: Number(match[3]),
|
||||||
|
a: match[4] !== undefined ? Number(match[4]) : 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function Color(input: string) {
|
||||||
|
const channels = parseHex(input) ?? parseRgb(input);
|
||||||
|
if (!channels) {
|
||||||
|
throw new Error(`Unable to parse color: ${input}`);
|
||||||
|
}
|
||||||
|
return createColor(channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color.rgb = (r: number, g: number, b: number) => createColor({ r, g, b, a: 1 });
|
||||||
|
|
||||||
|
export default Color;
|
||||||
+35
-2
@@ -1,5 +1,38 @@
|
|||||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
import { settingsState } from "@/seqta/utils/listeners/SettingsState";
|
||||||
|
|
||||||
export function verboseLog(...args: unknown[]): void {
|
const VERBOSE_LOG_ATTR = "data-bsplus-verbose-log";
|
||||||
if (settingsState.devMode) console.log(...args);
|
|
||||||
|
export function isVerboseLoggingEnabled(): boolean {
|
||||||
|
return Boolean(settingsState.devMode && settingsState.verboseLogging);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function syncVerboseLogDomFlag(): void {
|
||||||
|
if (typeof document === "undefined") return;
|
||||||
|
document.documentElement.toggleAttribute(
|
||||||
|
VERBOSE_LOG_ATTR,
|
||||||
|
isVerboseLoggingEnabled(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let initialized = false;
|
||||||
|
|
||||||
|
/** Register DOM flag sync when dev / verbose toggles change. Call after settings load. */
|
||||||
|
export function initVerboseLogging(): void {
|
||||||
|
if (initialized) return;
|
||||||
|
initialized = true;
|
||||||
|
syncVerboseLogDomFlag();
|
||||||
|
settingsState.register("devMode", () => syncVerboseLogDomFlag());
|
||||||
|
settingsState.register("verboseLogging", () => syncVerboseLogDomFlag());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verboseDebug(...args: unknown[]): void {
|
||||||
|
if (isVerboseLoggingEnabled()) console.debug(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verboseInfo(...args: unknown[]): void {
|
||||||
|
if (isVerboseLoggingEnabled()) console.info(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verboseLog(...args: unknown[]): void {
|
||||||
|
if (isVerboseLoggingEnabled()) console.log(...args);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user