From 47e3c7148935091b21b77c8c42a2a578ef2ccfba Mon Sep 17 00:00:00 2001 From: Kirk Swenson Date: Tue, 20 Feb 2024 13:42:31 -0800 Subject: [PATCH] fix: create a copy for CODAP v3 --- readme.md | 2 ++ src/code/client.ts | 2 +- src/code/providers/provider-interface.ts | 35 ++++++++++++++++-------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/readme.md b/readme.md index a28dc2c2..49b6befd 100644 --- a/readme.md +++ b/readme.md @@ -189,6 +189,8 @@ export interface CFMAppOptions { // true if the application sets the page title // false (default) if CFM sets page title from document name appSetsWindowTitle?: boolean + // true if the content stored to file/disk should be wrapped with CFM metadata + // false if the content should be unwrapped before storing to file/disk wrapFileContent?: boolean mimeType?: string // note different capitalization from CFMBaseProviderOptions diff --git a/src/code/client.ts b/src/code/client.ts index 8945ee27..f066a034 100644 --- a/src/code/client.ts +++ b/src/code/client.ts @@ -142,7 +142,7 @@ class CloudFileManagerClient { this.appOptions = appOptions if (this.appOptions.wrapFileContent == null) { this.appOptions.wrapFileContent = true } CloudContent.wrapFileContent = this.appOptions.wrapFileContent - if (this.appOptions.isClientContent) cloudContentFactory.isClientContent = this.appOptions.isClientContent + if (this.appOptions.isClientContent) CloudContent.isClientContent = this.appOptions.isClientContent type ProviderClass = any const allProviders: Record = {} diff --git a/src/code/providers/provider-interface.ts b/src/code/providers/provider-interface.ts index a9875993..00e0eb4f 100644 --- a/src/code/providers/provider-interface.ts +++ b/src/code/providers/provider-interface.ts @@ -166,14 +166,8 @@ interface IEnvelopeMetaData { // singleton that can create CloudContent wrapped with global options class CloudContentFactory { - // For backward compatibility, by default we assume that a top-level `metadata` - // property indicates an unwrapped client document (e.g. CODAP v2). Clients can - // override this assumption with the `isClientContent` configuration option. - isClientContent = (content: unknown) => { - return typeof content === "object" && "metadata" in content && !!content.metadata - } - envelopeMetadata: IEnvelopeMetaData + constructor() { this.envelopeMetadata = { // replaced by version number at build time @@ -215,7 +209,7 @@ class CloudContentFactory { } } // If looks like client content, then it's neither wrapped nor pre-CFM. - if (this.isClientContent(content)) { + if (CloudContent.isClientContent(content)) { return result } if ( @@ -237,7 +231,7 @@ class CloudContentFactory { // noop, just checking if it's json or plain text } } - if ((typeof content === "object") && (content?.content != null)) { + if ((typeof content === "object") && (content?.content != null) && !CloudContent.isClientContent(content)) { return content } else { return {content} @@ -251,8 +245,18 @@ export interface CloudContentFormat { } class CloudContent { + // Client content is always wrapped by the CFM while it is being handled internally. + // This setting controls whether content is stored to file/disk in its wrapped form + // or whether it should be unwrapped before serializing to file/disk. static wrapFileContent: boolean = true + // For backward compatibility, by default we assume that a top-level `metadata` + // property indicates an unwrapped client document (e.g. CODAP v2). Clients can + // override this assumption with the `isClientContent` configuration option. + static isClientContent = (content: unknown) => { + return typeof content === "object" && "metadata" in content && !!content.metadata + } + // TODO: These should probably be private, but there is some refactoring // that has to happen to make this possible cfmVersion?: string @@ -264,7 +268,8 @@ class CloudContent { this.contentFormat = contentFormat } - // getContent and getContentAsJSON return the file content as stored on disk + // getContent and getContentAsJSON return the file content as stored on disk. + // They are expected to be called on internally wrapped content. getContent() { return CloudContent.wrapFileContent ? this.content @@ -275,9 +280,15 @@ class CloudContent { return JSON.stringify(this.getContent()) } - // returns the client-visible content (excluding wrapper for wrapped clients) + // Returns the client-visible content (excluding wrapper). + // Note that this can be called with wrapped or unwrapped content independent of the `wrapFileContent` + // setting, because CFM wraps content internally, so we need to inspect the content. getClientContent() { - return CloudContent.wrapFileContent + // if we can specifically identify client content, then return it + if (CloudContent.isClientContent(this.content?.content)) return this.content.content + if (CloudContent.isClientContent(this.content)) return this.content + // otherwise, assume that a nested `content` property means we are wrapped + return this.content?.content ? this.content.content : this.content }