sdk: harden goView import (iframe/video/image)
This commit is contained in:
parent
c574d4e323
commit
d00544b0a7
@ -1,13 +1,16 @@
|
|||||||
import type { Screen } from './schema';
|
import type { Screen } from './schema';
|
||||||
|
import { convertGoViewProjectToScreen } from './goview/convert';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* goView JSON converter (stub).
|
* goView JSON converter.
|
||||||
*
|
*
|
||||||
* The legacy goView format isn't implemented yet; this is a placeholder so we can
|
* We keep this permissive because goView exports / storage snapshots vary across
|
||||||
* start wiring UI + migration flows without committing to the full mapping.
|
* versions and forks. The heavy lifting lives in `goview/convert.ts`.
|
||||||
*/
|
*/
|
||||||
export function convertGoViewJSONToScreen(input: unknown): Screen {
|
export function convertGoViewJSONToScreen(input: unknown): Screen {
|
||||||
// keep reference to avoid unused-vars lint until implemented
|
if (!input || typeof input !== 'object') {
|
||||||
void input;
|
throw new Error('convertGoViewJSONToScreen: expected object');
|
||||||
throw new Error('convertGoViewJSONToScreen: not implemented yet');
|
}
|
||||||
|
|
||||||
|
return convertGoViewProjectToScreen(input as unknown as object);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,13 +85,40 @@ function isVideo(c: GoViewComponentLike): boolean {
|
|||||||
return k.includes('mp4') || k.includes('media') || k.includes('player');
|
return k.includes('mp4') || k.includes('media') || k.includes('player');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pick<T>(...values: Array<T | undefined | null>): T | undefined {
|
||||||
|
for (const v of values) {
|
||||||
|
if (v !== undefined && v !== null) return v as T;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function convertGoViewProjectToScreen(input: GoViewProjectLike | GoViewStorageLike): Screen {
|
export function convertGoViewProjectToScreen(input: GoViewProjectLike | GoViewStorageLike): Screen {
|
||||||
const editCanvasConfig = (input as GoViewStorageLike).editCanvasConfig;
|
// goView exports vary a lot; attempt a few common nesting shapes.
|
||||||
|
const root = input as unknown as Record<string, unknown>;
|
||||||
|
const data = (root.data as Record<string, unknown> | undefined) ?? undefined;
|
||||||
|
const state = (root.state as Record<string, unknown> | undefined) ?? undefined;
|
||||||
|
const project = (root.project as Record<string, unknown> | undefined) ?? undefined;
|
||||||
|
|
||||||
|
const editCanvasConfig = pick<GoViewEditCanvasConfigLike>(
|
||||||
|
(input as GoViewStorageLike).editCanvasConfig,
|
||||||
|
data?.editCanvasConfig as GoViewEditCanvasConfigLike | undefined,
|
||||||
|
state?.editCanvasConfig as GoViewEditCanvasConfigLike | undefined,
|
||||||
|
project?.editCanvasConfig as GoViewEditCanvasConfigLike | undefined,
|
||||||
|
);
|
||||||
|
|
||||||
const width =
|
const width =
|
||||||
editCanvasConfig?.width ?? (input as GoViewProjectLike).canvas?.width ?? (input as GoViewProjectLike).width ?? 1920;
|
editCanvasConfig?.width ??
|
||||||
|
(input as GoViewProjectLike).canvas?.width ??
|
||||||
|
(input as GoViewProjectLike).width ??
|
||||||
|
(data?.width as number | undefined) ??
|
||||||
|
1920;
|
||||||
|
|
||||||
const height =
|
const height =
|
||||||
editCanvasConfig?.height ?? (input as GoViewProjectLike).canvas?.height ?? (input as GoViewProjectLike).height ?? 1080;
|
editCanvasConfig?.height ??
|
||||||
|
(input as GoViewProjectLike).canvas?.height ??
|
||||||
|
(input as GoViewProjectLike).height ??
|
||||||
|
(data?.height as number | undefined) ??
|
||||||
|
1080;
|
||||||
|
|
||||||
const name = editCanvasConfig?.projectName ?? 'Imported Project';
|
const name = editCanvasConfig?.projectName ?? 'Imported Project';
|
||||||
const background = editCanvasConfig?.background;
|
const background = editCanvasConfig?.background;
|
||||||
@ -105,7 +132,13 @@ export function convertGoViewProjectToScreen(input: GoViewProjectLike | GoViewSt
|
|||||||
nodes: [],
|
nodes: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const componentList = (input as GoViewStorageLike).componentList ?? (input as GoViewProjectLike).componentList ?? [];
|
const componentList =
|
||||||
|
(input as GoViewStorageLike).componentList ??
|
||||||
|
(input as GoViewProjectLike).componentList ??
|
||||||
|
(data?.componentList as GoViewComponentLike[] | undefined) ??
|
||||||
|
(state?.componentList as GoViewComponentLike[] | undefined) ??
|
||||||
|
(project?.componentList as GoViewComponentLike[] | undefined) ??
|
||||||
|
[];
|
||||||
|
|
||||||
const nodes: Array<TextWidgetNode | ImageWidgetNode | IframeWidgetNode | VideoWidgetNode> = [];
|
const nodes: Array<TextWidgetNode | ImageWidgetNode | IframeWidgetNode | VideoWidgetNode> = [];
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import type { IframeWidgetNode } from '../schema';
|
|||||||
* Keep it permissive and normalize the common fields.
|
* Keep it permissive and normalize the common fields.
|
||||||
*/
|
*/
|
||||||
export interface GoViewIframeOption {
|
export interface GoViewIframeOption {
|
||||||
dataset?: string;
|
dataset?: unknown;
|
||||||
src?: string;
|
src?: unknown;
|
||||||
url?: string;
|
url?: unknown;
|
||||||
borderRadius?: number;
|
borderRadius?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,8 +16,23 @@ export interface GoViewIframeOption {
|
|||||||
*/
|
*/
|
||||||
export type LegacyIframeOption = GoViewIframeOption;
|
export type LegacyIframeOption = GoViewIframeOption;
|
||||||
|
|
||||||
|
function asString(v: unknown): string {
|
||||||
|
if (typeof v === 'string') return v;
|
||||||
|
if (!v) return '';
|
||||||
|
|
||||||
|
// Some goView widgets store data as { value: '...' } or { url: '...' }.
|
||||||
|
if (typeof v === 'object') {
|
||||||
|
const obj = v as Record<string, unknown>;
|
||||||
|
if (typeof obj.value === 'string') return obj.value;
|
||||||
|
if (typeof obj.url === 'string') return obj.url;
|
||||||
|
if (typeof obj.src === 'string') return obj.src;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
function pickSrc(option: GoViewIframeOption): string {
|
function pickSrc(option: GoViewIframeOption): string {
|
||||||
return option.dataset ?? option.src ?? option.url ?? '';
|
return asString(option.dataset) || asString(option.src) || asString(option.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertGoViewIframeOptionToNodeProps(option: GoViewIframeOption): IframeWidgetNode['props'] {
|
export function convertGoViewIframeOptionToNodeProps(option: GoViewIframeOption): IframeWidgetNode['props'] {
|
||||||
|
|||||||
@ -8,28 +8,51 @@ export interface GoViewImageOption {
|
|||||||
/**
|
/**
|
||||||
* Common in existing legacy widgets (same as iframe/video).
|
* Common in existing legacy widgets (same as iframe/video).
|
||||||
*/
|
*/
|
||||||
dataset?: string;
|
dataset?: unknown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Other variants seen in the wild.
|
* Other variants seen in the wild.
|
||||||
*/
|
*/
|
||||||
src?: string;
|
src?: unknown;
|
||||||
url?: string;
|
url?: unknown;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Styling.
|
* Styling.
|
||||||
*/
|
*/
|
||||||
fit?: ImageWidgetNode['props']['fit'];
|
fit?: unknown;
|
||||||
objectFit?: ImageWidgetNode['props']['fit'];
|
objectFit?: unknown;
|
||||||
borderRadius?: number;
|
borderRadius?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function asString(v: unknown): string {
|
||||||
|
if (typeof v === 'string') return v;
|
||||||
|
if (!v) return '';
|
||||||
|
|
||||||
|
// Some goView widgets store data as { value: '...' } or { url: '...' }.
|
||||||
|
if (typeof v === 'object') {
|
||||||
|
const obj = v as Record<string, unknown>;
|
||||||
|
if (typeof obj.value === 'string') return obj.value;
|
||||||
|
if (typeof obj.url === 'string') return obj.url;
|
||||||
|
if (typeof obj.src === 'string') return obj.src;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
function pickSrc(option: GoViewImageOption): string {
|
function pickSrc(option: GoViewImageOption): string {
|
||||||
return option.dataset ?? option.src ?? option.url ?? '';
|
return asString(option.dataset) || asString(option.src) || asString(option.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pickFit(option: GoViewImageOption): ImageWidgetNode['props']['fit'] | undefined {
|
function pickFit(option: GoViewImageOption): ImageWidgetNode['props']['fit'] | undefined {
|
||||||
return option.fit ?? option.objectFit;
|
const raw = asString(option.fit) || asString(option.objectFit);
|
||||||
|
if (!raw) return undefined;
|
||||||
|
|
||||||
|
const v = raw.toLowerCase();
|
||||||
|
if (v === 'contain' || v === 'cover' || v === 'fill' || v === 'none' || v === 'scale-down') {
|
||||||
|
return v as ImageWidgetNode['props']['fit'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertGoViewImageOptionToNodeProps(option: GoViewImageOption): ImageWidgetNode['props'] {
|
export function convertGoViewImageOptionToNodeProps(option: GoViewImageOption): ImageWidgetNode['props'] {
|
||||||
|
|||||||
@ -5,15 +5,15 @@ import type { VideoWidgetNode } from '../schema';
|
|||||||
* Keep it permissive and normalize the common fields.
|
* Keep it permissive and normalize the common fields.
|
||||||
*/
|
*/
|
||||||
export interface GoViewVideoOption {
|
export interface GoViewVideoOption {
|
||||||
dataset?: string;
|
dataset?: unknown;
|
||||||
src?: string;
|
src?: unknown;
|
||||||
url?: string;
|
url?: unknown;
|
||||||
|
|
||||||
loop?: boolean;
|
loop?: boolean;
|
||||||
muted?: boolean;
|
muted?: boolean;
|
||||||
|
|
||||||
fit?: VideoWidgetNode['props']['fit'];
|
fit?: unknown;
|
||||||
objectFit?: VideoWidgetNode['props']['fit'];
|
objectFit?: unknown;
|
||||||
|
|
||||||
borderRadius?: number;
|
borderRadius?: number;
|
||||||
}
|
}
|
||||||
@ -23,12 +23,35 @@ export interface GoViewVideoOption {
|
|||||||
*/
|
*/
|
||||||
export type LegacyVideoOption = GoViewVideoOption;
|
export type LegacyVideoOption = GoViewVideoOption;
|
||||||
|
|
||||||
|
function asString(v: unknown): string {
|
||||||
|
if (typeof v === 'string') return v;
|
||||||
|
if (!v) return '';
|
||||||
|
|
||||||
|
if (typeof v === 'object') {
|
||||||
|
const obj = v as Record<string, unknown>;
|
||||||
|
if (typeof obj.value === 'string') return obj.value;
|
||||||
|
if (typeof obj.url === 'string') return obj.url;
|
||||||
|
if (typeof obj.src === 'string') return obj.src;
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
function pickSrc(option: GoViewVideoOption): string {
|
function pickSrc(option: GoViewVideoOption): string {
|
||||||
return option.dataset ?? option.src ?? option.url ?? '';
|
return asString(option.dataset) || asString(option.src) || asString(option.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
function pickFit(option: GoViewVideoOption): VideoWidgetNode['props']['fit'] | undefined {
|
function pickFit(option: GoViewVideoOption): VideoWidgetNode['props']['fit'] | undefined {
|
||||||
return option.fit ?? option.objectFit;
|
const raw = asString(option.fit) || asString(option.objectFit);
|
||||||
|
if (!raw) return undefined;
|
||||||
|
|
||||||
|
// normalize common variants
|
||||||
|
const v = raw.toLowerCase();
|
||||||
|
if (v === 'contain' || v === 'cover' || v === 'fill' || v === 'none' || v === 'scale-down') {
|
||||||
|
return v as VideoWidgetNode['props']['fit'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertGoViewVideoOptionToNodeProps(option: GoViewVideoOption): VideoWidgetNode['props'] {
|
export function convertGoViewVideoOptionToNodeProps(option: GoViewVideoOption): VideoWidgetNode['props'] {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user