Skip to content

Commit d1a3eed

Browse files
authored
fix: add structuredClone fallback for Android (#1018)
1 parent cf38d88 commit d1a3eed

13 files changed

+230
-44
lines changed

src/gui/AIAssistantProvidersModal.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { dedupeModels } from "src/ai/modelsDirectory";
66
import { discoverProviderModels } from "src/ai/modelDiscoveryService";
77
import { ModelDirectoryModal } from "./ModelDirectoryModal";
88
import { setPasswordOnBlur } from "src/utils/setPasswordOnBlur";
9+
import { deepClone } from "src/utils/deepClone";
910
import GenericInputPrompt from "./GenericInputPrompt/GenericInputPrompt";
1011
import { ProviderPickerModal } from "./ProviderPickerModal";
1112
import GenericYesNoPrompt from "./GenericYesNoPrompt/GenericYesNoPrompt";
@@ -101,14 +102,14 @@ export class AIAssistantProvidersModal extends Modal {
101102
button.setWarning();
102103
button.setIcon("trash" as IconType);
103104
})
104-
.addButton((button) => {
105-
button.setButtonText("Edit").onClick(() => {
106-
this.selectedProvider = provider;
107-
this._selectedProviderClone = structuredClone(provider);
105+
.addButton((button) => {
106+
button.setButtonText("Edit").onClick(() => {
107+
this.selectedProvider = provider;
108+
this._selectedProviderClone = deepClone(provider);
108109

109-
this.reload();
110+
this.reload();
111+
});
110112
});
111-
});
112113
});
113114
}
114115

src/gui/MacroGUIs/ConditionalBranchEditorModal.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,12 @@ import type { App } from "obsidian";
33
import type QuickAdd from "../../main";
44
import type IChoice from "../../types/choices/IChoice";
55
import type { ICommand } from "../../types/macros/ICommand";
6+
import { deepClone } from "../../utils/deepClone";
67
import {
78
CommandSequenceEditor,
89
type CommandSequenceEditorConditionalHandlers,
910
} from "./CommandSequenceEditor";
1011

