Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit c70b1ae

Browse files
committed
Merge remote-tracking branch 'origin/61-bug-accessor-key-and-label-needs-to-be-edited-without-the-ui-and-yaml-in-existing-files-shifts-around'
2 parents 3d41921 + 8fbd564 commit c70b1ae

File tree

5 files changed

+89
-50
lines changed

5 files changed

+89
-50
lines changed

src/helpers/VaultManagement.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ export async function updateRowFileProxy(file: TFile, columnId: string, newValue
9898
*/
9999
export async function updateRowFile(file: TFile, columnId: string, newValue: string, state: TableDataType, option: string): Promise<void> {
100100
LOGGER.info(`=>updateRowFile. file: ${file.path} | columnId: ${columnId} | newValue: ${newValue} | option: ${option}`);
101-
const rowFields = obtainRowDatabaseFields(file, state.columns);
102101
const content = await VaultManagerDB.obtainContentFromTfile(file);
103-
let currentFrontmatter = VaultManagerDB.ontainCurrentFrontmatter(content);
102+
const frontmatterKeys = await VaultManagerDB.obtainFrontmatterKeys(content);
103+
const rowFields = obtainRowDatabaseFields(file, state.columns, frontmatterKeys);
104104
const column = state.columns.find(c => c.key === columnId);
105105
// Adds an empty frontmatter at the beginning of the file
106106
async function addFrontmatter(): Promise<void> {
@@ -139,7 +139,8 @@ export async function updateRowFile(file: TFile, columnId: string, newValue: str
139139
return;
140140
}
141141
// If field does not exist yet, ignore it
142-
if (!Object.prototype.hasOwnProperty.call(currentFrontmatter, columnId)) {
142+
if (!Object.prototype.hasOwnProperty.call(rowFields.frontmatter, columnId)
143+
&& !Object.prototype.hasOwnProperty.call(rowFields.inline, columnId)) {
143144
return;
144145
}
145146

@@ -162,7 +163,7 @@ export async function updateRowFile(file: TFile, columnId: string, newValue: str
162163

163164
async function persistFrontmatter(deletedColumn?: string): Promise<void> {
164165
const frontmatterGroupRegex = /^---[\s\S]+?---/g;
165-
const frontmatterFieldsText = parseFrontmatterFieldsToString(rowFields, currentFrontmatter, deletedColumn);
166+
const frontmatterFieldsText = parseFrontmatterFieldsToString(rowFields, deletedColumn);
166167
const noteObject = {
167168
action: 'replace',
168169
file: file,
@@ -176,15 +177,15 @@ export async function updateRowFile(file: TFile, columnId: string, newValue: str
176177
* INLINE GROUP FUNCTIONS
177178
*******************************************************************************************/
178179
async function inlineColumnEdit(): Promise<void> {
179-
/* Regex explanation
180-
* group 1 is inline field checking that starts in new line
181-
* group 2 is the current value of inline field
182-
*/
183180
const inlineFieldRegex = new RegExp(`(^${columnId}[:]{2})+(.*$)`, 'gm');
184181
if (!inlineFieldRegex.test(content)) {
185182
await inlineAddColumn();
186183
return;
187184
}
185+
/* Regex explanation
186+
* group 1 is inline field checking that starts in new line
187+
* group 2 is the current value of inline field
188+
*/
188189
const noteObject = {
189190
action: 'replace',
190191
file: file,
@@ -196,14 +197,14 @@ export async function updateRowFile(file: TFile, columnId: string, newValue: str
196197
}
197198

198199
async function inlineColumnKey(): Promise<void> {
200+
if (!Object.keys(rowFields.inline).contains(columnId)) {
201+
return;
202+
}
199203
/* Regex explanation
200204
* group 1 is inline field checking that starts in new line
201205
* group 2 is the current value of inline field
202206
*/
203207
const inlineFieldRegex = new RegExp(`(^${columnId}[:]{2})+(.*$)`, 'gm');
204-
if (!inlineFieldRegex.test(content)) {
205-
return;
206-
}
207208
const noteObject = {
208209
action: 'replace',
209210
file: file,
@@ -215,15 +216,15 @@ export async function updateRowFile(file: TFile, columnId: string, newValue: str
215216
}
216217

217218
async function inlineAddColumn(): Promise<void> {
218-
const inlineAddRegex = new RegExp(`(^---\\s+[\\w\\W]+?\\s+---\\s)+(.[\\w\\W]+)`, 'g');
219+
const inlineAddRegex = new RegExp(`(^---[\\s\\S]+?---\\n)+(.*)`, 'g');
219220
const noteObject = {
220221
action: 'replace',
221222
file: file,
222223
regexp: inlineAddRegex,
223224
newValue: `$1${columnId}:: ${newValue}\n$2`
224225
};
225-
await VaultManagerDB.editNoteContent(noteObject);
226226
await persistFrontmatter();
227+
await VaultManagerDB.editNoteContent(noteObject);
227228
}
228229

229230
async function inlineRemoveColumn(): Promise<void> {
@@ -238,7 +239,6 @@ export async function updateRowFile(file: TFile, columnId: string, newValue: str
238239
regexp: inlineFieldRegex
239240
};
240241
await VaultManagerDB.editNoteContent(noteObject);
241-
await persistFrontmatter(columnId);
242242
}
243243
// Record of options
244244
const updateOptions: Record<string, any> = {};
@@ -249,10 +249,9 @@ export async function updateRowFile(file: TFile, columnId: string, newValue: str
249249
// Execute action
250250
if (updateOptions[option]) {
251251
// Check if file has frontmatter
252-
if (currentFrontmatter === undefined) {
252+
if (rowFields.frontmatter) {
253253
// If not, add it
254254
await addFrontmatter();
255-
currentFrontmatter = {};
256255
}
257256
// Then execute the action
258257
await updateOptions[option]();

src/parsers/FileToRowDatabaseFields.ts

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
11
import { RowDatabaseFields } from "cdm/DatabaseModel";
22
import { TableColumn } from "cdm/FolderModel";
33
import { TFile } from "obsidian";
4+
import { DataArray } from "obsidian-dataview/lib/api/data-array";
45
import { DataviewService } from "services/DataviewService";
56

6-
7-
const obtainRowDatabaseFields = (file: TFile, columns: TableColumn[]): RowDatabaseFields => {
7+
/**
8+
* Obtain both frontmatter and inline fields from a file.
9+
* Use column information to determine which fields are frontmatter and which are inline.
10+
* @param file
11+
* @param columns
12+
* @returns
13+
*/
14+
const obtainRowDatabaseFields = (file: TFile, columns: TableColumn[], frontmatterKeys: string[]): RowDatabaseFields => {
815
const columnsToPersist = columns.filter(c => !c.isMetadata);
916
const currentFileFields = DataviewService.getDataviewAPI().page(file.path);
1017
const filteredFields: RowDatabaseFields = { frontmatter: {}, inline: {} };
18+
const columnKeys = columnsToPersist.map(c => c.key);
1119

12-
columnsToPersist.forEach(column => {
13-
const fieldValue = currentFileFields[column.key] ?? "";
14-
if (column.config.isInline) {
15-
filteredFields.inline[column.key] = fieldValue;
16-
} else {
17-
filteredFields.frontmatter[column.key] = fieldValue;
18-
}
19-
});
20+
Object.keys(currentFileFields)
21+
.forEach(fieldKey => {
22+
// Parse nullable fields
23+
const fieldValue = DataviewService.getDataviewAPI().value.isTruthy(currentFileFields[fieldKey])
24+
? currentFileFields[fieldKey] : "";
25+
// Then classify fields into frontmatter and inline
26+
let forceInline = false;
27+
if (columnKeys.includes(fieldKey)) {
28+
forceInline = columnsToPersist.find(c => c.key === fieldKey).config.isInline
29+
}
30+
if (forceInline || !frontmatterKeys.includes(fieldKey)) {
31+
filteredFields.inline[fieldKey] = fieldValue;
32+
} else {
33+
filteredFields.frontmatter[fieldKey] = fieldValue;
34+
}
35+
});
2036
return filteredFields;
2137
};
2238

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,15 @@
11
import { RowDatabaseFields } from "cdm/DatabaseModel";
2-
export const parseFrontmatterFieldsToString = (databaseFields: RowDatabaseFields, original: Record<string, string>, deletedColumn?: string): string => {
2+
import { Literal } from "obsidian-dataview/lib/data-model/value";
3+
import { DataviewService } from "services/DataviewService";
4+
export const parseFrontmatterFieldsToString = (databaseFields: RowDatabaseFields, deletedColumn?: string): string => {
35
const frontmatterFields = databaseFields.frontmatter;
4-
const inlineFields = databaseFields.inline;
56
const array: string[] = [];
67
array.push(`---`);
78
Object.keys(frontmatterFields).forEach(key => {
8-
array.push(`${key}: ${frontmatterFields[key]}`);
9+
if (key !== deletedColumn) {
10+
array.push(...parseLiteralToString(frontmatterFields[key], 0, key));
11+
}
912
});
10-
11-
Object.keys(original)
12-
.filter(fkey =>
13-
// Filter out duplicates and deleted columns
14-
!Object.prototype.hasOwnProperty.call(inlineFields, fkey)
15-
&& !Object.prototype.hasOwnProperty.call(frontmatterFields, fkey)
16-
&& fkey !== deletedColumn)
17-
.forEach(key => {
18-
// add frontmatter fields that are not specified as database fields
19-
array.push(`${key}: ${original[key] ?? ''}`);
20-
});
21-
2213
array.push(`---`);
2314
return array.join('\n');
2415
}
@@ -29,4 +20,21 @@ export const parseInlineFieldsToString = (inlineFields: RowDatabaseFields): stri
2920
array.push(`${key}:: ${inlineFields.inline[key]}`);
3021
});
3122
return array.join('\n');
23+
}
24+
25+
function parseLiteralToString(literal: Literal, level: number, key?: string): string[] {
26+
const literalBlock: string[] = [];
27+
literal = DataviewService.parseDataArray(literal);
28+
if (DataviewService.getDataviewAPI().value.isArray(literal)) {
29+
literalBlock.push(`${" ".repeat(level)}${key}:`);
30+
literal.forEach((literal, index) => {
31+
literalBlock.push(...parseLiteralToString(literal, level + 1));
32+
});
33+
}
34+
else if (key) {
35+
literalBlock.push(`${" ".repeat(level)}${key}: ${literal}`);
36+
} else {
37+
literalBlock.push(`${" ".repeat(level)}- ${literal}`);
38+
}
39+
return literalBlock;
3240
}

src/services/DataviewService.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,7 @@ class DataviewProxy {
6767
return "";
6868
}
6969

70-
if ((literal as any).values !== undefined) {
71-
72-
literal = (literal as any).values[0];
73-
LOGGER.warn(`There is a repeated key into a file with this values: ${(literal as any).values[0]
74-
}`);
75-
}
70+
literal = this.parseDataArray(literal);
7671

7772
const wrapped = this.getDataviewAPI().value.wrapValue(literal)
7873

@@ -96,7 +91,18 @@ class DataviewProxy {
9691
}
9792
return parsedLiteral;
9893
}
94+
/**
95+
* Check if literal is Proxy DataArray, if so, parse it. If not, return same literal
96+
* @param literal
97+
* @returns
98+
*/
99+
parseDataArray(literal: Literal): Literal {
99100

101+
if ((literal as any).values !== undefined && (literal as any).settings !== undefined) {
102+
literal = (literal as any).values
103+
}
104+
return literal;
105+
}
100106
/**
101107
* Singleton instance
102108
* @returns {VaultManager}

src/services/FileManagerService.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class VaultManager {
1919
targetFolder,
2020
filename ?? "Untitled"
2121
);
22-
const content = parseFrontmatterFieldsToString(databasefields, {}).concat("\n").concat(parseInlineFieldsToString(databasefields));
22+
const content = parseFrontmatterFieldsToString(databasefields).concat("\n").concat(parseInlineFieldsToString(databasefields));
2323
await app.vault.modify(created_note, content ?? "");
2424
LOGGER.debug(`<= create_markdown_file`);
2525
return created_note;
@@ -66,12 +66,12 @@ class VaultManager {
6666
return await app.vault.read(tfile);
6767
}
6868

69-
ontainCurrentFrontmatter(content: string): Record<string, string> {
69+
ontainCurrentFrontmatter(content: string): Record<string, any> {
7070
const match = content.match(/^---\s+([\w\W]+?)\s+---/);
7171
if (match) {
7272
const frontmatterRaw = match[1];
7373
const yaml = parseYaml(frontmatterRaw);
74-
const frontmatter: Record<string, string> = {};
74+
const frontmatter: Record<string, any> = {};
7575
Object.keys(yaml)
7676

7777
.forEach(key => {
@@ -84,6 +84,16 @@ class VaultManager {
8484
return undefined;
8585
}
8686
}
87+
88+
obtainFrontmatterKeys(content: string): string[] {
89+
const currentFrontmatter = VaultManagerDB.ontainCurrentFrontmatter(content);
90+
if (currentFrontmatter) {
91+
return Object.keys(currentFrontmatter);
92+
}
93+
else {
94+
return [];
95+
}
96+
}
8797
/**
8898
* Obtain TFile from file path
8999
* @param filePath

0 commit comments

Comments
 (0)