From 1fa108ee67b7e992a4d2a61cde13df7917e103be Mon Sep 17 00:00:00 2001 From: KoljaTM Date: Sun, 25 Oct 2020 16:29:59 +0100 Subject: [PATCH] feat: Support filters for template strings #3677 (#4396) --- .../src/__tests__/stringTemplate.spec.js | 22 ++++++++++ .../src/stringTemplate.ts | 41 +++++++++++++++++-- website/content/docs/beta-features.md | 21 ++++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/packages/netlify-cms-lib-widgets/src/__tests__/stringTemplate.spec.js b/packages/netlify-cms-lib-widgets/src/__tests__/stringTemplate.spec.js index f96d09e1..350d3232 100644 --- a/packages/netlify-cms-lib-widgets/src/__tests__/stringTemplate.spec.js +++ b/packages/netlify-cms-lib-widgets/src/__tests__/stringTemplate.spec.js @@ -107,6 +107,28 @@ describe('stringTemplate', () => { compileStringTemplate('{{slug}}', date, 'slug', fromJS({}), value => value.toUpperCase()), ).toBe('SLUG'); }); + + it('return apply filter to values', () => { + expect( + compileStringTemplate( + '{{slug | upper}}-{{title | lower}}-{{year}}', + date, + 'backendSlug', + fromJS({ slug: 'entrySlug', title: 'Title', date }), + ), + ).toBe('BACKENDSLUG-title-2020'); + }); + + it('return apply filter to date field', () => { + expect( + compileStringTemplate( + "{{slug | upper}}-{{title | lower}}-{{published | date('MM-DD')}}-{{year}}", + date, + 'backendSlug', + fromJS({ slug: 'entrySlug', title: 'Title', published: date, date }), + ), + ).toBe('BACKENDSLUG-title-01-02-2020'); + }); }); describe('expandPath', () => { diff --git a/packages/netlify-cms-lib-widgets/src/stringTemplate.ts b/packages/netlify-cms-lib-widgets/src/stringTemplate.ts index 392f1451..ad485f28 100644 --- a/packages/netlify-cms-lib-widgets/src/stringTemplate.ts +++ b/packages/netlify-cms-lib-widgets/src/stringTemplate.ts @@ -1,11 +1,24 @@ import moment from 'moment'; import { Map } from 'immutable'; -import { basename, extname, dirname } from 'path'; +import { basename, dirname, extname } from 'path'; import { get, trimEnd } from 'lodash'; +const filters = [ + { pattern: /^upper$/, transform: (str: string) => str.toUpperCase() }, + { + pattern: /^lower$/, + transform: (str: string) => str.toLowerCase(), + }, + { + pattern: /^date\('(.+)'\)$/, + transform: (str: string, match: RegExpMatchArray) => moment(str).format(match[1]), + }, +]; + const FIELD_PREFIX = 'fields.'; -const templateContentPattern = '[^}{]+'; -const templateVariablePattern = `{{(${templateContentPattern})}}`; +const templateContentPattern = '([^}{|]+)'; +const filterPattern = '( \\| ([^}{]+))?'; +const templateVariablePattern = `{{${templateContentPattern}${filterPattern}}}`; // prepends a Zero if the date has only 1 digit function formatDate(date: number) { @@ -110,6 +123,21 @@ function getExplicitFieldReplacement(key: string, data: Map) { return value; } +function getFilterFunction(filterStr: string) { + if (filterStr) { + let match: RegExpMatchArray | null = null; + const filter = filters.find(filter => { + match = filterStr.match(filter.pattern); + return !!match; + }); + + if (filter) { + return (str: string) => filter.transform(str, match as RegExpMatchArray); + } + } + return null; +} + export function compileStringTemplate( template: string, date: Date | undefined | null, @@ -125,7 +153,7 @@ export function compileStringTemplate( const compiledString = template.replace( RegExp(templateVariablePattern, 'g'), - (_, key: string) => { + (_full, key: string, _part, filter: string) => { let replacement; const explicitFieldReplacement = getExplicitFieldReplacement(key, data); @@ -144,6 +172,11 @@ export function compileStringTemplate( if (processor) { return processor(replacement); + } else { + const filterFunction = getFilterFunction(filter); + if (filterFunction) { + replacement = filterFunction(replacement); + } } return replacement; diff --git a/website/content/docs/beta-features.md b/website/content/docs/beta-features.md index f1c44004..0a4a5b54 100644 --- a/website/content/docs/beta-features.md +++ b/website/content/docs/beta-features.md @@ -493,6 +493,27 @@ Example config: max_file_size: 512000 # in bytes, only for default media library ``` +## Summary string template transformations + +You can apply transformations on fields in a summary string template using filter notation syntax. + +Example config: + +```yaml +collections: + - name: 'posts' + label: 'Posts' + folder: '_posts' + summary: "{{title | upper}} - {{date | date('YYYY-MM-DD')}}" + fields: + - { label: 'Title', name: 'title', widget: 'string' } + - { label: 'Publish Date', name: 'date', widget: 'datetime' } +``` + +The above config will transform the title field to uppercase and format the date field using `YYYY-MM-DD` format. +Available transformations are `upper`, `lower` and `date('')` + + ## Registering to CMS Events You can execute a function when a specific CMS event occurs.