Skip to content

Commit

Permalink
refactor: fix dependencies and update to function
Browse files Browse the repository at this point in the history
  • Loading branch information
YvesRijckaert committed Jan 2, 2024
1 parent cd886a7 commit d30cec3
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 74 deletions.
2 changes: 1 addition & 1 deletion packages/live-preview-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@
"dependencies": {
"@contentful/rich-text-types": "^16.2.0",
"@contentful/visual-sdk": "^1.0.0-alpha.34",
"@types/json-pointer": "^1.0.34",
"@vercel/stega": "^0.1.0",
"graphql-tag": "^2.12.6",
"json-pointer": "^0.6.2",
"lodash.isequal": "^4.5.0"
},
"devDependencies": {
"@testing-library/react": "14.1.2",
"@types/json-pointer": "^1.0.34",
"@types/lodash.isequal": "^4.5.6",
"@types/node": "^20.1.0",
"@types/react": "^18.0.27",
Expand Down
20 changes: 7 additions & 13 deletions packages/live-preview-sdk/src/__tests__/csm.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { describe, test, beforeEach, expect } from 'vitest';
import { ContentSourceMaps } from '../csm';
import { describe, test, expect } from 'vitest';
import { encodeSourceMap } from '../csm';
import { vercelStegaDecode } from '@vercel/stega';

type Mappings = {
Expand Down Expand Up @@ -46,12 +46,6 @@ function testEncodingDecoding(encodedResponse: EncodedResponse, mappings: Mappin
}

describe('Content Source Maps', () => {
let csm: ContentSourceMaps;

beforeEach(() => {
csm = new ContentSourceMaps();
});

describe('GraphQL', () => {
test('basic example', () => {
const graphQLResponse = {
Expand Down Expand Up @@ -89,7 +83,7 @@ describe('Content Source Maps', () => {
},
},
};
const encodedGraphQLResponse = csm.encodeSourceMap(graphQLResponse);
const encodedGraphQLResponse = encodeSourceMap(graphQLResponse);
testEncodingDecoding(encodedGraphQLResponse.data.post, {
title: {
origin: 'contentful.com',
Expand Down Expand Up @@ -158,7 +152,7 @@ describe('Content Source Maps', () => {
},
},
};
const encodedGraphQLResponse = csm.encodeSourceMap(graphQLResponse);
const encodedGraphQLResponse = encodeSourceMap(graphQLResponse);
testEncodingDecoding(encodedGraphQLResponse.data.postCollection.items, {
0: {
title: {
Expand Down Expand Up @@ -229,7 +223,7 @@ describe('Content Source Maps', () => {
},
},
};
const encodedGraphQLResponse = csm.encodeSourceMap(graphQLResponse);
const encodedGraphQLResponse = encodeSourceMap(graphQLResponse);
testEncodingDecoding(encodedGraphQLResponse.data.postCollection.items[0], {
akanTitle: {
origin: 'contentful.com',
Expand Down Expand Up @@ -274,7 +268,7 @@ describe('Content Source Maps', () => {
},
},
};
const encodedGraphQLResponse = csm.encodeSourceMap(graphQLResponse);
const encodedGraphQLResponse = encodeSourceMap(graphQLResponse);

testEncodingDecoding(encodedGraphQLResponse.data.post, {
date: undefined,
Expand Down Expand Up @@ -309,7 +303,7 @@ describe('Content Source Maps', () => {
},
},
};
const encodedGraphQLResponse = csm.encodeSourceMap(graphQLResponse);
const encodedGraphQLResponse = encodeSourceMap(graphQLResponse);

testEncodingDecoding(encodedGraphQLResponse.data.post, {
url: undefined,
Expand Down
114 changes: 56 additions & 58 deletions packages/live-preview-sdk/src/csm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,72 +3,70 @@ import { debug } from '../helpers';
import jsonPointer from 'json-pointer';
import { EntitySource, GraphQLResponse, Source } from './types';

export class ContentSourceMaps {
private isUrlOrIsoDate(value: string) {
// Regular expression for URL validation
const urlRegex = /^(http|https):\/\/[^ "]+$/;
// Regular expression for ISO 8601 date validation
const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(.\d+)?([+-]\d{2}:\d{2}|Z)?$/;
const isUrlOrIsoDate = (value: string) => {
// Regular expression for URL validation
const urlRegex = /^(http|https):\/\/[^ "]+$/;
// Regular expression for ISO 8601 date validation
const isoDateRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(.\d+)?([+-]\d{2}:\d{2}|Z)?$/;

// Check if the string matches URL or ISO 8601 date format
return urlRegex.test(value) || isoDateRegex.test(value);
}
// Check if the string matches URL or ISO 8601 date format
return urlRegex.test(value) || isoDateRegex.test(value);
};

private getHref(
source: Source,
entries: EntitySource[],
assets: EntitySource[],
spaces: string[],
environments: string[],
fields: string[],
locales: string[]
): string | null {
const isEntry = 'entry' in source;
const entity = isEntry ? entries[source.entry] : assets[source.asset];
if (!entity) return null;
const getHref = (
source: Source,
entries: EntitySource[],
assets: EntitySource[],
spaces: string[],
environments: string[],
fields: string[],
locales: string[]
): string | null => {
const isEntry = 'entry' in source;
const entity = isEntry ? entries[source.entry] : assets[source.asset];
if (!entity) return null;

const space = spaces[entity.space];
const environment = environments[entity.environment];
const entityId = entity.id;
const field = fields[source.field];
const locale = locales[source.locale];
const space = spaces[entity.space];
const environment = environments[entity.environment];
const entityId = entity.id;
const field = fields[source.field];
const locale = locales[source.locale];

const basePath = `https://app.contentful.com/spaces/${space}/environments/${environment}`;
const entityType = isEntry ? 'entries' : 'assets';
return `${basePath}/${entityType}/${entityId}/?focusedField=${field}&focusedLocale=${locale}`;
}
const basePath = `https://app.contentful.com/spaces/${space}/environments/${environment}`;
const entityType = isEntry ? 'entries' : 'assets';
return `${basePath}/${entityType}/${entityId}/?focusedField=${field}&focusedLocale=${locale}`;
};

encodeSourceMap(graphqlResponse: GraphQLResponse): GraphQLResponse {
if (
!graphqlResponse ||
!graphqlResponse.extensions ||
!graphqlResponse.extensions.contentSourceMaps
) {
debug.error('GraphQL response does not contain Content Source Maps information.');
return graphqlResponse;
}
const { spaces, environments, fields, locales, entries, assets, mappings } =
graphqlResponse.extensions.contentSourceMaps;
const data = graphqlResponse.data;
export const encodeSourceMap = (graphqlResponse: GraphQLResponse): GraphQLResponse => {
if (
!graphqlResponse ||
!graphqlResponse.extensions ||
!graphqlResponse.extensions.contentSourceMaps
) {
debug.error('GraphQL response does not contain Content Source Maps information.');
return graphqlResponse;
}
const { spaces, environments, fields, locales, entries, assets, mappings } =
graphqlResponse.extensions.contentSourceMaps;
const data = graphqlResponse.data;

for (const pointer in mappings) {
const { source } = mappings[pointer];
const href = this.getHref(source, entries, assets, spaces, environments, fields, locales);
for (const pointer in mappings) {
const { source } = mappings[pointer];
const href = getHref(source, entries, assets, spaces, environments, fields, locales);

if (href && jsonPointer.has(data, pointer)) {
const currentValue = jsonPointer.get(data, pointer);
if (href && jsonPointer.has(data, pointer)) {
const currentValue = jsonPointer.get(data, pointer);

if (!this.isUrlOrIsoDate(currentValue)) {
const encodedValue = vercelStegaEncode({
origin: 'contentful.com',
href,
});
jsonPointer.set(data, pointer, `${encodedValue}${currentValue}`);
}
} else {
debug.error(`Pointer ${pointer} not found in GraphQL data or href could not be generated.`);
if (!isUrlOrIsoDate(currentValue)) {
const encodedValue = vercelStegaEncode({
origin: 'contentful.com',
href,
});
jsonPointer.set(data, pointer, `${encodedValue}${currentValue}`);
}
} else {
debug.error(`Pointer ${pointer} not found in GraphQL data or href could not be generated.`);
}
return graphqlResponse;
}
}
return graphqlResponse;
};
4 changes: 2 additions & 2 deletions packages/live-preview-sdk/src/csm/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface EntitySource {

type Mappings = Record<string, { source: Source }>;

interface IContentSourceMaps {
interface ContentSourceMaps {
version: number;
spaces: string[];
environments: string[];
Expand All @@ -25,6 +25,6 @@ interface IContentSourceMaps {
export interface GraphQLResponse {
data: any;
extensions: {
contentSourceMaps: IContentSourceMaps;
contentSourceMaps: ContentSourceMaps;
};
}

0 comments on commit d30cec3

Please sign in to comment.