From fbe967abbb999b97b17d6d60fff43e0de36c5a0f Mon Sep 17 00:00:00 2001 From: Jean Date: Fri, 24 Sep 2021 20:03:03 +0200 Subject: [PATCH 01/14] feat: register custom formats --- .../netlify-cms-core/src/formats/formats.ts | 6 +++++ packages/netlify-cms-core/src/lib/registry.js | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/packages/netlify-cms-core/src/formats/formats.ts b/packages/netlify-cms-core/src/formats/formats.ts index 3508986b459f..56c282ccb03b 100644 --- a/packages/netlify-cms-core/src/formats/formats.ts +++ b/packages/netlify-cms-core/src/formats/formats.ts @@ -5,6 +5,7 @@ import yamlFormatter from './yaml'; import tomlFormatter from './toml'; import jsonFormatter from './json'; import { FrontmatterInfer, frontmatterJSON, frontmatterTOML, frontmatterYAML } from './frontmatter'; +import { getCustomFormatsExtensions, getCustomFormatsFormatters } from '../lib/registry'; import type { Delimiter } from './frontmatter'; import type { Collection, EntryObject, Format } from '../types/redux'; @@ -23,6 +24,10 @@ export const formatExtensions = { 'yaml-frontmatter': 'md', }; +export function getFormatExtensions() { + return { ...formatExtensions, ...getCustomFormatsExtensions() }; +} + export const extensionFormatters = { yml: yamlFormatter, yaml: yamlFormatter, @@ -43,6 +48,7 @@ function formatByName(name: Format, customDelimiter?: Delimiter) { 'json-frontmatter': frontmatterJSON(customDelimiter), 'toml-frontmatter': frontmatterTOML(customDelimiter), 'yaml-frontmatter': frontmatterYAML(customDelimiter), + ...getCustomFormatsFormatters(), }[name]; } diff --git a/packages/netlify-cms-core/src/lib/registry.js b/packages/netlify-cms-core/src/lib/registry.js index 1e56a1b94f2b..bdffa4de1339 100644 --- a/packages/netlify-cms-core/src/lib/registry.js +++ b/packages/netlify-cms-core/src/lib/registry.js @@ -31,6 +31,7 @@ const registry = { mediaLibraries: [], locales: {}, eventHandlers, + formats: {}, }; export default { @@ -58,6 +59,10 @@ export default { removeEventListener, getEventListeners, invokeEvent, + registerCustomFormat, + getCustomFormats, + getCustomFormatsExtensions, + getCustomFormatsFormatters, }; /** @@ -284,3 +289,23 @@ export function registerLocale(locale, phrases) { export function getLocale(locale) { return registry.locales[locale]; } + +export function registerCustomFormat(name, extension, formatter) { + registry.formats[name] = { extension, formatter }; +} + +export function getCustomFormats() { + return registry.formats; +} + +export function getCustomFormatsExtensions() { + return Object.entries(registry.formats).reduce(function (acc, [name, { extension }]) { + return { ...acc, [name]: extension }; + }, {}); +} + +export function getCustomFormatsFormatters() { + return Object.entries(registry.formats).reduce(function (acc, [name, { formatter }]) { + return { ...acc, [name]: formatter }; + }, {}); +} From f7952f23e8a059f39decb526458bac6368b090b4 Mon Sep 17 00:00:00 2001 From: Jean Date: Wed, 29 Sep 2021 09:35:13 +0200 Subject: [PATCH 02/14] fix: register custom formats validation --- dev-test/config.yml | 21 ++++++++++++ dev-test/index.html | 32 +++++++++++++++++++ .../src/constants/configSchema.js | 4 +-- .../src/reducers/collections.ts | 4 +-- packages/netlify-cms-core/src/types/redux.ts | 2 +- 5 files changed, 58 insertions(+), 5 deletions(-) diff --git a/dev-test/config.yml b/dev-test/config.yml index 2ffe5041ddb5..34d1a97cd962 100644 --- a/dev-test/config.yml +++ b/dev-test/config.yml @@ -7,6 +7,27 @@ publish_mode: editorial_workflow media_folder: assets/uploads collections: # A list of collections the CMS should be able to edit + - name: 'translations' + label: 'Translations' + folder: '_translations' + i18n: + structure: 'multiple_folders' + format: custom + identifier_field: namespace + fields: + - label: Namespace + name: namespace + widget: string + i18n: false + - label: 'Items' + label_singular: 'Item' + name: 'list' + widget: list + fields: + - name: key + widget: string + - name: value + widget: string - name: 'posts' # Used in routes, ie.: /admin/collections/:slug/edit label: 'Posts' # Used in the UI label_singular: 'Post' # Used in the UI, ie: "New Post" diff --git a/dev-test/index.html b/dev-test/index.html index 0a68d4e30cd6..ca1f5c1888d9 100644 --- a/dev-test/index.html +++ b/dev-test/index.html @@ -6,6 +6,11 @@ Netlify CMS Development Test + diff --git a/packages/netlify-cms-core/src/constants/configSchema.js b/packages/netlify-cms-core/src/constants/configSchema.js index 31e3711f8745..e95dc7b66db8 100644 --- a/packages/netlify-cms-core/src/constants/configSchema.js +++ b/packages/netlify-cms-core/src/constants/configSchema.js @@ -8,7 +8,7 @@ import { import ajvErrors from 'ajv-errors'; import uuid from 'uuid/v4'; -import { formatExtensions, frontmatterFormats, extensionFormatters } from '../formats/formats'; +import { getFormatExtensions, frontmatterFormats, extensionFormatters } from '../formats/formats'; import { getWidgets } from '../lib/registry'; import { I18N_STRUCTURE, I18N_FIELD } from '../lib/i18n'; @@ -231,7 +231,7 @@ function getConfigSchema() { preview: { type: 'boolean' }, }, }, - format: { type: 'string', enum: Object.keys(formatExtensions) }, + format: { type: 'string', enum: Object.keys(getFormatExtensions()) }, extension: { type: 'string' }, frontmatter_delimiter: { type: ['string', 'array'], diff --git a/packages/netlify-cms-core/src/reducers/collections.ts b/packages/netlify-cms-core/src/reducers/collections.ts index 0bd045d56bdb..19c1e1c170f1 100644 --- a/packages/netlify-cms-core/src/reducers/collections.ts +++ b/packages/netlify-cms-core/src/reducers/collections.ts @@ -7,7 +7,7 @@ import { CONFIG_SUCCESS } from '../actions/config'; import { FILES, FOLDER } from '../constants/collectionTypes'; import { COMMIT_DATE, COMMIT_AUTHOR } from '../constants/commitProps'; import { INFERABLE_FIELDS, IDENTIFIER_FIELDS, SORTABLE_FIELDS } from '../constants/fieldInference'; -import { formatExtensions } from '../formats/formats'; +import { getFormatExtensions } from '../formats/formats'; import { selectMediaFolder } from './entries'; import { summaryFormatter } from '../lib/formatters'; @@ -48,7 +48,7 @@ const selectors = { entryExtension(collection: Collection) { return ( collection.get('extension') || - get(formatExtensions, collection.get('format') || 'frontmatter') + get(getFormatExtensions(), collection.get('format') || 'frontmatter') ).replace(/^\./, ''); }, fields(collection: Collection) { diff --git a/packages/netlify-cms-core/src/types/redux.ts b/packages/netlify-cms-core/src/types/redux.ts index e00ad57246a8..aa670704d68e 100644 --- a/packages/netlify-cms-core/src/types/redux.ts +++ b/packages/netlify-cms-core/src/types/redux.ts @@ -598,7 +598,7 @@ type i18n = StaticallyTypedRecord<{ default_locale: string; }>; -export type Format = keyof typeof formatExtensions; +export type Format = keyof typeof formatExtensions | string; type CollectionObject = { name: string; From 988a06db72408fd7afec114f419f389573b8cea4 Mon Sep 17 00:00:00 2001 From: Jean Date: Thu, 30 Sep 2021 10:37:56 +0200 Subject: [PATCH 03/14] fix: change 'format' field validation to string instead of enum Format will have the same behaviour as the widget property --- packages/netlify-cms-core/index.d.ts | 19 ++++++++++--------- .../src/constants/configSchema.js | 4 ++-- .../netlify-cms-core/src/formats/formats.ts | 11 ++++++++--- packages/netlify-cms-core/src/lib/registry.js | 5 +++++ 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/packages/netlify-cms-core/index.d.ts b/packages/netlify-cms-core/index.d.ts index 2a82e4d3178d..bd401f11e806 100644 --- a/packages/netlify-cms-core/index.d.ts +++ b/packages/netlify-cms-core/index.d.ts @@ -36,15 +36,7 @@ declare module 'netlify-cms-core' { value: any; } - export type CmsCollectionFormatType = - | 'yml' - | 'yaml' - | 'toml' - | 'json' - | 'frontmatter' - | 'yaml-frontmatter' - | 'toml-frontmatter' - | 'json-frontmatter'; + export type CmsCollectionFormatType = string; export type CmsAuthScope = 'repo' | 'public_repo'; @@ -498,6 +490,11 @@ declare module 'netlify-cms-core' { export type CmsLocalePhrases = any; // TODO: type properly + export type Formatter = { + fromFile(content: string): unknown; + toFile(data: object, sortedKeys?: string[], comments?: Record): string; + }; + export interface CmsRegistry { backends: { [name: string]: CmsRegistryBackend; @@ -517,6 +514,9 @@ declare module 'netlify-cms-core' { locales: { [name: string]: CmsLocalePhrases; }; + formats: { + [name: string]: Formatter; + }; } type GetAssetFunction = (asset: string) => { @@ -576,6 +576,7 @@ declare module 'netlify-cms-core' { serializer: CmsWidgetValueSerializer, ) => void; resolveWidget: (name: string) => CmsWidget | undefined; + registerCustomFormat: (name: string, extension: string, formatter: Formatter) => void; } export const NetlifyCmsCore: CMS; diff --git a/packages/netlify-cms-core/src/constants/configSchema.js b/packages/netlify-cms-core/src/constants/configSchema.js index e95dc7b66db8..a7d3c14a2530 100644 --- a/packages/netlify-cms-core/src/constants/configSchema.js +++ b/packages/netlify-cms-core/src/constants/configSchema.js @@ -8,7 +8,7 @@ import { import ajvErrors from 'ajv-errors'; import uuid from 'uuid/v4'; -import { getFormatExtensions, frontmatterFormats, extensionFormatters } from '../formats/formats'; +import { frontmatterFormats, extensionFormatters } from '../formats/formats'; import { getWidgets } from '../lib/registry'; import { I18N_STRUCTURE, I18N_FIELD } from '../lib/i18n'; @@ -231,7 +231,7 @@ function getConfigSchema() { preview: { type: 'boolean' }, }, }, - format: { type: 'string', enum: Object.keys(getFormatExtensions()) }, + format: { type: 'string' }, extension: { type: 'string' }, frontmatter_delimiter: { type: ['string', 'array'], diff --git a/packages/netlify-cms-core/src/formats/formats.ts b/packages/netlify-cms-core/src/formats/formats.ts index 56c282ccb03b..dfeb3280fde0 100644 --- a/packages/netlify-cms-core/src/formats/formats.ts +++ b/packages/netlify-cms-core/src/formats/formats.ts @@ -10,6 +10,7 @@ import { getCustomFormatsExtensions, getCustomFormatsFormatters } from '../lib/r import type { Delimiter } from './frontmatter'; import type { Collection, EntryObject, Format } from '../types/redux'; import type { EntryValue } from '../valueObjects/Entry'; +import type { Formatter } from 'netlify-cms-core'; export const frontmatterFormats = ['yaml-frontmatter', 'toml-frontmatter', 'json-frontmatter']; @@ -38,8 +39,8 @@ export const extensionFormatters = { html: FrontmatterInfer, }; -function formatByName(name: Format, customDelimiter?: Delimiter) { - return { +function formatByName(name: Format, customDelimiter?: Delimiter): Formatter { + const formatters: Record = { yml: yamlFormatter, yaml: yamlFormatter, toml: tomlFormatter, @@ -49,7 +50,11 @@ function formatByName(name: Format, customDelimiter?: Delimiter) { 'toml-frontmatter': frontmatterTOML(customDelimiter), 'yaml-frontmatter': frontmatterYAML(customDelimiter), ...getCustomFormatsFormatters(), - }[name]; + }; + if (name in formatters) { + return formatters[name]; + } + throw new Error(`No formatter available with name: ${name}`); } function frontmatterDelimiterIsList( diff --git a/packages/netlify-cms-core/src/lib/registry.js b/packages/netlify-cms-core/src/lib/registry.js index bdffa4de1339..4bf89256586e 100644 --- a/packages/netlify-cms-core/src/lib/registry.js +++ b/packages/netlify-cms-core/src/lib/registry.js @@ -304,8 +304,13 @@ export function getCustomFormatsExtensions() { }, {}); } +/** @type {() => Record} */ export function getCustomFormatsFormatters() { return Object.entries(registry.formats).reduce(function (acc, [name, { formatter }]) { return { ...acc, [name]: formatter }; }, {}); } + +export function getFormatter(name) { + return registry.formats[name]?.formatter; +} From 1dc43db87936fa480d3650972f2bf0a0882da726 Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Sat, 12 Feb 2022 17:53:11 -0500 Subject: [PATCH 04/14] test: custom formats and register function --- .../src/formats/__tests__/formats.spec.js | 70 +++++++++++++++++++ .../src/lib/__tests__/registry.spec.js | 15 ++++ 2 files changed, 85 insertions(+) create mode 100644 packages/netlify-cms-core/src/formats/__tests__/formats.spec.js diff --git a/packages/netlify-cms-core/src/formats/__tests__/formats.spec.js b/packages/netlify-cms-core/src/formats/__tests__/formats.spec.js new file mode 100644 index 000000000000..74d77dde00aa --- /dev/null +++ b/packages/netlify-cms-core/src/formats/__tests__/formats.spec.js @@ -0,0 +1,70 @@ +import { Map, List, fromJS } from 'immutable'; + +import { extensionFormatters, resolveFormat } from '../formats' +import { registerCustomFormat } from '../../lib/registry'; + +describe('custom formats', () => { + const testEntry = { + collection: 'testCollection', + data: { x: 1 }, + isModification: false, + label: 'testLabel', + mediaFiles: [], + meta: {}, + newRecord: true, + partial: false, + path: 'testPath1', + raw: 'testRaw', + slug: 'testSlug', + author: 'testAuthor', + updatedOn: 'testUpdatedOn' + } + it('resolves builtint formats', () => { + const collection = Map({ + name: 'posts', + }); + expect(resolveFormat(collection, { ...testEntry, path: 'test.yml' })).toEqual(extensionFormatters.yml) + expect(resolveFormat(collection, { ...testEntry, path: 'test.yaml' })).toEqual(extensionFormatters.yml) + expect(resolveFormat(collection, { ...testEntry, path: 'test.toml' })).toEqual(extensionFormatters.toml) + expect(resolveFormat(collection, { ...testEntry, path: 'test.json' })).toEqual(extensionFormatters.json) + expect(resolveFormat(collection, { ...testEntry, path: 'test.md' })).toEqual(extensionFormatters.md) + expect(resolveFormat(collection, { ...testEntry, path: 'test.markdown' })).toEqual(extensionFormatters.markdown) + expect(resolveFormat(collection, { ...testEntry, path: 'test.html' })).toEqual(extensionFormatters.html) + }); + + it('resolves custom format', () => { + registerCustomFormat('txt-querystring', 'txt', { + fromFile: (file) => Object.fromEntries(new URLSearchParams(file)), + toFile: (value) => new URLSearchParams(value).toString(), + }) + + const collection = Map({ + name: 'posts', + format: 'txt-querystring', + }); + + const formatter = resolveFormat(collection, { ...testEntry, path: 'test.txt' }) + + expect(formatter.toFile({ foo: 'bar' })).toEqual('foo=bar') + expect(formatter.fromFile('foo=bar')).toEqual({ foo: 'bar' }) + }); + + it('can override existing formatters', () => { + // simplified version of a more realistic use case: using a different yaml library like js-yaml + // to make netlify-cms play nice with other tools that edit content and spit out yaml + registerCustomFormat('bad-yaml', 'yml', { + fromFile: (file) => Object.fromEntries(file.split('\n').map(line => line.split(': '))), + toFile: (value) => Object.entries(value).map(([k, v]) => `${k}: ${v}`).join('\n'), + }) + + const collection = Map({ + name: 'posts', + format: 'bad-yaml', + }); + + const formatter = resolveFormat(collection, { ...testEntry, path: 'test.txt' }) + + expect(formatter.toFile({ a: 'b', c: 'd' })).toEqual('a: b\nc: d') + expect(formatter.fromFile('a: b\nc: d')).toEqual({ a: 'b', c: 'd' }) + }); +}); diff --git a/packages/netlify-cms-core/src/lib/__tests__/registry.spec.js b/packages/netlify-cms-core/src/lib/__tests__/registry.spec.js index 633025b9d8b7..118e2514bb8a 100644 --- a/packages/netlify-cms-core/src/lib/__tests__/registry.spec.js +++ b/packages/netlify-cms-core/src/lib/__tests__/registry.spec.js @@ -46,6 +46,21 @@ describe('registry', () => { }); }); + describe('registerCustomFormat', () => { + it('can register a custom format', () => { + const { getCustomFormats, registerCustomFormat } = require('../registry'); + + expect(Object.keys(getCustomFormats())).not.toContain('querystring'); + + registerCustomFormat('querystring', 'qs', { + fromFile: content => Object.fromEntries(new URLSearchParams(content)), + toFile: obj => new URLSearchParams(obj).toString(), + }); + + expect(Object.keys(getCustomFormats())).toContain('querystring'); + }); + }); + describe('eventHandlers', () => { const events = [ 'prePublish', From 6d29b239cb36073d4dde8d5bd0d3db87c86eab07 Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Sat, 12 Feb 2022 17:53:27 -0500 Subject: [PATCH 05/14] docs: explain usage and note manual initialization requirement --- website/content/docs/beta-features.md | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/website/content/docs/beta-features.md b/website/content/docs/beta-features.md index d68d552d07f2..e1b5b7bfa342 100644 --- a/website/content/docs/beta-features.md +++ b/website/content/docs/beta-features.md @@ -664,3 +664,31 @@ CMS.registerRemarkPlugin({ settings: { bullet: '-' } }); ``` Note that `netlify-widget-markdown` currently uses `remark@10`, so you should check a plugin's compatibility first. + +## Custom formatters + +To manage content with other file formats than the built in ones, you can register a custom formatter: + +```js +const JSON5 = require('json5'); + +CMS.registerCustomFormat('json5', 'json5', { + fromFile: text => JSON5.parse(text), + toFile: value => JSON5.stringify(value, null, 2), +}); +``` + +Then include `format: json5` in your collection configuration. See the [Collection docs](https://www.netlifycms.org/docs/configuration-options/#collections) for more details. + +You can also override the in-built formatters. For example, to change the YAML serialization method from [`yaml`](https://npmjs.com/package/yaml) to [`js-yaml`](https://npmjs.com/package/js-yaml): + +```js +const jsYaml = require('js-yaml'); + +CMS.registerCustomFormat('yml', 'yml', { + fromFile: text => jsYaml.load(text), + toFile: value => jsYaml.dump(value), +}); +``` + +Note: custom formats must be registered before the CMS is initialized, so enable [manual initialization](#manual-initialization) when using it. From 3c63e9b3c6a82ad9a9f8c9f585442ad6f181193b Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Sat, 12 Feb 2022 18:11:00 -0500 Subject: [PATCH 06/14] fix: remove unused imports --- .../src/formats/__tests__/formats.spec.js | 63 ++++++++++++------- 1 file changed, 40 insertions(+), 23 deletions(-) diff --git a/packages/netlify-cms-core/src/formats/__tests__/formats.spec.js b/packages/netlify-cms-core/src/formats/__tests__/formats.spec.js index 74d77dde00aa..57e6e5f7bd2f 100644 --- a/packages/netlify-cms-core/src/formats/__tests__/formats.spec.js +++ b/packages/netlify-cms-core/src/formats/__tests__/formats.spec.js @@ -1,6 +1,6 @@ -import { Map, List, fromJS } from 'immutable'; +import { Map } from 'immutable'; -import { extensionFormatters, resolveFormat } from '../formats' +import { extensionFormatters, resolveFormat } from '../formats'; import { registerCustomFormat } from '../../lib/registry'; describe('custom formats', () => { @@ -17,54 +17,71 @@ describe('custom formats', () => { raw: 'testRaw', slug: 'testSlug', author: 'testAuthor', - updatedOn: 'testUpdatedOn' - } + updatedOn: 'testUpdatedOn', + }; it('resolves builtint formats', () => { const collection = Map({ name: 'posts', }); - expect(resolveFormat(collection, { ...testEntry, path: 'test.yml' })).toEqual(extensionFormatters.yml) - expect(resolveFormat(collection, { ...testEntry, path: 'test.yaml' })).toEqual(extensionFormatters.yml) - expect(resolveFormat(collection, { ...testEntry, path: 'test.toml' })).toEqual(extensionFormatters.toml) - expect(resolveFormat(collection, { ...testEntry, path: 'test.json' })).toEqual(extensionFormatters.json) - expect(resolveFormat(collection, { ...testEntry, path: 'test.md' })).toEqual(extensionFormatters.md) - expect(resolveFormat(collection, { ...testEntry, path: 'test.markdown' })).toEqual(extensionFormatters.markdown) - expect(resolveFormat(collection, { ...testEntry, path: 'test.html' })).toEqual(extensionFormatters.html) + expect(resolveFormat(collection, { ...testEntry, path: 'test.yml' })).toEqual( + extensionFormatters.yml, + ); + expect(resolveFormat(collection, { ...testEntry, path: 'test.yaml' })).toEqual( + extensionFormatters.yml, + ); + expect(resolveFormat(collection, { ...testEntry, path: 'test.toml' })).toEqual( + extensionFormatters.toml, + ); + expect(resolveFormat(collection, { ...testEntry, path: 'test.json' })).toEqual( + extensionFormatters.json, + ); + expect(resolveFormat(collection, { ...testEntry, path: 'test.md' })).toEqual( + extensionFormatters.md, + ); + expect(resolveFormat(collection, { ...testEntry, path: 'test.markdown' })).toEqual( + extensionFormatters.markdown, + ); + expect(resolveFormat(collection, { ...testEntry, path: 'test.html' })).toEqual( + extensionFormatters.html, + ); }); it('resolves custom format', () => { registerCustomFormat('txt-querystring', 'txt', { - fromFile: (file) => Object.fromEntries(new URLSearchParams(file)), - toFile: (value) => new URLSearchParams(value).toString(), - }) + fromFile: file => Object.fromEntries(new URLSearchParams(file)), + toFile: value => new URLSearchParams(value).toString(), + }); const collection = Map({ name: 'posts', format: 'txt-querystring', }); - const formatter = resolveFormat(collection, { ...testEntry, path: 'test.txt' }) + const formatter = resolveFormat(collection, { ...testEntry, path: 'test.txt' }); - expect(formatter.toFile({ foo: 'bar' })).toEqual('foo=bar') - expect(formatter.fromFile('foo=bar')).toEqual({ foo: 'bar' }) + expect(formatter.toFile({ foo: 'bar' })).toEqual('foo=bar'); + expect(formatter.fromFile('foo=bar')).toEqual({ foo: 'bar' }); }); it('can override existing formatters', () => { // simplified version of a more realistic use case: using a different yaml library like js-yaml // to make netlify-cms play nice with other tools that edit content and spit out yaml registerCustomFormat('bad-yaml', 'yml', { - fromFile: (file) => Object.fromEntries(file.split('\n').map(line => line.split(': '))), - toFile: (value) => Object.entries(value).map(([k, v]) => `${k}: ${v}`).join('\n'), - }) + fromFile: file => Object.fromEntries(file.split('\n').map(line => line.split(': '))), + toFile: value => + Object.entries(value) + .map(([k, v]) => `${k}: ${v}`) + .join('\n'), + }); const collection = Map({ name: 'posts', format: 'bad-yaml', }); - const formatter = resolveFormat(collection, { ...testEntry, path: 'test.txt' }) + const formatter = resolveFormat(collection, { ...testEntry, path: 'test.txt' }); - expect(formatter.toFile({ a: 'b', c: 'd' })).toEqual('a: b\nc: d') - expect(formatter.fromFile('a: b\nc: d')).toEqual({ a: 'b', c: 'd' }) + expect(formatter.toFile({ a: 'b', c: 'd' })).toEqual('a: b\nc: d'); + expect(formatter.fromFile('a: b\nc: d')).toEqual({ a: 'b', c: 'd' }); }); }); From 9acee6a2f1917003c86312021065a812fb9cc1ff Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Sat, 23 Apr 2022 11:23:39 -0400 Subject: [PATCH 07/14] use default extension --- packages/netlify-cms-core/src/reducers/collections.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/netlify-cms-core/src/reducers/collections.ts b/packages/netlify-cms-core/src/reducers/collections.ts index 19c1e1c170f1..5a9d3408c07a 100644 --- a/packages/netlify-cms-core/src/reducers/collections.ts +++ b/packages/netlify-cms-core/src/reducers/collections.ts @@ -48,7 +48,8 @@ const selectors = { entryExtension(collection: Collection) { return ( collection.get('extension') || - get(getFormatExtensions(), collection.get('format') || 'frontmatter') + get(getFormatExtensions(), collection.get('format') || 'frontmatter') || + get(getFormatExtensions(), 'frontmatter') ).replace(/^\./, ''); }, fields(collection: Collection) { From 0ad477a51b93dac8c621f9c04415d3a181e2bf6c Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Sat, 23 Apr 2022 11:24:47 -0400 Subject: [PATCH 08/14] remove manual init note --- website/content/docs/beta-features.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/website/content/docs/beta-features.md b/website/content/docs/beta-features.md index 738f3fb6e436..1bf3845f79e4 100644 --- a/website/content/docs/beta-features.md +++ b/website/content/docs/beta-features.md @@ -709,5 +709,3 @@ CMS.registerCustomFormat('yml', 'yml', { toFile: value => jsYaml.dump(value), }); ``` - -Note: custom formats must be registered before the CMS is initialized, so enable [manual initialization](#manual-initialization) when using it. From 2f95d52cec5900572918ec801cbf7da8a769dd89 Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Thu, 30 Jun 2022 09:54:31 -0400 Subject: [PATCH 09/14] PR comments --- dev-test/index.html | 9 --------- .../netlify-cms-core/src/reducers/collections.ts | 12 ++++++++---- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/dev-test/index.html b/dev-test/index.html index ff473a861a16..6cbf85d7c269 100644 --- a/dev-test/index.html +++ b/dev-test/index.html @@ -246,15 +246,6 @@ } }); - const PreWidget = createClass({ - render: function() { - const { value, fieldsMetaData } = this.props; - return value ? h('pre', { style: style }, - value.toJS() - ) : null; - } - }); - CMS.registerCustomFormat('custom', 'json', { fromFile(content) { const {__ns, ...others} = JSON.parse(content); diff --git a/packages/netlify-cms-core/src/reducers/collections.ts b/packages/netlify-cms-core/src/reducers/collections.ts index 5a9d3408c07a..9a1fc05430c1 100644 --- a/packages/netlify-cms-core/src/reducers/collections.ts +++ b/packages/netlify-cms-core/src/reducers/collections.ts @@ -46,11 +46,15 @@ function collections(state = defaultState, action: ConfigAction) { const selectors = { [FOLDER]: { entryExtension(collection: Collection) { - return ( + const ext = ( collection.get('extension') || - get(getFormatExtensions(), collection.get('format') || 'frontmatter') || - get(getFormatExtensions(), 'frontmatter') - ).replace(/^\./, ''); + get(getFormatExtensions(), collection.get('format') || 'frontmatter') + ) + if (!ext) { + throw new Error(`No extension found for format ${collection.get('format')}`) + } + + return ext.replace(/^\./, ''); }, fields(collection: Collection) { return collection.get('fields'); From aea2bed9427fe213a5c39b2b40fed8766c5d145d Mon Sep 17 00:00:00 2001 From: mmkal Date: Sun, 17 Jul 2022 11:52:29 -0400 Subject: [PATCH 10/14] fix: prettier --- packages/netlify-cms-core/src/reducers/collections.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/netlify-cms-core/src/reducers/collections.ts b/packages/netlify-cms-core/src/reducers/collections.ts index 9a1fc05430c1..1fec8b07725a 100644 --- a/packages/netlify-cms-core/src/reducers/collections.ts +++ b/packages/netlify-cms-core/src/reducers/collections.ts @@ -46,12 +46,11 @@ function collections(state = defaultState, action: ConfigAction) { const selectors = { [FOLDER]: { entryExtension(collection: Collection) { - const ext = ( + const ext = collection.get('extension') || - get(getFormatExtensions(), collection.get('format') || 'frontmatter') - ) + get(getFormatExtensions(), collection.get('format') || 'frontmatter'); if (!ext) { - throw new Error(`No extension found for format ${collection.get('format')}`) + throw new Error(`No extension found for format ${collection.get('format')}`); } return ext.replace(/^\./, ''); From a0c8efefe5a3efce7445cb464fddb124eb8fa8b1 Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Tue, 16 Aug 2022 16:11:02 -0400 Subject: [PATCH 11/14] revert unnecessary changes? --- dev-test/config.yml | 47 +++++++++++---------------------------------- dev-test/index.html | 23 ---------------------- 2 files changed, 11 insertions(+), 59 deletions(-) diff --git a/dev-test/config.yml b/dev-test/config.yml index 34d1a97cd962..91999b721b3d 100644 --- a/dev-test/config.yml +++ b/dev-test/config.yml @@ -7,27 +7,6 @@ publish_mode: editorial_workflow media_folder: assets/uploads collections: # A list of collections the CMS should be able to edit - - name: 'translations' - label: 'Translations' - folder: '_translations' - i18n: - structure: 'multiple_folders' - format: custom - identifier_field: namespace - fields: - - label: Namespace - name: namespace - widget: string - i18n: false - - label: 'Items' - label_singular: 'Item' - name: 'list' - widget: list - fields: - - name: key - widget: string - - name: value - widget: string - name: 'posts' # Used in routes, ie.: /admin/collections/:slug/edit label: 'Posts' # Used in the UI label_singular: 'Post' # Used in the UI, ie: "New Post" @@ -146,14 +125,6 @@ collections: # A list of collections the CMS should be able to edit - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - { label: 'Date', name: 'date', widget: 'date' } - - { label: 'Color', name: 'color', widget: 'color' } - - { - label: 'Color string editable and alpha enabled', - name: 'colorEditable', - widget: 'color', - enableAlpha: true, - allowInput: true, - } - { label: 'Image', name: 'image', widget: 'image' } - { label: 'File', name: 'file', widget: 'file' } - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } @@ -164,13 +135,6 @@ collections: # A list of collections the CMS should be able to edit options: ['a', 'b', 'c'], multiple: true, } - - { - label: 'Select numeric', - name: 'select_numeric', - widget: 'select', - options: - [{ label: 'One', value: 1 }, { label: 'Two', value: 2 }, { label: 'Three', value: 3 }], - } - { label: 'Hidden', name: 'hidden', widget: 'hidden', default: 'hidden' } - label: 'Object' name: 'object' @@ -287,3 +251,14 @@ collections: # A list of collections the CMS should be able to edit - { label: 'Date', name: 'date', widget: 'date' } - { label: 'Image', name: 'image', widget: 'image' } - { label: 'File', name: 'file', widget: 'file' } + - name: pages # a nested collection + label: Pages + label_singular: 'Page' + folder: _pages + create: true + nested: { depth: 100 } + fields: + - label: Title + name: title + widget: string + meta: { path: { widget: string, label: 'Path', index_file: 'index' } } diff --git a/dev-test/index.html b/dev-test/index.html index 6cbf85d7c269..cde4d1d4fb7a 100644 --- a/dev-test/index.html +++ b/dev-test/index.html @@ -6,11 +6,6 @@ Netlify CMS Development Test - From b7886b84ada2cbc5c1ca21e8faac761596bc86ba Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Tue, 16 Aug 2022 16:14:33 -0400 Subject: [PATCH 12/14] chore: more revert? --- dev-test/config.yml | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/dev-test/config.yml b/dev-test/config.yml index 91999b721b3d..8a4836a4a7e7 100644 --- a/dev-test/config.yml +++ b/dev-test/config.yml @@ -125,6 +125,14 @@ collections: # A list of collections the CMS should be able to edit - { label: 'Markdown', name: 'markdown', widget: 'markdown' } - { label: 'Datetime', name: 'datetime', widget: 'datetime' } - { label: 'Date', name: 'date', widget: 'date' } + - { label: 'Color', name: 'color', widget: 'color' } + - { + label: 'Color string editable and alpha enabled', + name: 'colorEditable', + widget: 'color', + enableAlpha: true, + allowInput: true, + } - { label: 'Image', name: 'image', widget: 'image' } - { label: 'File', name: 'file', widget: 'file' } - { label: 'Select', name: 'select', widget: 'select', options: ['a', 'b', 'c'] } @@ -135,6 +143,13 @@ collections: # A list of collections the CMS should be able to edit options: ['a', 'b', 'c'], multiple: true, } + - { + label: 'Select numeric', + name: 'select_numeric', + widget: 'select', + options: + [{ label: 'One', value: 1 }, { label: 'Two', value: 2 }, { label: 'Three', value: 3 }], + } - { label: 'Hidden', name: 'hidden', widget: 'hidden', default: 'hidden' } - label: 'Object' name: 'object' @@ -250,15 +265,4 @@ collections: # A list of collections the CMS should be able to edit fields: - { label: 'Date', name: 'date', widget: 'date' } - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } - - name: pages # a nested collection - label: Pages - label_singular: 'Page' - folder: _pages - create: true - nested: { depth: 100 } - fields: - - label: Title - name: title - widget: string - meta: { path: { widget: string, label: 'Path', index_file: 'index' } } + - { label: 'File', name: 'file', widget: 'file' } \ No newline at end of file From 8e8a2489ff9a94c3926363eab4451d6e078d10e1 Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Tue, 16 Aug 2022 17:06:32 -0400 Subject: [PATCH 13/14] chore: newline --- dev-test/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-test/config.yml b/dev-test/config.yml index 8a4836a4a7e7..2ffe5041ddb5 100644 --- a/dev-test/config.yml +++ b/dev-test/config.yml @@ -265,4 +265,4 @@ collections: # A list of collections the CMS should be able to edit fields: - { label: 'Date', name: 'date', widget: 'date' } - { label: 'Image', name: 'image', widget: 'image' } - - { label: 'File', name: 'file', widget: 'file' } \ No newline at end of file + - { label: 'File', name: 'file', widget: 'file' } From bd162e405321d10d0d49d568f2d5c8cad22825be Mon Sep 17 00:00:00 2001 From: Misha Kaletsky Date: Wed, 23 Aug 2023 13:39:55 -0400 Subject: [PATCH 14/14] chore: update import --- packages/decap-cms-core/src/formats/formats.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/decap-cms-core/src/formats/formats.ts b/packages/decap-cms-core/src/formats/formats.ts index dfeb3280fde0..6e79c5e5035b 100644 --- a/packages/decap-cms-core/src/formats/formats.ts +++ b/packages/decap-cms-core/src/formats/formats.ts @@ -10,7 +10,7 @@ import { getCustomFormatsExtensions, getCustomFormatsFormatters } from '../lib/r import type { Delimiter } from './frontmatter'; import type { Collection, EntryObject, Format } from '../types/redux'; import type { EntryValue } from '../valueObjects/Entry'; -import type { Formatter } from 'netlify-cms-core'; +import type { Formatter } from 'decap-cms-core'; export const frontmatterFormats = ['yaml-frontmatter', 'toml-frontmatter', 'json-frontmatter'];