11-
function cloneCommands(commands: ICommand[]): ICommand[] {
12-
if (typeof structuredClone === "function") {
13-
return structuredClone(commands);
14-
}
15-
16-
return JSON.parse(JSON.stringify(commands)) as ICommand[];
17-
}
18-
1912
interface ConditionalBranchEditorModalOptions {
2013
app: App;
2114
plugin: QuickAdd;
@@ -40,7 +33,7 @@ export class ConditionalBranchEditorModal extends Modal {
4033
this.plugin = options.plugin;
4134
this.choices = options.choices;
4235
this.conditionalHandlers = options.conditionalHandlers;
43-
this.workingCommands = cloneCommands(options.commands);
36+
this.workingCommands = deepClone(options.commands);
4437

4538
this.waitForClose = new Promise<ICommand[] | null>((resolve) => {
4639
this.resolvePromise = resolve;

src/migrations/incrementFileNameSettingMoveToDefaultBehavior.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type QuickAdd from "src/main";
22
import type IChoice from "src/types/choices/IChoice";
33
import type { IMacro } from "src/types/macros/IMacro";
4+
import { deepClone } from "src/utils/deepClone";
45
import { isMultiChoice } from "./helpers/isMultiChoice";
56
import { isNestedChoiceCommand } from "./helpers/isNestedChoiceCommand";
67
import { isOldTemplateChoice } from "./helpers/isOldTemplateChoice";
@@ -48,13 +49,13 @@ const incrementFileNameSettingMoveToDefaultBehavior: Migration = {
4849
"'Increment file name' setting moved to 'Set default behavior if file already exists' setting",
4950

5051
migrate: async (plugin: QuickAdd): Promise<void> => {
51-
const choicesCopy = structuredClone(plugin.settings.choices);
52+
const choicesCopy = deepClone(plugin.settings.choices);
5253
const choices = recursiveRemoveIncrementFileName(choicesCopy);
5354

54-
const macrosCopy = structuredClone((plugin.settings as any).macros || []);
55+
const macrosCopy = deepClone((plugin.settings as any).macros || []);
5556
const macros = removeIncrementFileName(macrosCopy);
5657

57-
plugin.settings.choices = structuredClone(choices);
58+
plugin.settings.choices = deepClone(choices);
5859

5960
// Save the migrated macros back to settings - later migrations still need it
6061
(plugin.settings as any).macros = macros;

src/migrations/migrate.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import addDefaultAIProviders from "./addDefaultAIProviders";
99
import removeMacroIndirection from "./removeMacroIndirection";
1010
import migrateFileOpeningSettings from "./migrateFileOpeningSettings";
1111
import setProviderModelDiscoveryMode from "./setProviderModelDiscoveryMode";
12+
import { deepClone } from "src/utils/deepClone";
1213

1314
const migrations: Migrations = {
1415
useQuickAddTemplateFolder,
@@ -38,7 +39,7 @@ async function migrate(plugin: QuickAdd): Promise<void> {
3839
`Running migration ${migration}: ${migrations[migration].description}`
3940
);
4041

41-
const backup = structuredClone(plugin.settings);
42+
const backup = deepClone(plugin.settings);
4243

4344
try {
4445
await migrations[migration].migrate(plugin);

src/migrations/mutualExclusionInsertAfterAndWriteToBottomOfFile.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { isCaptureChoice } from "./helpers/isCaptureChoice";
44
import { isMultiChoice } from "./helpers/isMultiChoice";
55
import { isNestedChoiceCommand } from "./helpers/isNestedChoiceCommand";
66
import type { Migration } from "./Migrations";
7+
import { deepClone } from "src/utils/deepClone";
78

89
function recursiveMigrateSettingInChoices(choices: IChoice[]): IChoice[] {
910
for (const choice of choices) {
@@ -48,10 +49,10 @@ const mutualExclusionInsertAfterAndWriteToBottomOfFile: Migration = {
4849
"Mutual exclusion of insertAfter and writeToBottomOfFile settings. If insertAfter is enabled, writeToBottomOfFile is disabled. To support changes in settings UI.",
4950

5051
migrate: async (plugin) => {
51-
const choicesCopy = structuredClone(plugin.settings.choices);
52+
const choicesCopy = deepClone(plugin.settings.choices);
5253
const choices = recursiveMigrateSettingInChoices(choicesCopy);
5354

54-
const macrosCopy = structuredClone((plugin.settings as any).macros || []);
55+
const macrosCopy = deepClone((plugin.settings as any).macros || []);
5556
const macros = migrateSettingsInMacros(macrosCopy);
5657

5758
plugin.settings.choices = choices;

src/migrations/setProviderModelDiscoveryMode.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type QuickAdd from "src/main";
22
import { settingsStore } from "src/settingsStore";
33
import type { Migration } from "./Migrations";
4+
import { deepClone } from "src/utils/deepClone";
45

56
const setProviderModelDiscoveryMode: Migration = {
67
description:
@@ -25,7 +26,7 @@ const setProviderModelDiscoveryMode: Migration = {
2526
...state,
2627
ai: {
2728
...state.ai,
28-
providers: structuredClone(providers),
29+
providers: deepClone(providers),
2930
},
3031
}));
3132
},

src/services/choiceService.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { MultiChoice } from "../types/choices/MultiChoice";
1818
import { TemplateChoice } from "../types/choices/TemplateChoice";
1919
import { excludeKeys } from "../utilityObsidian";
2020
import { regenerateIds } from "../utils/macroUtils";
21+
import { deepClone } from "../utils/deepClone";
2122

2223
const choiceConstructors: Record<ChoiceType, new (name: string) => IChoice> = {
2324
Template: TemplateChoice,
@@ -49,9 +50,7 @@ export function duplicateChoice(choice: IChoice): IChoice {
4950
Object.assign(newChoice, excludeKeys(choice, ["id", "name"]));
5051

5152
if (choice.type === "Macro") {
52-
(newChoice as IMacroChoice).macro = structuredClone(
53-
(choice as IMacroChoice).macro,
54-
);
53+
(newChoice as IMacroChoice).macro = deepClone((choice as IMacroChoice).macro);
5554
regenerateIds((newChoice as IMacroChoice).macro);
5655
}
5756

src/services/packageExportService.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ import type {
1010
} from "../types/packages/QuickAddPackage";
1111
import { QUICKADD_PACKAGE_SCHEMA_VERSION } from "../types/packages/QuickAddPackage";
1212
import {
13-
collectChoiceClosure,
14-
collectScriptDependencies,
15-
collectFileDependencies,
13+
collectChoiceClosure,
14+
collectScriptDependencies,
15+
collectFileDependencies,
1616
} from "../utils/packageTraversal";
1717
import { log } from "../logger/logManager";
1818
import { encodeToBase64 } from "../utils/base64";
19+
import { deepClone } from "../utils/deepClone";
1920

2021
export interface BuildPackageOptions {
2122
choices: IChoice[];
@@ -61,15 +62,15 @@ export async function buildPackage(
6162
const assets = await encodeAssets(app, assetDescriptors);
6263

6364
const packageChoices: QuickAddPackageChoice[] = closure.choiceIds.map(
64-
(choiceId) => {
65-
const entry = closure.catalog.get(choiceId);
66-
if (!entry) throw new Error(`Choice '${choiceId}' missing from catalog.`);
67-
const clonedChoice = structuredClone(entry.choice);
68-
pruneChoiceTree(clonedChoice, includedChoiceIds);
69-
return {
70-
choice: clonedChoice,
71-
pathHint: [...entry.path],
72-
parentChoiceId: entry.parentId,
65+
(choiceId) => {
66+
const entry = closure.catalog.get(choiceId);
67+
if (!entry) throw new Error(`Choice '${choiceId}' missing from catalog.`);
68+
const clonedChoice = deepClone(entry.choice);
69+
pruneChoiceTree(clonedChoice, includedChoiceIds);
70+
return {
71+
choice: clonedChoice,
72+
pathHint: [...entry.path],
73+
parentChoiceId: entry.parentId,
7374
};
7475
},
7576
);

src/services/packageImportService.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import type { IUserScript } from "../types/macros/IUserScript";
2020
import { CommandType } from "../types/macros/CommandType";
2121
import { log } from "../logger/logManager";
2222
import { decodeFromBase64 } from "../utils/base64";
23+
import { deepClone } from "../utils/deepClone";
2324

2425
export interface LoadedQuickAddPackage {
2526
pkg: QuickAddPackage;
@@ -259,7 +260,7 @@ export async function applyPackageImport(
259260
idMap.set(entry.choice.id, newId);
260261
}
261262

262-
const updatedChoices = structuredClone(existingChoices);
263+
const updatedChoices = deepClone(existingChoices);
263264
const addedChoiceIds: string[] = [];
264265
const overwrittenChoiceIds: string[] = [];
265266
const skippedChoiceIds: string[] = [];
@@ -272,10 +273,10 @@ export async function applyPackageImport(
272273
continue;
273274
}
274275

275-
const clone = structuredClone(entry.choice);
276-
const remapped = remapChoiceTree(clone, idMap, importableChoiceIds);
277-
preparedChoices.set(entry.choice.id, remapped);
278-
}
276+
const clone = deepClone(entry.choice);
277+
const remapped = remapChoiceTree(clone, idMap, importableChoiceIds);
278+
preparedChoices.set(entry.choice.id, remapped);
279+
}
279280

280281
const handledChoices = new Set<string>();
281282

src/settingsStore.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { createStore } from "zustand/vanilla";
22
import type { QuickAddSettings } from "./quickAddSettingsTab";
33
import { DEFAULT_SETTINGS } from "./quickAddSettingsTab";
4+
import { deepClone } from "./utils/deepClone";
45

56
type SettingsState = QuickAddSettings;
67

78
export const settingsStore = (() => {
89
const useSettingsStore = createStore<SettingsState>((set, _get) => ({
9-
...structuredClone(DEFAULT_SETTINGS),
10+
...deepClone(DEFAULT_SETTINGS),
1011
}));
1112

1213
const { getState, setState, subscribe } = useSettingsStore;

0 commit comments

Comments
 (0)