Skip to content
This repository was archived by the owner on Sep 9, 2024. It is now read-only.

Commit 84b73db

Browse files
authored
feat: allow yaml parse/stringify options in config (#977)
1 parent 037ac0b commit 84b73db

File tree

11 files changed

+239
-50
lines changed

11 files changed

+239
-50
lines changed

packages/core/src/__tests__/backend.spec.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
createMockExpandedEntry,
66
createMockUnpublishedEntry,
77
} from '@staticcms/test/data/entry.mock';
8+
import { applyDefaults } from '../actions/config';
89
import {
910
Backend,
1011
expandSearchEntries,
@@ -327,8 +328,10 @@ describe('Backend', () => {
327328
format: 'json-frontmatter',
328329
}) as CollectionWithDefaults;
329330

331+
const config = applyDefaults(createMockConfig({ collections: [collection] }));
332+
330333
const backend = new Backend(initializer, {
331-
config: createMockConfig({ collections: [collection] }),
334+
config,
332335
backendName: 'github',
333336
});
334337

@@ -343,10 +346,10 @@ describe('Backend', () => {
343346
},
344347
});
345348

346-
await backend.persistLocalDraftBackup(entry, collection);
349+
await backend.persistLocalDraftBackup(entry, collection, config);
347350

348351
expect(backend.entryToRaw).toHaveBeenCalledTimes(1);
349-
expect(backend.entryToRaw).toHaveBeenCalledWith(collection, entry);
352+
expect(backend.entryToRaw).toHaveBeenCalledWith(collection, entry, config);
350353
expect(localForage.setItem).toHaveBeenCalledTimes(0);
351354
});
352355

@@ -364,8 +367,10 @@ describe('Backend', () => {
364367
format: 'json-frontmatter',
365368
}) as CollectionWithDefaults;
366369

370+
const config = applyDefaults(createMockConfig({ collections: [collection] }));
371+
367372
const backend = new Backend(initializer, {
368-
config: createMockConfig({ collections: [collection] }),
373+
config,
369374
backendName: 'github',
370375
});
371376

@@ -382,10 +387,10 @@ describe('Backend', () => {
382387
},
383388
});
384389

385-
await backend.persistLocalDraftBackup(entry, collection);
390+
await backend.persistLocalDraftBackup(entry, collection, config);
386391

