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