mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-06-17 11:50:16 +00:00
for automatic review
This commit is contained in:
@@ -2,14 +2,15 @@ import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore";
|
||||
import { P2P_DEFAULT_SETTINGS } from "@lib/common/types";
|
||||
import type { ServiceContext } from "@lib/services/base/ServiceBase";
|
||||
import { LiveSyncTrysteroReplicator } from "@lib/replication/trystero/LiveSyncTrysteroReplicator";
|
||||
import { addP2PEventHandlers } from "@lib/replication/trystero/addP2PEventHandlers";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
type CLIP2PPeer = {
|
||||
peerId: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
function delay(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => compatGlobal.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export function parseTimeoutSeconds(value: string, commandName: string): number {
|
||||
|
||||
@@ -18,6 +18,7 @@ import { promptForPassphrase, readStdinAsUtf8, toArrayBuffer, toDatabaseRelative
|
||||
import { collectPeers, openP2PHost, parseTimeoutSeconds, syncWithPeer } from "./p2p";
|
||||
import { performFullScan } from "@lib/serviceFeatures/offlineScanner";
|
||||
import { UnresolvedErrorManager } from "@lib/services/base/UnresolvedErrorManager";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
function redactConnectionString(uri: string): string {
|
||||
return uri.replace(/\/\/([^@/]+)@/u, "//***@");
|
||||
@@ -150,11 +151,11 @@ export async function runCommand(options: CLIOptions, context: CLICommandContext
|
||||
);
|
||||
}
|
||||
}
|
||||
pollTimer = setTimeout(poll, currentIntervalMs);
|
||||
pollTimer = compatGlobal.setTimeout(poll, currentIntervalMs);
|
||||
};
|
||||
let pollTimer: ReturnType<typeof setTimeout> = setTimeout(poll, currentIntervalMs);
|
||||
let pollTimer = compatGlobal.setTimeout(poll, currentIntervalMs);
|
||||
core.services.appLifecycle.onUnload.addHandler(async () => {
|
||||
clearTimeout(pollTimer);
|
||||
compatGlobal.clearTimeout(pollTimer);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { applyRemoteSyncSettings, initSettingsFile } from "./helpers/settings.ts
|
||||
import { assertFilesEqual, runCliOrFail } from "./helpers/cli.ts";
|
||||
import { startCouchdb, stopCouchdb } from "./helpers/docker.ts";
|
||||
import { createDeterministicDataset, type DatasetEntry } from "./helpers/dataset.ts";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
type BenchmarkConfig = {
|
||||
couchdbBackendUri: string;
|
||||
@@ -137,7 +138,7 @@ function startCouchdbProxy(options: { backendUri: string; proxyUri: string; requ
|
||||
},
|
||||
},
|
||||
async (request) => {
|
||||
await new Promise((resolve) => setTimeout(resolve, halfDelayMs));
|
||||
await new Promise((resolve) => compatGlobal.setTimeout(resolve, halfDelayMs));
|
||||
|
||||
const targetUrl = new URL(request.url);
|
||||
targetUrl.protocol = backend.protocol;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CLI_DIR, TEE_ENABLED, formatTeeCommand, createLineTeeWriter } from "./cli.ts";
|
||||
import { join } from "@std/path";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
const CLI_DIST = join(CLI_DIR, "dist", "index.cjs");
|
||||
const VERBOSE_ENABLED = Deno.env.get("LIVESYNC_CLI_VERBOSE") === "1";
|
||||
@@ -77,7 +78,9 @@ export class BackgroundCliProcess {
|
||||
if (this.combined.includes(needle)) return;
|
||||
const status = await Promise.race([
|
||||
this.child.status.then((s) => ({ type: "status" as const, status: s })),
|
||||
new Promise<{ type: "tick" }>((resolve) => setTimeout(() => resolve({ type: "tick" }), 100)),
|
||||
new Promise<{ type: "tick" }>((resolve) =>
|
||||
compatGlobal.setTimeout(() => resolve({ type: "tick" }), 100)
|
||||
),
|
||||
]);
|
||||
if (status.type === "status") {
|
||||
throw new Error(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { join } from "@std/path";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Path resolution
|
||||
@@ -25,7 +26,7 @@ const VERBOSE_ENABLED = Deno.env.get("LIVESYNC_CLI_VERBOSE") === "1";
|
||||
const DEBUG_ENABLED = Deno.env.get("LIVESYNC_CLI_DEBUG") === "1";
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => compatGlobal.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function concatChunks(chunks: Uint8Array[]): Uint8Array {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
/**
|
||||
* Docker service management for tests.
|
||||
*
|
||||
@@ -256,7 +258,7 @@ function untrackContainer(container: string): void {
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => compatGlobal.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function waitForCouchdbStable(hostname: string, user: string, password: string): Promise<void> {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
type WaitForPortOptions = {
|
||||
timeoutMs?: number;
|
||||
intervalMs?: number;
|
||||
@@ -5,7 +7,7 @@ type WaitForPortOptions = {
|
||||
};
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => compatGlobal.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function connectWithTimeout(hostname: string, port: number, timeoutMs: number): Promise<void> {
|
||||
@@ -13,13 +15,13 @@ async function connectWithTimeout(hostname: string, port: number, timeoutMs: num
|
||||
try {
|
||||
const connPromise = Deno.connect({ hostname, port });
|
||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||
timer = setTimeout(() => reject(new Error(`connect timeout after ${timeoutMs}ms`)), timeoutMs);
|
||||
timer = compatGlobal.setTimeout(() => reject(new Error(`connect timeout after ${timeoutMs}ms`)), timeoutMs);
|
||||
});
|
||||
const conn = await Promise.race([connPromise, timeoutPromise]);
|
||||
conn.close();
|
||||
} finally {
|
||||
if (timer !== undefined) {
|
||||
clearTimeout(timer);
|
||||
compatGlobal.clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { runCli } from "./cli.ts";
|
||||
import { isLocalP2pRelay, startP2pRelay, stopP2pRelay, startCoturn, stopCoturn } from "./docker.ts";
|
||||
import { waitForPort } from "./net.ts";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
export type PeerEntry = {
|
||||
id: string;
|
||||
@@ -8,7 +9,7 @@ export type PeerEntry = {
|
||||
};
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
return new Promise((resolve) => compatGlobal.setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function parseRelayEndpoint(relay: string): { hostname: string; port: number } {
|
||||
|
||||
@@ -28,6 +28,7 @@ import { TempDir } from "./helpers/temp.ts";
|
||||
import { runCliOrFail, jsonFieldIsNa } from "./helpers/cli.ts";
|
||||
import { applyCouchdbSettings, initSettingsFile } from "./helpers/settings.ts";
|
||||
import { startCouchdb, stopCouchdb } from "./helpers/docker.ts";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Load configuration
|
||||
@@ -109,7 +110,7 @@ async function runSuite(
|
||||
config: { uri: string; user: string; password: string },
|
||||
dbname: string
|
||||
): Promise<void> {
|
||||
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
const sleep = (ms: number) => new Promise((resolve) => compatGlobal.setTimeout(resolve, ms));
|
||||
const runWithRetry = async <T>(label: string, fn: () => Promise<T>, retries = SYNC_RETRY): Promise<T> => {
|
||||
let lastErr: unknown;
|
||||
for (let i = 0; i <= retries; i++) {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { LiveSyncWebApp } from "./main";
|
||||
import { VaultHistoryStore, type VaultHistoryItem } from "./vaultSelector";
|
||||
import { compatGlobal, _activeDocument } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
const historyStore = new VaultHistoryStore();
|
||||
let app: LiveSyncWebApp | null = null;
|
||||
|
||||
function getRequiredElement<T extends HTMLElement>(id: string): T {
|
||||
const element = document.getElementById(id);
|
||||
const element = _activeDocument.getElementById(id);
|
||||
if (!element) {
|
||||
throw new Error(`Missing element: #${id}`);
|
||||
}
|
||||
@@ -22,7 +23,7 @@ function setBusyState(isBusy: boolean): void {
|
||||
const pickNewBtn = getRequiredElement<HTMLButtonElement>("pick-new-vault");
|
||||
pickNewBtn.disabled = isBusy;
|
||||
|
||||
const historyButtons = document.querySelectorAll<HTMLButtonElement>(".vault-item button");
|
||||
const historyButtons = _activeDocument.querySelectorAll<HTMLButtonElement>(".vault-item button");
|
||||
historyButtons.forEach((button) => {
|
||||
button.disabled = isBusy;
|
||||
});
|
||||
@@ -45,24 +46,24 @@ async function renderHistoryList(): Promise<VaultHistoryItem[]> {
|
||||
emptyEl.classList.toggle("is-hidden", items.length > 0);
|
||||
|
||||
for (const item of items) {
|
||||
const row = document.createElement("div");
|
||||
const row = _activeDocument.createElement("div");
|
||||
row.className = "vault-item";
|
||||
|
||||
const info = document.createElement("div");
|
||||
const info = _activeDocument.createElement("div");
|
||||
info.className = "vault-item-info";
|
||||
|
||||
const name = document.createElement("div");
|
||||
const name = _activeDocument.createElement("div");
|
||||
name.className = "vault-item-name";
|
||||
name.textContent = item.name;
|
||||
|
||||
const meta = document.createElement("div");
|
||||
const meta = _activeDocument.createElement("div");
|
||||
meta.className = "vault-item-meta";
|
||||
const label = item.id === lastUsedId ? "Last used" : "Used";
|
||||
meta.textContent = `${label}: ${formatLastUsed(item.lastUsedAt)}`;
|
||||
|
||||
info.append(name, meta);
|
||||
|
||||
const useButton = document.createElement("button");
|
||||
const useButton = _activeDocument.createElement("button");
|
||||
useButton.type = "button";
|
||||
useButton.textContent = "Use this vault";
|
||||
useButton.addEventListener("click", () => {
|
||||
@@ -120,7 +121,7 @@ async function initializeVaultSelector(): Promise<void> {
|
||||
await renderHistoryList();
|
||||
}
|
||||
|
||||
window.addEventListener("load", async () => {
|
||||
compatGlobal.addEventListener("load", async () => {
|
||||
try {
|
||||
await initializeVaultSelector();
|
||||
} catch (error) {
|
||||
@@ -129,11 +130,11 @@ window.addEventListener("load", async () => {
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("beforeunload", () => {
|
||||
compatGlobal.addEventListener("beforeunload", () => {
|
||||
void app?.shutdown();
|
||||
});
|
||||
|
||||
(window as any).livesyncApp = {
|
||||
(compatGlobal as any).livesyncApp = {
|
||||
getApp: () => app,
|
||||
historyStore,
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@ import { SetupManager } from "@/modules/features/SetupManager";
|
||||
import { useSetupManagerHandlersFeature } from "@/serviceFeatures/setupObsidian/setupManagerHandlers";
|
||||
import { useP2PReplicatorCommands } from "@lib/replication/trystero/useP2PReplicatorCommands";
|
||||
import { useP2PReplicatorFeature } from "@lib/replication/trystero/useP2PReplicatorFeature";
|
||||
import { compatGlobal, _activeDocument } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
const SETTINGS_DIR = ".livesync";
|
||||
const SETTINGS_FILE = "settings.json";
|
||||
@@ -102,8 +103,8 @@ class LiveSyncWebApp {
|
||||
console.log("[AppLifecycle] Restart requested");
|
||||
await this.shutdown();
|
||||
await this.initialize();
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
compatGlobal.setTimeout(() => {
|
||||
compatGlobal.location.reload();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
@@ -235,7 +236,7 @@ class LiveSyncWebApp {
|
||||
}
|
||||
|
||||
private showError(message: string) {
|
||||
const statusEl = document.getElementById("status");
|
||||
const statusEl = _activeDocument.getElementById("status");
|
||||
if (statusEl) {
|
||||
statusEl.className = "error";
|
||||
statusEl.textContent = `Error: ${message}`;
|
||||
@@ -243,7 +244,7 @@ class LiveSyncWebApp {
|
||||
}
|
||||
|
||||
private showWarning(message: string) {
|
||||
const statusEl = document.getElementById("status");
|
||||
const statusEl = _activeDocument.getElementById("status");
|
||||
if (statusEl) {
|
||||
statusEl.className = "warning";
|
||||
statusEl.textContent = `Warning: ${message}`;
|
||||
@@ -251,7 +252,7 @@ class LiveSyncWebApp {
|
||||
}
|
||||
|
||||
private showSuccess(message: string) {
|
||||
const statusEl = document.getElementById("status");
|
||||
const statusEl = _activeDocument.getElementById("status");
|
||||
if (statusEl) {
|
||||
statusEl.className = "success";
|
||||
statusEl.textContent = message;
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
} from "@lib/managers/adapters";
|
||||
import type { FileEventItemSentinel } from "@lib/managers/StorageEventManager";
|
||||
import type { FSAPIFile, FSAPIFolder } from "@/apps/webapp/adapters/FSAPITypes";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
/**
|
||||
* FileSystem API-specific type guard adapter
|
||||
@@ -149,14 +150,14 @@ class FSAPIWatchAdapter implements IStorageEventWatchAdapter {
|
||||
|
||||
async beginWatch(handlers: IStorageEventWatchHandlers): Promise<void> {
|
||||
// Use FileSystemObserver if available (Chrome 124+)
|
||||
if (typeof (window as any).FileSystemObserver === "undefined") {
|
||||
if (typeof (compatGlobal as any).FileSystemObserver === "undefined") {
|
||||
console.log("[FSAPIWatchAdapter] FileSystemObserver not available, file watching disabled");
|
||||
console.log("[FSAPIWatchAdapter] Consider using Chrome 124+ for real-time file watching");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
try {
|
||||
const FileSystemObserver = (window as any).FileSystemObserver;
|
||||
const FileSystemObserver = (compatGlobal as any).FileSystemObserver;
|
||||
|
||||
this.observer = new FileSystemObserver(async (records: any[]) => {
|
||||
for (const record of records) {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
import { LiveSyncWebApp } from "./main";
|
||||
import type { ObsidianLiveSyncSettings } from "@lib/common/types";
|
||||
import type { FilePathWithPrefix } from "@lib/common/types";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Internal state – one app instance per page / browser context
|
||||
@@ -41,7 +42,7 @@ async function waitForIdle(core: any, timeoutMs = 60_000): Promise<void> {
|
||||
(core.services?.fileProcessing?.processing?.value ?? 0) +
|
||||
(core.services?.replication?.storageApplyingCount?.value ?? 0);
|
||||
if (q === 0) return;
|
||||
await new Promise<void>((r) => setTimeout(r, 300));
|
||||
await new Promise<void>((r) => compatGlobal.setTimeout(r, 300));
|
||||
}
|
||||
throw new Error(`waitForIdle timed out after ${timeoutMs} ms`);
|
||||
}
|
||||
@@ -116,7 +117,7 @@ export interface LiveSyncTestAPI {
|
||||
const livesyncTest: LiveSyncTestAPI = {
|
||||
async init(vaultName: string, settings: Partial<ObsidianLiveSyncSettings>): Promise<void> {
|
||||
// Clean up any stale OPFS data from previous runs.
|
||||
const opfsRoot = await navigator.storage.getDirectory();
|
||||
const opfsRoot = await compatGlobal.navigator.storage.getDirectory();
|
||||
try {
|
||||
await opfsRoot.removeEntry(vaultName, { recursive: true });
|
||||
} catch {
|
||||
@@ -200,4 +201,4 @@ const livesyncTest: LiveSyncTestAPI = {
|
||||
};
|
||||
|
||||
// Expose on window for Playwright page.evaluate() calls.
|
||||
(window as any).livesyncTest = livesyncTest;
|
||||
(compatGlobal as any).livesyncTest = livesyncTest;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
|
||||
/* Path mapping */
|
||||
"baseUrl": ".",
|
||||
// "baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["../../*"],
|
||||
"@lib/*": ["../../lib/src/*"]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
const HANDLE_DB_NAME = "livesync-webapp-handles";
|
||||
const HANDLE_STORE_NAME = "handles";
|
||||
const LAST_USED_KEY = "meta:lastUsedVaultId";
|
||||
@@ -170,7 +172,7 @@ export class VaultHistoryStore {
|
||||
}
|
||||
|
||||
async pickNewVault(): Promise<FileSystemDirectoryHandle> {
|
||||
const picker = (window as any).showDirectoryPicker;
|
||||
const picker = (compatGlobal as any).showDirectoryPicker;
|
||||
if (typeof picker !== "function") {
|
||||
throw new Error("FileSystem API showDirectoryPicker is not supported in this browser");
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@ import {
|
||||
type PeerStatus,
|
||||
type PluginShim,
|
||||
} from "@lib/replication/trystero/P2PReplicatorPaneCommon";
|
||||
import { P2PLogCollector, type P2PReplicatorBase, useP2PReplicator } from "@lib/replication/trystero/P2PReplicatorCore";
|
||||
import { useP2PReplicator } from "@lib/replication/trystero/P2PReplicatorCore";
|
||||
import { P2PLogCollector } from "@lib/replication/trystero/P2PLogCollector";
|
||||
import type { P2PReplicatorBase } from "@lib/replication/trystero/P2PReplicatorBase.ts";
|
||||
import type { SimpleStore } from "octagonal-wheels/databases/SimpleStoreBase";
|
||||
import { reactiveSource } from "octagonal-wheels/dataobject/reactive_v2";
|
||||
import { EVENT_SETTING_SAVED } from "@lib/events/coreEvents";
|
||||
@@ -31,6 +33,7 @@ import { SimpleStoreIDBv2 } from "octagonal-wheels/databases/SimpleStoreIDBv2";
|
||||
import type { BrowserAPIService } from "@lib/services/implements/browser/BrowserAPIService";
|
||||
import type { InjectableSettingService } from "@lib/services/implements/injectable/InjectableSettingService";
|
||||
import { LiveSyncTrysteroReplicator } from "@lib/replication/trystero/LiveSyncTrysteroReplicator";
|
||||
import { compatGlobal } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
function addToList(item: string, list: string) {
|
||||
return unique(
|
||||
@@ -137,7 +140,7 @@ export class P2PReplicatorShim implements P2PReplicatorBase {
|
||||
|
||||
this._initP2PReplicator();
|
||||
|
||||
setTimeout(() => {
|
||||
compatGlobal.setTimeout(() => {
|
||||
if (this.settings.P2P_AutoStart && this.settings.P2P_Enabled) {
|
||||
void this.open();
|
||||
}
|
||||
@@ -164,12 +167,12 @@ export class P2PReplicatorShim implements P2PReplicatorBase {
|
||||
getConfig(key: string) {
|
||||
const vaultName = this.services.vault.getVaultName();
|
||||
const dbKey = `${vaultName}-${key}`;
|
||||
return localStorage.getItem(dbKey);
|
||||
return compatGlobal.localStorage.getItem(dbKey);
|
||||
}
|
||||
setConfig(key: string, value: string) {
|
||||
const vaultName = this.services.vault.getVaultName();
|
||||
const dbKey = `${vaultName}-${key}`;
|
||||
localStorage.setItem(dbKey, value);
|
||||
compatGlobal.localStorage.setItem(dbKey, value);
|
||||
}
|
||||
|
||||
getDeviceName(): string {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { mount } from "svelte";
|
||||
import "./app.css";
|
||||
import App from "./App.svelte";
|
||||
import { _activeDocument } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
const app = mount(App, {
|
||||
target: document.getElementById("app")!,
|
||||
target: _activeDocument.getElementById("app")!,
|
||||
});
|
||||
|
||||
export default app;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { mount } from "svelte";
|
||||
import "./app.css";
|
||||
import App from "./UITest.svelte";
|
||||
import { _activeDocument } from "@lib/common/coreEnvFunctions.ts";
|
||||
|
||||
const app = mount(App, {
|
||||
target: document.getElementById("app")!,
|
||||
target: _activeDocument.getElementById("app")!,
|
||||
});
|
||||
|
||||
export default app;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"sourceRoot": "../",
|
||||
// "sourceRoot": "../",
|
||||
"target": "ESNext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
|
||||
@@ -19,7 +19,7 @@ export class PluginDialogModal extends Modal {
|
||||
this.contentEl.setCssStyles({
|
||||
overflow: "auto",
|
||||
display: "flex",
|
||||
flexDirection: "column"
|
||||
flexDirection: "column",
|
||||
});
|
||||
this.titleEl.setText("Customization Sync (Beta3)");
|
||||
if (!this.component) {
|
||||
|
||||
+1
-1
Submodule src/lib updated: 3dad9565aa...7157dbc62c
@@ -194,7 +194,7 @@ export class MessageBox<T extends readonly string[]> extends AutoClosableModal {
|
||||
const div = contentEl.createDiv();
|
||||
div.setCssStyles({
|
||||
userSelect: "text",
|
||||
"webkitUserSelect": "text"
|
||||
webkitUserSelect: "text",
|
||||
});
|
||||
void MarkdownRenderer.render(this.plugin.app, this.contentMd, div, "/", this.plugin);
|
||||
const buttonSetting = new Setting(contentEl);
|
||||
@@ -214,7 +214,7 @@ export class MessageBox<T extends readonly string[]> extends AutoClosableModal {
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
flexGrow: "1"
|
||||
flexGrow: "1",
|
||||
});
|
||||
}
|
||||
contentEl.addEventListener("click", () => {
|
||||
@@ -244,7 +244,7 @@ export class MessageBox<T extends readonly string[]> extends AutoClosableModal {
|
||||
if (this.wideButton) {
|
||||
btn.buttonEl.setCssStyles({
|
||||
flexGrow: "1",
|
||||
width: "100%"
|
||||
width: "100%",
|
||||
});
|
||||
}
|
||||
return btn;
|
||||
|
||||
@@ -45,7 +45,7 @@ const TARGET_GLOBALS = new Set([
|
||||
"navigator",
|
||||
"location",
|
||||
"document",
|
||||
"window"
|
||||
"window",
|
||||
]);
|
||||
|
||||
let modifiedFilesCount = 0;
|
||||
@@ -59,22 +59,13 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude submodule files under src/lib/
|
||||
if (posixFilePath.startsWith(posixLibSrc)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude independent application modules under src/apps/
|
||||
if (posixFilePath.startsWith(`${posixSrc}/apps/`)) {
|
||||
// Exclude coreEnvFunctions.ts to avoid self-referential definitions
|
||||
if (posixFilePath.endsWith("/coreEnvFunctions.ts") || posixFilePath.endsWith("/coreEnvFunctions")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclude unit and integration test files
|
||||
if (
|
||||
posixFilePath.endsWith(".spec.ts") ||
|
||||
posixFilePath.endsWith(".test.ts") ||
|
||||
posixFilePath.includes("/_test/")
|
||||
) {
|
||||
if (posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts") || posixFilePath.includes("/_test/")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -101,6 +92,14 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
}
|
||||
}
|
||||
|
||||
// 1.5. Skip if it is the right-hand side of a QualifiedName (e.g. the "requestAnimationFrame" in "typeof compatGlobal.requestAnimationFrame")
|
||||
if (parent.getKind() === SyntaxKind.QualifiedName) {
|
||||
const qualified = parent.asKindOrThrow(SyntaxKind.QualifiedName);
|
||||
if (qualified.getRight() === idNode) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Skip if it is the operand of a typeof expression (e.g. "typeof window")
|
||||
if (parent.getKind() === SyntaxKind.TypeOfExpression) {
|
||||
continue;
|
||||
@@ -153,6 +152,8 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
let replacement = "";
|
||||
if (name === "window" || name === "globalThis") {
|
||||
replacement = "compatGlobal";
|
||||
} else if (name === "document") {
|
||||
replacement = "_activeDocument";
|
||||
} else {
|
||||
replacement = `compatGlobal.${name}`;
|
||||
}
|
||||
@@ -174,23 +175,33 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
node.replaceWithText(replacement);
|
||||
}
|
||||
|
||||
// Ensure compatGlobal is imported
|
||||
const hasCompatGlobalImport = sourceFile.getImportDeclarations().some((imp) => {
|
||||
return imp.getNamedImports().some((ni) => ni.getName() === "compatGlobal");
|
||||
});
|
||||
// Determine what needs to be imported based on replacements
|
||||
const needsCompatGlobal = nodesToReplace.some((r) => r.replacement.includes("compatGlobal"));
|
||||
const needsActiveDocument = nodesToReplace.some((r) => r.replacement.includes("_activeDocument"));
|
||||
|
||||
if (!hasCompatGlobalImport) {
|
||||
const requiredImports: string[] = [];
|
||||
if (needsCompatGlobal) requiredImports.push("compatGlobal");
|
||||
if (needsActiveDocument) requiredImports.push("_activeDocument");
|
||||
|
||||
if (requiredImports.length > 0) {
|
||||
const existingImport = sourceFile.getImportDeclarations().find((imp) => {
|
||||
const spec = imp.getModuleSpecifierValue();
|
||||
return spec === "@lib/common/coreEnvFunctions" || spec === "@lib/common/coreEnvFunctions.ts";
|
||||
});
|
||||
|
||||
if (existingImport) {
|
||||
existingImport.addNamedImport("compatGlobal");
|
||||
for (const nameToImport of requiredImports) {
|
||||
const alreadyImported = existingImport
|
||||
.getNamedImports()
|
||||
.some((ni) => ni.getName() === nameToImport);
|
||||
if (!alreadyImported) {
|
||||
existingImport.addNamedImport(nameToImport);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sourceFile.addImportDeclaration({
|
||||
namedImports: ["compatGlobal"],
|
||||
moduleSpecifier: "@lib/common/coreEnvFunctions.ts"
|
||||
namedImports: requiredImports,
|
||||
moduleSpecifier: "@lib/common/coreEnvFunctions.ts",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ function matchStyleAccess(node: Node): { element: Node; propertyName: string; is
|
||||
return {
|
||||
element: expr.getExpression(),
|
||||
propertyName: node.getName(),
|
||||
isComputed: false
|
||||
isComputed: false,
|
||||
};
|
||||
}
|
||||
} else if (Node.isElementAccessExpression(node)) {
|
||||
@@ -52,7 +52,7 @@ function matchStyleAccess(node: Node): { element: Node; propertyName: string; is
|
||||
return {
|
||||
element: expr.getExpression(),
|
||||
propertyName: arg.getText(),
|
||||
isComputed: true
|
||||
isComputed: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ function getStyleAssignment(statement: Node) {
|
||||
property: styleAccess.propertyName,
|
||||
valueText: expr.getRight().getText(),
|
||||
isComputed: styleAccess.isComputed,
|
||||
statementNode: statement
|
||||
statementNode: statement,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -100,11 +100,7 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
}
|
||||
|
||||
// Exclude unit and integration test files
|
||||
if (
|
||||
posixFilePath.endsWith(".spec.ts") ||
|
||||
posixFilePath.endsWith(".test.ts") ||
|
||||
posixFilePath.includes("/_test/")
|
||||
) {
|
||||
if (posixFilePath.endsWith(".spec.ts") || posixFilePath.endsWith(".test.ts") || posixFilePath.includes("/_test/")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -126,12 +122,14 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
if (assignment) {
|
||||
const currentGroup: StyleGroup = {
|
||||
elementText: assignment.elementText,
|
||||
assignments: [{
|
||||
property: assignment.property,
|
||||
valueText: assignment.valueText,
|
||||
isComputed: assignment.isComputed,
|
||||
statementNode: assignment.statementNode
|
||||
}]
|
||||
assignments: [
|
||||
{
|
||||
property: assignment.property,
|
||||
valueText: assignment.valueText,
|
||||
isComputed: assignment.isComputed,
|
||||
statementNode: assignment.statementNode,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// Look ahead to collect consecutive assignments to the same element
|
||||
@@ -143,7 +141,7 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
property: nextAssignment.property,
|
||||
valueText: nextAssignment.valueText,
|
||||
isComputed: nextAssignment.isComputed,
|
||||
statementNode: nextAssignment.statementNode
|
||||
statementNode: nextAssignment.statementNode,
|
||||
});
|
||||
j++;
|
||||
} else {
|
||||
@@ -190,7 +188,12 @@ for (const sourceFile of project.getSourceFiles()) {
|
||||
const { line } = sourceFile.getLineAndColumnAtPos(firstNode.getStart());
|
||||
|
||||
console.log(` Line ${line}: Replacing consecutive style assignments on "${group.elementText}" with:`);
|
||||
console.log(newText.split("\n").map((l) => ` ${l}`).join("\n"));
|
||||
console.log(
|
||||
newText
|
||||
.split("\n")
|
||||
.map((l) => ` ${l}`)
|
||||
.join("\n")
|
||||
);
|
||||
|
||||
if (!isDryRun) {
|
||||
firstNode.replaceWithText(newText);
|
||||
|
||||
Reference in New Issue
Block a user