387392
expect(backend.entryToRaw).toHaveBeenCalledTimes(1);
388-
expect(backend.entryToRaw).toHaveBeenCalledWith(collection, entry);
393+
expect(backend.entryToRaw).toHaveBeenCalledWith(collection, entry, config);
389394
expect(localForage.setItem).toHaveBeenCalledTimes(2);
390395
expect(localForage.setItem).toHaveBeenCalledWith('backup.posts.slug', {
391396
mediaFiles: [{ id: '1', name: 'file.png', path: '/path/to/file.png' }],

packages/core/src/actions/editorialWorkflow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ export function persistUnpublishedEntry(
377377
let serializedEntry = getSerializedEntry(collection, entry);
378378
serializedEntry = {
379379
...serializedEntry,
380-
raw: backend.entryToRaw(collection, serializedEntry),
380+
raw: backend.entryToRaw(collection, serializedEntry, state.config.config),
381381
};
382382
const serializedEntryDraft: EntryDraft = {
383383
...(entryDraft as EntryDraft),

packages/core/src/actions/entries.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ export function persistLocalBackup(entry: Entry, collection: CollectionWithDefau
569569

570570
const backend = currentBackend(configState.config);
571571

572-
return backend.persistLocalDraftBackup(entry, collection);
572+
return backend.persistLocalDraftBackup(entry, collection, configState.config);
573573
};
574574
}
575575

packages/core/src/backend.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -780,11 +780,15 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
780780
return { entry };
781781
}
782782

783-
async persistLocalDraftBackup(entry: Entry, collection: CollectionWithDefaults) {
783+
async persistLocalDraftBackup(
784+
entry: Entry,
785+
collection: CollectionWithDefaults,
786+
config: ConfigWithDefaults,
787+
) {
784788
try {
785789
await this.backupSync.acquire();
786790
const key = getEntryBackupKey(collection.name, entry.slug);
787-
const raw = this.entryToRaw(collection, entry);
791+
const raw = this.entryToRaw(collection, entry, config);
788792

789793
if (!raw.trim()) {
790794
return;
@@ -803,7 +807,9 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
803807

804808
let i18n;
805809
if (hasI18n(collection)) {
806-
i18n = getI18nBackup(collection, entry, entry => this.entryToRaw(collection, entry));
810+
i18n = getI18nBackup(collection, entry, entry =>
811+
this.entryToRaw(collection, entry, config),
812+
);
807813
}
808814

809815
await localForage.setItem<BackupEntry>(key, {
@@ -994,15 +1000,15 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
9941000
dataFile = {
9951001
path,
9961002
slug,
997-
raw: this.entryToRaw(collection, entryDraft.entry),
1003+
raw: this.entryToRaw(collection, entryDraft.entry, config),
9981004
};
9991005
} else {
10001006
const slug = entryDraft.entry.slug;
10011007
dataFile = {
10021008
path: entryDraft.entry.path,
10031009
// for workflow entries we refresh the slug on publish
10041010
slug: customPath && !useWorkflow ? slugFromCustomPath(collection, customPath) : slug,
1005-
raw: this.entryToRaw(collection, entryDraft.entry),
1011+
raw: this.entryToRaw(collection, entryDraft.entry, config),
10061012
newPath: customPath,
10071013
};
10081014
}
@@ -1016,7 +1022,7 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
10161022
collection,
10171023
extension,
10181024
entryDraft.entry,
1019-
(draftData: Entry) => this.entryToRaw(collection, draftData),
1025+
(draftData: Entry) => this.entryToRaw(collection, draftData, config),
10201026
path,
10211027
slug,
10221028
newPath,
@@ -1164,11 +1170,11 @@ export class Backend<EF extends BaseField = UnknownField, BC extends BackendClas
11641170
return this.implementation.deleteFiles([path], commitMessage);
11651171
}
11661172

1167-
entryToRaw(collection: CollectionWithDefaults, entry: Entry): string {
1173+
entryToRaw(collection: CollectionWithDefaults, entry: Entry, config: ConfigWithDefaults): string {
11681174
const format = resolveFormat(collection, entry);
11691175
const fieldsOrder = this.fieldsOrder(collection, entry);
11701176
const fieldsComments = selectFieldsComments(collection, entry);
1171-
return format ? format.toFile(entry.data ?? {}, fieldsOrder, fieldsComments) : '';
1177+
return format ? format.toFile(entry.data ?? {}, config, fieldsOrder, fieldsComments) : '';
11721178
}
11731179

11741180
fieldsOrder(collection: CollectionWithDefaults, entry: Entry) {
Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
1+
import type { ConfigWithDefaults } from '../interface';
2+
13
export default abstract class FileFormatter {
24
abstract name: string;
3-
abstract fromFile(content: string): object;
4-
abstract toFile(data: object, sortedKeys?: string[], comments?: Record<string, string>): string;
5+
abstract fromFile(content: string, config: ConfigWithDefaults): object;
6+
abstract toFile(
7+
data: object,
8+
config: ConfigWithDefaults,
9+
sortedKeys?: string[],
10+
comments?: Record<string, string>,
11+
): string;
512
}

packages/core/src/formats/YamlFormatter.ts

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import yaml, { isNode, isMap } from 'yaml';
1+
import yaml, { isMap, isNode } from 'yaml';
22

3-
import { sortKeys } from './helpers';
4-
import FileFormatter from './FileFormatter';
53
import { isNotNullish } from '../lib/util/null.util';
4+
import FileFormatter from './FileFormatter';
5+
import { sortKeys } from './helpers';
66

7-
import type { Pair, YAMLMap, Node } from 'yaml';
7+
import type { Node, Pair, YAMLMap } from 'yaml';
8+
import type { ConfigWithDefaults } from '../interface';
89

910
function addComments(items: Array<Pair>, comments: Record<string, string>, prefix = '') {
1011
items.forEach(item => {
@@ -25,23 +26,42 @@ function addComments(items: Array<Pair>, comments: Record<string, string>, prefi
2526
class YamlFormatter extends FileFormatter {
2627
name = 'yaml';
2728

28-
fromFile(content: string) {
29+
fromFile(content: string, config: ConfigWithDefaults) {
2930
if (content && content.trim().endsWith('---')) {
3031
content = content.trim().slice(0, -3);
3132
}
32-
return yaml.parse(content);
33+
return yaml.parse(content, {
34+
...(config.yaml?.parseOptions ?? {}),
35+
...(config.yaml?.documentOptions ?? {}),
36+
...(config.yaml?.schemaOptions ?? {}),
37+
...(config.yaml?.toJsOptions ?? {}),
38+
});
3339
}
3440

35-
toFile(data: object, sortedKeys: string[] = [], comments: Record<string, string> = {}) {
36-
const doc = new yaml.Document({ aliasDuplicateObjects: false });
37-
const contents = doc.createNode(data) as YAMLMap<Node>;
41+
toFile(
42+
data: object,
43+
config: ConfigWithDefaults,
44+
sortedKeys: string[] = [],
45+
comments: Record<string, string> = {},
46+
) {
47+
const doc = new yaml.Document({
48+
aliasDuplicateObjects: false,
49+
...(config.yaml?.documentOptions ?? {}),
50+
...(config.yaml?.schemaOptions ?? {}),
51+
...(config.yaml?.parseOptions ?? {}),
52+
...(config.yaml?.createNodeOptions ?? {}),
53+
});
54+
const contents = doc.createNode(data, {
55+
aliasDuplicateObjects: false,
56+
...(config.yaml?.createNodeOptions ?? {}),
57+
}) as YAMLMap<Node>;
3858

3959
addComments(contents.items as Pair<Node>[], comments);
4060

4161
contents.items.sort(sortKeys(sortedKeys, item => item.key?.toString()));
4262
doc.contents = contents;
4363

44-
return doc.toString();
64+
return doc.toString(config.yaml?.toStringOptions);
4565
}
4666
}
4767

0 commit comments

Comments
 (0)