Skip to content

Commit bef30d9

Browse files
committed
O_O checklist - no js styles; atomic file operations
1 parent b56225b commit bef30d9

20 files changed

+361
-287
lines changed

exampleVault/Examples.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
slider1: 7
2+
slider1: 8
33
suggest: test
44
toggle1: false
55
Domestic_tasks:
@@ -13,7 +13,7 @@ inlineSelect: 1
1313
nested:
1414
object: test
1515
number1: 2
16-
number2: 14
16+
number2: 16
1717
time:
1818
---
1919

packages/core/src/api/API.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export abstract class API<Plugin extends IPlugin> {
145145
},
146146
);
147147

148-
if (this.plugin.internal.isFilePathExcluded(filePath) && honorExcludedSetting) {
148+
if (this.plugin.internal.file.isExcludedFromRendering(filePath) && honorExcludedSetting) {
149149
return this.createExcludedMountable(filePath);
150150
}
151151

@@ -269,7 +269,7 @@ export abstract class API<Plugin extends IPlugin> {
269269
},
270270
);
271271

272-
if (this.plugin.internal.isFilePathExcluded(filePath) && honorExcludedSetting) {
272+
if (this.plugin.internal.file.isExcludedFromRendering(filePath) && honorExcludedSetting) {
273273
return this.createExcludedMountable(filePath);
274274
}
275275

packages/core/src/api/FileAPI.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { IPlugin } from 'packages/core/src/IPlugin';
2+
3+
export abstract class FileAPI<Plugin extends IPlugin> {
4+
readonly plugin: Plugin;
5+
6+
constructor(plugin: Plugin) {
7+
this.plugin = plugin;
8+
}
9+
10+
public abstract read(filePath: string): Promise<string>;
11+
12+
public abstract write(filePath: string, content: string): Promise<void>;
13+
14+
// currently not used
15+
// public abstract deleteFile(filePath: string): Promise<void>;
16+
17+
public abstract exists(filePath: string): Promise<boolean>;
18+
19+
public abstract atomicModify(filePath: string, modify: (content: string) => string): Promise<void>;
20+
21+
/**
22+
* Create a file in the given folder with the given name and extension.
23+
* If the name is already taken, a number will be appended to the name.
24+
*
25+
* @param folderPath the path to the folder
26+
* @param fileName the name of the file
27+
* @param extension the extension of the file
28+
* @param open
29+
*
30+
* @returns the path to the created file
31+
*/
32+
public abstract create(folderPath: string, fileName: string, extension: string, open?: boolean): Promise<string>;
33+
34+
/**
35+
* List all files by their path.
36+
*/
37+
public abstract getAllFiles(): string[];
38+
39+
/**
40+
* List all folders by their path.
41+
*/
42+
public abstract getAllFolders(): string[];
43+
44+
/**
45+
* Open a specific file.
46+
*
47+
* @param filePath
48+
* @param callingFilePath
49+
* @param newTab
50+
*/
51+
public abstract open(filePath: string, callingFilePath: string, newTab: boolean): void;
52+
53+
/**
54+
* Resolves a file name to a file path.
55+
*
56+
* @param name
57+
* @param relativeTo
58+
*/
59+
public abstract getPathByName(name: string, relativeTo?: string): string | undefined;
60+
61+
/**
62+
* Checks if a file path has been excluded in the settings.
63+
*
64+
* @param filePath
65+
*/
66+
public isExcludedFromRendering(filePath: string): boolean {
67+
for (const excludedFolder of this.plugin.settings.excludedFolders) {
68+
if (filePath.startsWith(excludedFolder)) {
69+
return true;
70+
}
71+
}
72+
73+
return false;
74+
}
75+
}

packages/core/src/api/InternalAPI.ts

Lines changed: 5 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Moment } from 'moment';
22
import type { LifecycleHook } from 'packages/core/src/api/API';
3+
import type { FileAPI } from 'packages/core/src/api/FileAPI';
34
import DatePickerInput from 'packages/core/src/fields/inputFields/fields/DatePicker/DatePicker.svelte';
45
import type { DatePickerIPF } from 'packages/core/src/fields/inputFields/fields/DatePicker/DatePickerIPF';
56
import type {
@@ -57,10 +58,12 @@ export interface TextPromptModalOptions extends ModalOptions {
5758
}
5859

5960
export abstract class InternalAPI<Plugin extends IPlugin> {
60-
plugin: Plugin;
61+
readonly plugin: Plugin;
62+
readonly file: FileAPI<Plugin>;
6163

62-
constructor(plugin: Plugin) {
64+
constructor(plugin: Plugin, fileAPI: FileAPI<Plugin>) {
6365
this.plugin = plugin;
66+
this.file = fileAPI;
6467
}
6568

6669
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -147,23 +150,6 @@ export abstract class InternalAPI<Plugin extends IPlugin> {
147150
*/
148151
abstract createJsRenderer(container: HTMLElement, filePath: string, code: string, hidden: boolean): IJsRenderer;
149152

150-
/**
151-
* Open a specific file.
152-
*
153-
* @param filePath
154-
* @param callingFilePath
155-
* @param newTab
156-
*/
157-
abstract openFile(filePath: string, callingFilePath: string, newTab: boolean): void;
158-
159-
/**
160-
* Resolves a file name to a file path.
161-
*
162-
* @param name
163-
* @param relativeTo
164-
*/
165-
abstract getFilePathByName(name: string, relativeTo?: string): string | undefined;
166-
167153
/**
168154
* Shows a notice to the user.
169155
*
@@ -190,16 +176,6 @@ export abstract class InternalAPI<Plugin extends IPlugin> {
190176
*/
191177
abstract imagePathToUri(imagePath: string): string;
192178

193-
/**
194-
* List all files by their path.
195-
*/
196-
abstract getAllFiles(): string[];
197-
198-
/**
199-
* List all folders by their path.
200-
*/
201-
abstract getAllFolders(): string[];
202-
203179
/**
204180
* List all commands.
205181
*/
@@ -225,30 +201,6 @@ export abstract class InternalAPI<Plugin extends IPlugin> {
225201
*/
226202
abstract createFuzzySearch(): IFuzzySearch;
227203

228-
/**
229-
* Read a files content.
230-
*
231-
* @param filePath
232-
*/
233-
abstract readFilePath(filePath: string): Promise<string>;
234-
235-
abstract writeFilePath(filePath: string, content: string): Promise<void>;
236-
237-
/**
238-
* Create a file in the given folder with the given name and extension.
239-
* If the name is already taken, a number will be appended to the name.
240-
*
241-
* @param folderPath the path to the folder
242-
* @param fileName the name of the file
243-
* @param extension the extension of the file
244-
* @param open
245-
*
246-
* @returns the path to the created file
247-
*/
248-
abstract createFile(folderPath: string, fileName: string, extension: string, open?: boolean): Promise<string>;
249-
250-
abstract existsFilePath(filePath: string): Promise<boolean>;
251-
252204
abstract createContextMenu(items: ContextMenuItemDefinition[]): IContextMenu;
253205

254206
abstract evaluateTemplaterTemplate(templateFilePath: string, targetFilePath: string): Promise<string>;
@@ -381,19 +333,4 @@ export abstract class InternalAPI<Plugin extends IPlugin> {
381333
},
382334
});
383335
}
384-
385-
/**
386-
* Checks if a file path has been excluded in the settings.
387-
*
388-
* @param filePath
389-
*/
390-
isFilePathExcluded(filePath: string): boolean {
391-
for (const excludedFolder of this.plugin.settings.excludedFolders) {
392-
if (filePath.startsWith(excludedFolder)) {
393-
return true;
394-
}
395-
}
396-
397-
return false;
398-
}
399336
}

packages/core/src/fields/button/ButtonActionRunner.ts

Lines changed: 57 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export class ButtonActionRunner {
3232

3333
resolveFilePath(filePath: string, relativeFilePath?: string | undefined): string {
3434
const targetFilePath = MDLinkParser.isLink(filePath) ? MDLinkParser.parseLink(filePath).target : filePath;
35-
const resolvedFilePath = this.plugin.internal.getFilePathByName(targetFilePath, relativeFilePath);
35+
const resolvedFilePath = this.plugin.internal.file.getPathByName(targetFilePath, relativeFilePath);
3636
if (resolvedFilePath === undefined) {
3737
throw new MetaBindParsingError({
3838
errorLevel: ErrorLevel.ERROR,
@@ -270,8 +270,8 @@ export class ButtonActionRunner {
270270
if (action.openIfAlreadyExists && action.fileName) {
271271
const filePath = ensureFileExtension(joinPath(action.folderPath ?? '', action.fileName), 'md');
272272
// if the file already exists, open it in the same tab
273-
if (await this.plugin.internal.existsFilePath(filePath)) {
274-
this.plugin.internal.openFile(filePath, '', false);
273+
if (await this.plugin.internal.file.exists(filePath)) {
274+
this.plugin.internal.file.open(filePath, '', false);
275275
return;
276276
}
277277
}
@@ -316,39 +316,44 @@ export class ButtonActionRunner {
316316
if (action.openIfAlreadyExists) {
317317
const filePath = ensureFileExtension(joinPath(action.folderPath ?? '', action.fileName), 'md');
318318
// if the file already exists, open it in the same tab
319-
if (await this.plugin.internal.existsFilePath(filePath)) {
320-
this.plugin.internal.openFile(filePath, '', false);
319+
if (await this.plugin.internal.file.exists(filePath)) {
320+
this.plugin.internal.file.open(filePath, '', false);
321321
return;
322322
}
323323
}
324324

325-
await this.plugin.internal.createFile(action.folderPath ?? '', action.fileName, 'md', action.openNote ?? false);
325+
await this.plugin.internal.file.create(
326+
action.folderPath ?? '',
327+
action.fileName,
328+
'md',
329+
action.openNote ?? false,
330+
);
326331
}
327332

328333
async runReplaceInNoteAction(action: ReplaceInNoteButtonAction, filePath: string): Promise<void> {
329334
if (action.fromLine > action.toLine) {
330335
throw new Error('From line cannot be greater than to line');
331336
}
332337

333-
const content = await this.plugin.internal.readFilePath(filePath);
334-
335-
let splitContent = content.split('\n');
336-
337-
if (action.fromLine < 0 || action.toLine > splitContent.length + 1) {
338-
throw new Error('Line numbers out of bounds');
339-
}
340-
341338
const replacement = action.templater
342339
? await this.plugin.internal.evaluateTemplaterTemplate(this.resolveFilePath(action.replacement), filePath)
343340
: action.replacement;
344341

345-
splitContent = [
346-
...splitContent.slice(0, action.fromLine - 1),
347-
replacement,
348-
...splitContent.slice(action.toLine),
349-
];
342+
await this.plugin.internal.file.atomicModify(filePath, content => {
343+
let splitContent = content.split('\n');
350344

351-
await this.plugin.internal.writeFilePath(filePath, splitContent.join('\n'));
345+
if (action.fromLine < 0 || action.toLine > splitContent.length + 1) {
346+
throw new Error('Line numbers out of bounds');
347+
}
348+
349+
splitContent = [
350+
...splitContent.slice(0, action.fromLine - 1),
351+
replacement,
352+
...splitContent.slice(action.toLine),
353+
];
354+
355+
return splitContent.join('\n');
356+
});
352357
}
353358

354359
async runReplaceSelfAction(
@@ -368,59 +373,59 @@ export class ButtonActionRunner {
368373
throw new Error('Position of the button in the note is invalid');
369374
}
370375

371-
const content = await this.plugin.internal.readFilePath(filePath);
372-
373-
let splitContent = content.split('\n');
374-
375-
if (buttonContext.position.lineStart < 0 || buttonContext.position.lineEnd > splitContent.length + 1) {
376-
throw new Error('Position of the button in the note is out of bounds');
377-
}
376+
const position = buttonContext.position;
378377

379378
const replacement = action.templater
380379
? await this.plugin.internal.evaluateTemplaterTemplate(this.resolveFilePath(action.replacement), filePath)
381380
: action.replacement;
382381

383-
splitContent = [
384-
...splitContent.slice(0, buttonContext.position.lineStart),
385-
replacement,
386-
...splitContent.slice(buttonContext.position.lineEnd + 1),
387-
];
382+
await this.plugin.internal.file.atomicModify(filePath, content => {
383+
let splitContent = content.split('\n');
388384

389-
await this.plugin.internal.writeFilePath(filePath, splitContent.join('\n'));
385+
if (position.lineStart < 0 || position.lineEnd > splitContent.length + 1) {
386+
throw new Error('Position of the button in the note is out of bounds');
387+
}
388+
389+
splitContent = [
390+
...splitContent.slice(0, position.lineStart),
391+
replacement,
392+
...splitContent.slice(position.lineEnd + 1),
393+
];
394+
395+
return splitContent.join('\n');
396+
});
390397
}
391398

392399
async runRegexpReplaceInNoteAction(action: RegexpReplaceInNoteButtonAction, filePath: string): Promise<void> {
393400
if (action.regexp === '') {
394401
throw new Error('Regexp cannot be empty');
395402
}
396403

397-
let content = await this.plugin.internal.readFilePath(filePath);
398-
399-
content = content.replace(new RegExp(action.regexp, action.regexpFlags ?? 'g'), action.replacement);
400-
401-
await this.plugin.internal.writeFilePath(filePath, content);
404+
await this.plugin.internal.file.atomicModify(filePath, content => {
405+
return content.replace(new RegExp(action.regexp, action.regexpFlags ?? 'g'), action.replacement);
406+
});
402407
}
403408

404409
async runInsertIntoNoteAction(action: InsertIntoNoteButtonAction, filePath: string): Promise<void> {
405-
const content = await this.plugin.internal.readFilePath(filePath);
406-
407-
let splitContent = content.split('\n');
408-
409-
if (action.line < 1 || action.line > splitContent.length + 1) {
410-
throw new Error('Line number out of bounds');
411-
}
412-
413410
const insertString = action.templater
414411
? await this.plugin.internal.evaluateTemplaterTemplate(this.resolveFilePath(action.value), filePath)
415412
: action.value;
416413

417-
splitContent = [
418-
...splitContent.slice(0, action.line - 1),
419-
insertString,
420-
...splitContent.slice(action.line - 1),
421-
];
414+
await this.plugin.internal.file.atomicModify(filePath, content => {
415+
let splitContent = content.split('\n');
416+
417+
if (action.line < 1 || action.line > splitContent.length + 1) {
418+
throw new Error('Line number out of bounds');
419+
}
420+
421+
splitContent = [
422+
...splitContent.slice(0, action.line - 1),
423+
insertString,
424+
...splitContent.slice(action.line - 1),
425+
];
422426

423-
await this.plugin.internal.writeFilePath(filePath, splitContent.join('\n'));
427+
return splitContent.join('\n');
428+
});
424429
}
425430

426431
async runInlineJsAction(

0 commit comments

Comments
 (0)