From 28372ff788fb6291f54bfb36f2a3f7bfcdfd8f72 Mon Sep 17 00:00:00 2001 From: Felix Gnass Date: Thu, 13 Feb 2025 08:45:42 +0100 Subject: [PATCH 1/5] fix(7401): move stega.ts to core package --- .../components/Editor/EditorPreviewPane/EditorPreviewPane.js | 2 +- .../src => decap-cms-core/src/lib}/stega.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename packages/{decap-cms-lib-util/src => decap-cms-core/src/lib}/stega.ts (98%) diff --git a/packages/decap-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js b/packages/decap-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js index 39424176ac95..3cc025fd705d 100644 --- a/packages/decap-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js +++ b/packages/decap-cms-core/src/components/Editor/EditorPreviewPane/EditorPreviewPane.js @@ -6,8 +6,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import Frame, { FrameContextConsumer } from 'react-frame-component'; import { lengths } from 'decap-cms-ui-default'; import { connect } from 'react-redux'; -import { encodeEntry } from 'decap-cms-lib-util/src/stega'; +import { encodeEntry } from '../../../lib/stega'; import { resolveWidget, getPreviewTemplate, diff --git a/packages/decap-cms-lib-util/src/stega.ts b/packages/decap-cms-core/src/lib/stega.ts similarity index 98% rename from packages/decap-cms-lib-util/src/stega.ts rename to packages/decap-cms-core/src/lib/stega.ts index 099b86e6db03..328a579a4bc8 100644 --- a/packages/decap-cms-lib-util/src/stega.ts +++ b/packages/decap-cms-core/src/lib/stega.ts @@ -1,6 +1,5 @@ import { vercelStegaEncode } from '@vercel/stega'; - -import { isImmutableMap, isImmutableList } from './types'; +import { isImmutableMap, isImmutableList } from 'decap-cms-lib-util/src/types'; import type { Map as ImmutableMap, List } from 'immutable'; import type { CmsField } from 'decap-cms-core'; From ae9bfd9b6b77a4803fe7325d4f9e8aef702374db Mon Sep 17 00:00:00 2001 From: Felix Gnass Date: Thu, 13 Feb 2025 08:46:23 +0100 Subject: [PATCH 2/5] fix: add visualEditing prop to types --- packages/decap-cms-core/index.d.ts | 1 + packages/decap-cms-core/src/types/redux.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/decap-cms-core/index.d.ts b/packages/decap-cms-core/index.d.ts index 9eb5e7f9855e..9f7600ff96c6 100644 --- a/packages/decap-cms-core/index.d.ts +++ b/packages/decap-cms-core/index.d.ts @@ -306,6 +306,7 @@ declare module 'decap-cms-core' { hide?: boolean; editor?: { preview?: boolean; + visualEditing?: boolean; }; publish?: boolean; nested?: { diff --git a/packages/decap-cms-core/src/types/redux.ts b/packages/decap-cms-core/src/types/redux.ts index b69a82311532..700cf2a1d2f0 100644 --- a/packages/decap-cms-core/src/types/redux.ts +++ b/packages/decap-cms-core/src/types/redux.ts @@ -322,6 +322,7 @@ export interface CmsCollection { delete?: boolean; editor?: { preview?: boolean; + visualEditing?: boolean; }; publish?: boolean; nested?: { From 716280f54b04f90faa3c14b493cef334dba1e14d Mon Sep 17 00:00:00 2001 From: Felix Gnass Date: Thu, 13 Feb 2025 08:46:40 +0100 Subject: [PATCH 3/5] fix: allow tests to run after build --- jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest.config.js b/jest.config.js index 74e19e1458c6..ea4a2343b479 100644 --- a/jest.config.js +++ b/jest.config.js @@ -9,6 +9,7 @@ module.exports = { 'decap-cms-widget-object': '/packages/decap-cms-widget-object/src/index.js', '\\.(css|less)$': '/__mocks__/styleMock.js', }, + modulePathIgnorePatterns: ['.nx', 'dist'], snapshotSerializers: ['@emotion/jest/serializer'], transformIgnorePatterns: [ 'node_modules/(?!copy-text-to-clipboard|clean-stack|escape-string-regexp)', From af01d1b6c925d8fb8063e5210b64687415e814f6 Mon Sep 17 00:00:00 2001 From: Felix Gnass Date: Thu, 13 Feb 2025 21:17:31 +0100 Subject: [PATCH 4/5] fix: move type guards into core too --- packages/decap-cms-core/src/lib/stega.ts | 3 ++- packages/decap-cms-core/src/types/immutable.ts | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/decap-cms-core/src/lib/stega.ts b/packages/decap-cms-core/src/lib/stega.ts index 328a579a4bc8..d47e2c338ced 100644 --- a/packages/decap-cms-core/src/lib/stega.ts +++ b/packages/decap-cms-core/src/lib/stega.ts @@ -1,5 +1,6 @@ import { vercelStegaEncode } from '@vercel/stega'; -import { isImmutableMap, isImmutableList } from 'decap-cms-lib-util/src/types'; + +import { isImmutableMap, isImmutableList } from '../types/immutable'; import type { Map as ImmutableMap, List } from 'immutable'; import type { CmsField } from 'decap-cms-core'; diff --git a/packages/decap-cms-core/src/types/immutable.ts b/packages/decap-cms-core/src/types/immutable.ts index 0afa58cdf915..3ab5fb5f1e00 100644 --- a/packages/decap-cms-core/src/types/immutable.ts +++ b/packages/decap-cms-core/src/types/immutable.ts @@ -1,3 +1,13 @@ +import { Map as ImmutableMap, List } from 'immutable'; + +export function isImmutableMap(value: unknown): value is ImmutableMap { + return ImmutableMap.isMap(value); +} + +export function isImmutableList(value: unknown): value is List { + return List.isList(value); +} + export interface StaticallyTypedRecord { get(key: K, defaultValue?: T[K]): T[K]; set(key: K, value: V): StaticallyTypedRecord & T; From 3131bc6931fb6006c54b4360fbc40c90de00f2e8 Mon Sep 17 00:00:00 2001 From: Felix Gnass Date: Fri, 21 Feb 2025 12:23:24 +0100 Subject: [PATCH 5/5] feat: allow fields to opt out of visual editing --- packages/decap-cms-core/index.d.ts | 1 + packages/decap-cms-core/src/lib/stega.ts | 27 +++++++++++++++------- packages/decap-cms-core/src/types/redux.ts | 1 + 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/decap-cms-core/index.d.ts b/packages/decap-cms-core/index.d.ts index 9f7600ff96c6..a2fd54e14fed 100644 --- a/packages/decap-cms-core/index.d.ts +++ b/packages/decap-cms-core/index.d.ts @@ -233,6 +233,7 @@ declare module 'decap-cms-core' { // This is the default widget, so declaring its type is optional. widget?: 'string' | 'text'; default?: string; + visualEditing?: boolean; } export interface CmsFieldMeta { diff --git a/packages/decap-cms-core/src/lib/stega.ts b/packages/decap-cms-core/src/lib/stega.ts index d47e2c338ced..0cbeaaf63de6 100644 --- a/packages/decap-cms-core/src/lib/stega.ts +++ b/packages/decap-cms-core/src/lib/stega.ts @@ -38,14 +38,20 @@ function getNestedFields(f?: CmsField): CmsField[] { * For markdown fields, encode each paragraph separately */ function encodeString(value: string, { fields, path }: EncodeContext): string { - const stega = vercelStegaEncode({ decap: path }); - const isMarkdown = fields[0]?.widget === 'markdown'; - - if (isMarkdown && value.includes('\n\n')) { + const [field] = fields; + if (!field) return value; + const { widget } = field; + if (widget === 'string' || widget === 'text') { + if ('visualEditing' in field && field.visualEditing === false) return value; + const stega = vercelStegaEncode({ decap: path }); + return value + stega; + } + if (widget === 'markdown') { + const stega = vercelStegaEncode({ decap: path }); const blocks = value.split(/(\n\n+)/); return blocks.map(block => (block.trim() ? block + stega : block)).join(''); } - return value + stega; + return value; } /** @@ -102,16 +108,21 @@ function encodeMap( return newMap; } +/** + * Cache for encoded values to prevent re-encoding unchanged values + * across keystrokes. The cache is keyed by path. + */ +const encodingCache = new Map(); + /** * Main entry point for encoding steganographic data into entry values * Uses a visitor pattern with caching to handle recursive structures */ export function encodeEntry(value: unknown, fields: List>) { const plainFields = fields.toJS() as CmsField[]; - const cache = new Map(); function visit(value: unknown, fields: CmsField[], path = '') { - const cached = cache.get(path); + const cached = encodingCache.get(path); if (cached === value) return value; const ctx: EncodeContext = { fields, path, visit }; @@ -126,7 +137,7 @@ export function encodeEntry(value: unknown, fields: List