fix: switch to @iarna/toml as toml parser, handle raw dates in datetime field (#715)

This commit is contained in:
Daniel Lautzenheiser 2023-04-19 14:27:46 -04:00 committed by GitHub
parent 804c09415b
commit 95e64792dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 39 additions and 3483 deletions

View File

@ -2,4 +2,3 @@ dist/
bin/ bin/
public/ public/
.cache/ .cache/
j-toml.js

View File

@ -33,6 +33,10 @@
content: content:
'{\n"title": "This is a JSON front matter post",\n"draft": false,\n"image": "/assets/uploads/moby-dick.jpg",\n"date": "2015-02-15T00:00:00.000Z"\n}\n\n# I Am a Title in Markdown\n\nHello, world\n\n* One Thing\n* Another Thing\n* A Third Thing\n', '{\n"title": "This is a JSON front matter post",\n"draft": false,\n"image": "/assets/uploads/moby-dick.jpg",\n"date": "2015-02-15T00:00:00.000Z"\n}\n\n# I Am a Title in Markdown\n\nHello, world\n\n* One Thing\n* Another Thing\n* A Third Thing\n',
}, },
'2015-02-15-this-is-a-toml-frontmatter-post.md': {
content:
'+++\ntitle = "This is a TOML front matter post"\ndraft = true\nimage = "/assets/uploads/moby-dick.jpg"\ndate = 2015-02-14T00:00:00.000Z\n+++\n\n# I Am a Title in Markdown\n\nHello, world\n\n* One Thing\n* Another Thing\n* A Third Thing\n',
},
'2015-02-14-this-is-a-post-with-a-different-extension.other': { '2015-02-14-this-is-a-post-with-a-different-extension.other': {
content: content:
'---\ntitle: This post should not appear because the extension is different\ndraft: false\nimage: /assets/uploads/moby-dick.jpg\ndate: 2015-02-14T00:00:00.000Z\n---\n\n# I Am a Title in Markdown\n\nHello, world\n\n* One Thing\n* Another Thing\n* A Third Thing\n', '---\ntitle: This post should not appear because the extension is different\ndraft: false\nimage: /assets/uploads/moby-dick.jpg\ndate: 2015-02-14T00:00:00.000Z\n---\n\n# I Am a Title in Markdown\n\nHello, world\n\n* One Thing\n* Another Thing\n* A Third Thing\n',

View File

@ -190,6 +190,7 @@
"@babel/preset-typescript": "7.21.4", "@babel/preset-typescript": "7.21.4",
"@emotion/eslint-plugin": "11.10.0", "@emotion/eslint-plugin": "11.10.0",
"@emotion/jest": "11.10.5", "@emotion/jest": "11.10.5",
"@iarna/toml": "2.2.5",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10", "@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
"@simbathesailor/use-what-changed": "2.0.0", "@simbathesailor/use-what-changed": "2.0.0",
"@testing-library/dom": "9.2.0", "@testing-library/dom": "9.2.0",

View File

@ -66,7 +66,7 @@ export default function useWidgetsFor(
if (field.widget === 'list' || Array.isArray(value)) { if (field.widget === 'list' || Array.isArray(value)) {
let finalValue: ObjectValue[]; let finalValue: ObjectValue[];
if (!value || typeof value !== 'object') { if (!value || typeof value !== 'object' || value instanceof Date) {
finalValue = []; finalValue = [];
} else if (!Array.isArray(value)) { } else if (!Array.isArray(value)) {
finalValue = [value]; finalValue = [value];
@ -100,7 +100,7 @@ export default function useWidgetsFor(
}); });
} }
if (typeof value !== 'object') { if (typeof value !== 'object' || value instanceof Date) {
return { return {
data: {}, data: {},
widgets: {}, widgets: {},

View File

@ -1,16 +1,15 @@
import toml from '@iarna/toml';
import FileFormatter from './FileFormatter'; import FileFormatter from './FileFormatter';
import { parse, stringify } from './util/j-toml';
class TomlFormatter extends FileFormatter { class TomlFormatter extends FileFormatter {
fromFile(content: string) { fromFile(content: string) {
return parse(content) as object; return toml.parse(content) as object;
} }
toFile(data: object): string { toFile(data: object): string {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
return stringify(data as any, { return toml.stringify(data as any);
newline: '\n',
});
} }
} }

View File

@ -1 +0,0 @@
export default {};

View File

@ -1,493 +0,0 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-use-before-define */
export as namespace TOML;
export = exports;
declare namespace exports {
export const version: '1.38.0';
export const parse: {
(
this: void,
source: Source,
specificationVersion: 1.0 | 0.5 | 0.4 | 0.3 | 0.2 | 0.1,
multilineStringJoiner?: string,
useBigInt?: boolean | number,
xOptions?: XOptions,
): Table;
(
this: void,
source: Source,
multilineStringJoiner?: string,
useBigInt?: boolean | number,
xOptions?: XOptions,
): Table;
(
this: void,
source: Source,
options?: {
readonly joiner?: string;
readonly bigint?: boolean | number;
readonly x?: XOptions;
},
): Table;
} & {
readonly [SpecificationVersion in 1.0 | 0.5 | 0.4 | 0.3 | 0.2 | 0.1]: {
(
this: void,
source: Source,
multilineStringJoiner?: string,
useBigInt?: boolean | number,
xOptions?: XOptions,
): Table;
(
this: void,
source: Source,
options?: {
readonly joiner?: string;
readonly bigint?: boolean | number;
readonly x?: XOptions;
},
): Table;
};
};
export function stringify(
this: void,
rootTable: ReadonlyTable,
options?: {
readonly integer?: number;
readonly newline?: '\n' | '\r\n';
readonly newlineAround?: 'document' | 'section' | 'header' | 'pairs' | 'pair';
readonly indent?: string | number;
readonly T?: 'T' | 't' | ' ';
readonly Z?: 'Z' | 'z';
readonly xNull?: boolean;
readonly xBeforeNewlineInMultilineTable?: ',' | '';
readonly forceInlineArraySpacing?: 0 | 1 | 2 | 3;
},
): string;
export function isSection(this: void, table: ReadonlyTable): boolean;
export function isInline(this: void, value: ReadonlyTable | ReadonlyArray): boolean;
export function Section<T extends ReadonlyTable>(this: void, table: T): T;
export function inline<T extends ReadonlyArray>(
this: void,
value: T,
inlineMode?: 0 | 1 | 2 | 3,
): T;
export function inline<T extends ReadonlyTable>(this: void, value: T): T;
export const multiline: {
readonly array: {
<T extends ReadonlyArray>(this: void, array: T): T;
};
<T extends ReadonlyTable>(this: void, table: T): T;
(this: void, value: string): {
[_literal]: [`"""`, ...string[], `${string}"""`] | [`'''`, ...string[], `${string}'''`];
} & object &
String;
(this: void, lines: readonly string[]): {
[_literal]: [`"""`, ...string[], `${string}"""`] | [`'''`, ...string[], `${string}'''`];
} & object;
(this: void, lines: readonly string[], value: string): {
[_literal]: [`"""`, ...string[], `${string}"""`] | [`'''`, ...string[], `${string}'''`];
} & object &
String;
readonly basic: {
(this: void, value: string): { [_literal]: [`"""`, ...string[], `${string}"""`] } & object &
String;
(this: void, lines: readonly string[]): {
[_literal]: [`"""`, ...string[], `${string}"""`];
} & object;
(this: void, lines: readonly string[], value: string): {
[_literal]: [`"""`, ...string[], `${string}"""`];
} & object &
String;
};
};
export function basic(this: void, value: string): { [_literal]: `"${string}"` } & object & String;
export function literal(
this: void,
literal: string,
): { [_literal]: string | [string, ...string[]] } & object;
export function literal(
this: void,
literal: string,
value: string,
): { [_literal]: string | [string, ...string[]] } & object & String;
export function literal(
this: void,
literal: string,
value: number,
): { [_literal]: string | [string, ...string[]] } & object & Number;
export function literal(
this: void,
literal: string,
value: bigint,
): { [_literal]: string | [string, ...string[]] } & object & BigInt;
export function literal(
this: void,
literal: TemplateStringsArray,
...chars: string[]
): { [_literal]: string | [string, ...string[]] } & object;
export function commentFor(this: void, key: string): symbol;
export const commentForThis: unique symbol;
export { OffsetDateTime, LocalDateTime, LocalDate, LocalTime, Keys };
export { exports as default };
}
declare class OffsetDateTime {
readonly toJSON: Date['toJSON'];
readonly [Symbol.toStringTag]: 'OffsetDateTime';
readonly toISOString: (
this: Readonly<OffsetDateTime>,
) => `${number}-${number}-${number}T${number}:${number}:${number}${'' | `.${number}`}${
| 'Z'
| `${'+' | '-'}${number}:${number}`}`;
readonly valueOf: (this: Readonly<OffsetDateTime>) => `${number}${'' | `.${number}`}`;
private [OffsetDateTime_ISOString]: string;
private [OffsetDateTime_value]: string;
constructor(
literal: `${number}-${number}-${number}${'T' | 't' | ' '}${number}:${number}:${number}${
| ''
| `.${number}`}${'Z' | 'z' | `${'+' | '-'}${number}:${number}`}`,
);
readonly getUTCFullYear: (this: Readonly<OffsetDateTime>) => _1_10000;
readonly getUTCMonth: (this: Readonly<OffsetDateTime>) => _0_11;
readonly getUTCDate: (this: Readonly<OffsetDateTime>) => _1_31;
readonly getUTCHours: (this: Readonly<OffsetDateTime>) => _0_23;
readonly getUTCMinutes: (this: Readonly<OffsetDateTime>) => _0_59;
readonly getUTCSeconds: (this: Readonly<OffsetDateTime>) => _0_59;
readonly getUTCMilliseconds: (this: Readonly<OffsetDateTime>) => _0_999;
readonly getUTCDay: (this: Readonly<OffsetDateTime>) => _0_6;
readonly getTimezoneOffset: (this: Readonly<OffsetDateTime>) => _1439_1439;
readonly getTime: (this: Readonly<OffsetDateTime>) => number;
}
declare class LocalDateTime {
readonly toJSON: Date['toJSON'];
readonly [Symbol.toStringTag]: 'LocalDateTime';
readonly toISOString: (
this: Readonly<LocalDateTime>,
) => `${number}-${number}-${number}T${number}:${number}:${number}${'' | `.${number}`}`;
readonly valueOf: (this: Readonly<LocalDateTime>) => `${number}`;
private [LocalDateTime_ISOString]: string;
private [LocalDateTime_value]: string;
constructor(
literal: `${number}-${number}-${number}${'T' | 't' | ' '}${number}:${number}:${number}${
| ''
| `.${number}`}`,
);
readonly getFullYear: (this: Readonly<LocalDateTime>) => _0_9999;
readonly setFullYear: (this: LocalDateTime, year: _0_9999) => void;
readonly getMonth: (this: Readonly<LocalDateTime>) => _0_11;
readonly setMonth: (this: LocalDateTime, month: _0_11) => void;
readonly getDate: (this: Readonly<LocalDateTime>) => _1_31;
readonly setDate: (this: LocalDateTime, date: _1_31) => void;
readonly getHours: (this: Readonly<LocalDateTime>) => _0_23;
readonly setHours: (this: LocalDateTime, hours: _0_23) => void;
readonly getMinutes: (this: Readonly<LocalDateTime>) => _0_59;
readonly setMinutes: (this: LocalDateTime, min: _0_59) => void;
readonly getSeconds: (this: Readonly<LocalDateTime>) => _0_59;
readonly setSeconds: (this: LocalDateTime, sec: _0_59) => void;
readonly getMilliseconds: (this: Readonly<LocalDateTime>) => _0_999;
readonly setMilliseconds: (this: LocalDateTime, ms: _0_999) => void;
}
declare class LocalDate {
readonly toJSON: Date['toJSON'];
readonly [Symbol.toStringTag]: 'LocalDate';
readonly toISOString: (this: Readonly<LocalDate>) => `${number}-${number}-${number}`;
readonly valueOf: (this: Readonly<LocalDate>) => `${number}`;
private [LocalDate_ISOString]: string;
private [LocalDate_value]: string;
constructor(literal: `${number}-${number}-${number}`);
readonly getFullYear: (this: Readonly<LocalDate>) => _0_9999;
readonly setFullYear: (this: LocalDate, year: _0_9999) => void;
readonly getMonth: (this: Readonly<LocalDate>) => _0_11;
readonly setMonth: (this: LocalDate, month: _0_11) => void;
readonly getDate: (this: Readonly<LocalDate>) => _1_31;
readonly setDate: (this: LocalDate, date: _1_31) => void;
}
declare class LocalTime {
readonly toJSON: Date['toJSON'];
readonly [Symbol.toStringTag]: 'LocalTime';
readonly toISOString: (
this: Readonly<LocalTime>,
) => `${number}:${number}:${number}${'' | `.${number}`}`;
readonly valueOf: (this: Readonly<LocalTime>) => `${number}`;
private [LocalTime_ISOString]: string;
private [LocalTime_value]: string;
constructor(literal: `${number}:${number}:${number}${'' | `.${number}`}`);
readonly getHours: (this: Readonly<LocalTime>) => _0_23;
readonly setHours: (this: LocalTime, hours: _0_23) => void;
readonly getMinutes: (this: Readonly<LocalTime>) => _0_59;
readonly setMinutes: (this: LocalTime, min: _0_59) => void;
readonly getSeconds: (this: Readonly<LocalTime>) => _0_59;
readonly setSeconds: (this: LocalTime, sec: _0_59) => void;
readonly getMilliseconds: (this: Readonly<LocalTime>) => _0_999;
readonly setMilliseconds: (this: LocalTime, ms: _0_999) => void;
}
declare class Keys extends RegExp {
readonly lastIndex: number;
constructor(keys: ArrayLike<string>);
readonly test: (this: Keys, key: string) => boolean;
}
declare const _literal: unique symbol;
type Source =
| string
| ArrayBufferLike
| {
readonly path: string;
readonly data?: undefined;
readonly require:
| {
readonly resolve?: { readonly paths?: undefined };
(this: void, id: 'fs'): {
readonly readFileSync: (this: void, path: string) => ArrayBufferLike;
};
}
| {
readonly resolve: { readonly paths: (this: void, request: string) => null | string[] };
(this: void, id: 'path'): {
readonly resolve: (this: void, dirname: string, filename: string) => string;
};
(this: void, id: 'fs'): {
readonly readFileSync: (this: void, path: string) => ArrayBufferLike;
};
};
}
| {
readonly path: string;
readonly data: string | ArrayBufferLike;
readonly require?:
| {
readonly resolve?: { readonly paths?: undefined };
}
| {
readonly resolve: { readonly paths: (this: void, request: string) => null | string[] };
(this: void, id: 'path'): {
readonly resolve: (this: void, dirname: string, filename: string) => string;
};
};
};
type XOptions = null | {
readonly keys?: null | Keys;
readonly order?: boolean;
readonly exact?: boolean;
readonly multi?: boolean;
readonly longer?: boolean;
readonly string?: boolean;
readonly comment?: boolean;
readonly literal?: boolean;
readonly null?: boolean;
readonly tag?:
| null
| (<
Table extends object & { [key: string | symbol]: any },
Key extends string | symbol,
Array extends any[],
Index extends number,
Tag extends string,
>(
this: void,
each:
| { table: Table; key: Key; tag: Tag }
| { array: Array; index: Index; tag: Tag }
| { table: Table; key: Key; array: Array; index: Index; tag: Tag },
) => void);
};
type ReadonlyTable = object & { readonly [key: string]: ReadonlyValue };
type ReadonlyArray = readonly ReadonlyValue[];
type ReadonlyValue =
| ({ readonly [_literal]: string | readonly [string, ...string[]] } & object)
| null
| boolean
| bigint
| number
| string
| ReadonlyDatetime
| ReadonlyArray
| ReadonlyTable;
interface ReadonlyDatetime {
readonly toISOString: (this: this) => string;
}
type Table = object & { [key: string]: Value };
type Array = Value[];
type Value =
| (object & BigInt & { [_literal]: string })
| (object & Number & { [_literal]: string })
| (object & String & { [_literal]: string | [string, ...string[]] })
| null
| boolean
| bigint
| number
| string
| Datetime
| Array
| Table;
type Datetime = OffsetDateTime | LocalDateTime | LocalDate | LocalTime;
declare const OffsetDateTime_ISOString: unique symbol;
declare const OffsetDateTime_value: unique symbol;
declare const LocalDateTime_ISOString: unique symbol;
declare const LocalDateTime_value: unique symbol;
declare const LocalDate_ISOString: unique symbol;
declare const LocalDate_value: unique symbol;
declare const LocalTime_ISOString: unique symbol;
declare const LocalTime_value: unique symbol;
type _1439_1439 = -1439 | ({} & number) | 1439;
type _1_10000 = -1 | ({} & number) | 10000;
type _0_9999 = 0 | ({} & number) | 9999;
type _0_999 = 0 | ({} & number) | 999;
type _0_6 = 0 | 1 | 2 | 3 | 4 | 5 | 6;
type _0_11 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11;
type _0_23 =
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| 9
| 10
| 11
| 12
| 13
| 14
| 15
| 16
| 17
| 18
| 19
| 20
| 21
| 22
| 23;
type _1_31 =
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| 9
| 10
| 11
| 12
| 13
| 14
| 15
| 16
| 17
| 18
| 19
| 20
| 21
| 22
| 23
| 24
| 25
| 26
| 27
| 28
| 29
| 30
| 31;
type _0_59 =
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| 9
| 10
| 11
| 12
| 13
| 14
| 15
| 16
| 17
| 18
| 19
| 20
| 21
| 22
| 23
| 24
| 25
| 26
| 27
| 28
| 29
| 30
| 31
| 32
| 33
| 34
| 35
| 36
| 37
| 38
| 39
| 40
| 41
| 42
| 43
| 44
| 45
| 46
| 47
| 48
| 49
| 50
| 51
| 52
| 53
| 54
| 55
| 56
| 57
| 58
| 59;

File diff suppressed because it is too large Load Diff

View File

@ -76,6 +76,7 @@ export type ValueOrNestedValue =
| (string | number)[] | (string | number)[]
| boolean | boolean
| ObjectValue | ObjectValue
| Date
| ValueOrNestedValue[] | ValueOrNestedValue[]
| null | null
| undefined; | undefined;

View File

@ -308,7 +308,10 @@ export function selectMediaFilePath(
if (!currentFolder) { if (!currentFolder) {
let publicFolder = trim(config['public_folder'] ?? mediaFolder, '/'); let publicFolder = trim(config['public_folder'] ?? mediaFolder, '/');
const mediaPathDir = trim(dirname(mediaPath), '/'); let mediaPathDir = trim(dirname(mediaPath), '/');
if (mediaPathDir === '.') {
mediaPathDir = '';
}
if (hasCustomFolder('public_folder', collection, entryMap?.slug, field)) { if (hasCustomFolder('public_folder', collection, entryMap?.slug, field)) {
publicFolder = trim( publicFolder = trim(
@ -316,6 +319,7 @@ export function selectMediaFilePath(
'/', '/',
); );
} }
if (mediaPathDir.includes(publicFolder) && mediaPathDir != mediaFolder) { if (mediaPathDir.includes(publicFolder) && mediaPathDir != mediaFolder) {
mediaFolder = selectMediaFolder( mediaFolder = selectMediaFolder(
config, config,

View File

@ -42,7 +42,7 @@ function convertMuiTextFieldProps({
}; };
} }
const DateTimeControl: FC<WidgetControlProps<string, DateTimeField>> = ({ const DateTimeControl: FC<WidgetControlProps<string | Date, DateTimeField>> = ({
field, field,
label, label,
value, value,
@ -142,6 +142,10 @@ const DateTimeControl: FC<WidgetControlProps<string, DateTimeField>> = ({
valueToParse = defaultValue; valueToParse = defaultValue;
} }
if (typeof valueToParse !== 'string') {
return valueToParse;
}
return format ? parse(valueToParse, format, new Date()) : parseISO(valueToParse); return format ? parse(valueToParse, format, new Date()) : parseISO(valueToParse);
}, [defaultValue, format, internalValue]); }, [defaultValue, format, internalValue]);

View File

@ -3,7 +3,7 @@ import React from 'react';
import type { DateTimeField, WidgetPreviewProps } from '@staticcms/core/interface'; import type { DateTimeField, WidgetPreviewProps } from '@staticcms/core/interface';
import type { FC } from 'react'; import type { FC } from 'react';
const DatePreview: FC<WidgetPreviewProps<string, DateTimeField>> = ({ value }) => { const DatePreview: FC<WidgetPreviewProps<string | Date, DateTimeField>> = ({ value }) => {
return <div>{value ? value.toString() : null}</div>; return <div>{value ? value.toString() : null}</div>;
}; };

View File

@ -6,7 +6,10 @@ import { localToUTC } from './utc.util';
import type { DateTimeField, FieldGetDefaultMethod } from '@staticcms/core/interface'; import type { DateTimeField, FieldGetDefaultMethod } from '@staticcms/core/interface';
const getDefaultValue: FieldGetDefaultMethod<string, DateTimeField> = (defaultValue, field) => { const getDefaultValue: FieldGetDefaultMethod<string | Date, DateTimeField> = (
defaultValue,
field,
) => {
if (isNotNullish(defaultValue)) { if (isNotNullish(defaultValue)) {
return defaultValue; return defaultValue;
} }

View File

@ -5,7 +5,7 @@ import schema from './schema';
import type { DateTimeField, WidgetParam } from '@staticcms/core/interface'; import type { DateTimeField, WidgetParam } from '@staticcms/core/interface';
const DateTimeWidget = (): WidgetParam<string, DateTimeField> => { const DateTimeWidget = (): WidgetParam<string | Date, DateTimeField> => {
return { return {
name: 'datetime', name: 'datetime',
controlComponent, controlComponent,

View File

@ -29,7 +29,7 @@ function handleSummary(
label: string, label: string,
item: ValueOrNestedValue, item: ValueOrNestedValue,
): string { ): string {
if (typeof item === 'object' && !Array.isArray(item)) { if (typeof item === 'object' && !(item instanceof Date) && !Array.isArray(item)) {
const labeledItem: EntryData = { const labeledItem: EntryData = {
...item, ...item,
fields: { fields: {
@ -151,7 +151,9 @@ const ListItem: FC<ListItemProps> = ({
} }
const labelFieldValue = const labelFieldValue =
typeof objectValue === 'object' && !Array.isArray(objectValue) typeof objectValue === 'object' &&
!(objectValue instanceof Date) &&
!Array.isArray(objectValue)
? objectValue[labelField.name] ? objectValue[labelField.name]
: objectValue; : objectValue;

View File

@ -14,5 +14,3 @@ if (typeof window === 'undefined') {
} }
global.URL.createObjectURL = jest.fn(); global.URL.createObjectURL = jest.fn();
jest.mock('../src/formats/util/j-toml');

View File

@ -65,9 +65,11 @@ You may also specify a custom `extension` not included in the list above, as lon
- `yml` or `yaml`: parses and saves files as YAML-formatted data files; saves with `yml` extension by default - `yml` or `yaml`: parses and saves files as YAML-formatted data files; saves with `yml` extension by default
- `json`: parses and saves files as JSON-formatted data files; saves with `json` extension by default - `json`: parses and saves files as JSON-formatted data files; saves with `json` extension by default
- `toml`: parses and saves files as TOML-formatted data files; saves with `toml` extension by default
- `frontmatter`: parses files and saves files with data frontmatter followed by an unparsed body text (edited using a `body` field); saves with `md` extension by default; default for collections that can't be inferred. Collections with `frontmatter` format (either inferred or explicitly set) can parse files with frontmatter in YAML or JSON format. However, they will be saved with YAML frontmatter. - `frontmatter`: parses files and saves files with data frontmatter followed by an unparsed body text (edited using a `body` field); saves with `md` extension by default; default for collections that can't be inferred. Collections with `frontmatter` format (either inferred or explicitly set) can parse files with frontmatter in YAML or JSON format. However, they will be saved with YAML frontmatter.
- `yaml-frontmatter`: same as the `frontmatter` format above, except frontmatter will be both parsed and saved only as YAML, followed by unparsed body text. The default delimiter for this option is `---`. - `yaml-frontmatter`: same as the `frontmatter` format above, except frontmatter will be both parsed and saved only as YAML, followed by unparsed body text. The default delimiter for this option is `---`.
- `json-frontmatter`: same as the `frontmatter` format above, except frontmatter will be both parsed and saved as JSON, followed by unparsed body text. The default delimiter for this option is `{` `}`. - `json-frontmatter`: same as the `frontmatter` format above, except frontmatter will be both parsed and saved as JSON, followed by unparsed body text. The default delimiter for this option is `{` `}`.
- `toml-frontmatter`: same as the `frontmatter` format above, except frontmatter will be both parsed and saved only as TOML, followed by unparsed body text. The default delimiter for this option is `+++`.
## Frontmatter Delimiter ## Frontmatter Delimiter

View File

@ -1855,6 +1855,11 @@
resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340"
integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==
"@iarna/toml@2.2.5":
version "2.2.5"
resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.5.tgz#b32366c89b43c6f8cefbdefac778b9c828e3ba8c"
integrity sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==
"@icons/material@^0.2.4": "@icons/material@^0.2.4":
version "0.2.4" version "0.2.4"
resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"