Skip to content

Commit

Permalink
#114 Test guillotine
Browse files Browse the repository at this point in the history
  • Loading branch information
ComLock committed Feb 2, 2024
1 parent b53eebb commit 5c3142f
Show file tree
Hide file tree
Showing 12 changed files with 462 additions and 53 deletions.
8 changes: 8 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@ export default {
// '!src/**/*.d.ts',
],
coverageProvider: 'v8',
globals: {
app: {
name: 'com.enonic.app.metafields',
config: {}
}
},
moduleNameMapper: {
'/guillotine/(.*)': '<rootDir>/src/main/resources/guillotine/$1',
'/lib/common/(.*)': '<rootDir>/src/main/resources/lib/common/$1',
'/lib/metadata/(.*)': '<rootDir>/src/main/resources/lib/metadata/$1',
'/lib/brand(.*)': '<rootDir>/src/main/resources/lib/brand$1',
},
preset: 'ts-jest/presets/js-with-babel-legacy',
testEnvironment: 'node',
Expand Down
70 changes: 60 additions & 10 deletions src/main/resources/guillotine/guillotine.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import type {Content} from '@enonic-types/lib-content';
import type {Branded} from '/lib/brand.d';


export declare type BaseFolder = Content<{}, 'base:folder'>;

export declare type MediaImage = Content<{
media: {
altText?: string
artist?: string
attachment: string
caption?: string
copyright?: string
focalPoint: {
x: number
y: number
}
tags?: string // with comma?
}
}, 'media:image'>;

export const enum GraphQLTypeName {
CONTENT = 'Content',
// IMAGE = 'Image',
Expand All @@ -9,6 +27,34 @@ export const enum GraphQLTypeName {
METAFIELDS = 'MetaFields',
}

export interface MetaFields {
alternates?: {
canonical?: string
}, // string
description?: string
images?: MediaImage[]
locale?: string
openGraph?: {
type?: 'website' | 'article'
} // string
robots?: {
follow?: boolean
index?: boolean
} // string
siteName: string
title: string
twitter?: {
creator?: string
} // string
verification?: {
google?: string
} // string
}

type GraphQLContent = Branded<Content, 'Content'>
type GraphQLMediaImage = Branded<MediaImage, 'media_Image'>
type GraphQLMetaFields = Branded<MetaFields, 'MetaFields'>

export const enum GraphQLFieldName {
IMAGES = 'images',
METAFIELDS = 'metaFields',
Expand All @@ -23,23 +69,27 @@ type GraphQLInt = Branded<number, 'GraphQLInt'>
type GraphQLID = Branded<string, 'GraphQLID'>
type GraphQLBoolean = Branded<boolean, 'GraphQLBoolean'>
type GraphQLFloat = Branded<number, 'GraphQLFloat'>
type GraphJson = Branded<string, 'Json'>
type GraphDateTime = Branded<string, 'DateTime'>
type GraphDate = Branded<string, 'Date'>
type GraphLocalTime = Branded<string, 'LocalTime'>
type GraphLocalDateTime = Branded<string, 'LocalDateTime'>
type GraphQLJson = Branded<string, 'Json'>
type GraphQLDateTime = Branded<string, 'DateTime'>
type GraphQLDate = Branded<string, 'Date'>
type GraphQLLocalTime = Branded<string, 'LocalTime'>
type GraphQLLocalDateTime = Branded<string, 'LocalDateTime'>

type GraphQLType =
| GraphQLString
| GraphQLInt
| GraphQLID
| GraphQLBoolean
| GraphQLFloat
| GraphJson
| GraphDateTime
| GraphDate
| GraphLocalTime
| GraphLocalDateTime
| GraphQLJson
| GraphQLDateTime
| GraphQLDate
| GraphQLLocalTime
| GraphQLLocalDateTime
// Extensions:
| GraphQLContent
| GraphQLMediaImage
| GraphQLMetaFields

type GraphQLTypes =
|'GraphQLString'
Expand Down
11 changes: 10 additions & 1 deletion src/main/resources/guillotine/guillotine.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type {Extensions, GraphQL} from '/guillotine/guillotine.d';
import type {
Extensions,
GraphQL,
} from '/guillotine/guillotine.d';


import {GraphQLFieldName, GraphQLTypeName} from '/guillotine/guillotine.d';
Expand All @@ -18,6 +21,9 @@ export const extensions = (graphQL: GraphQL): Extensions => {
description: {
type: graphQL.GraphQLString,
},
locale: {
type: graphQL.GraphQLString,
},
images: {
type: graphQL.list(graphQL.reference(GraphQLTypeName.MEDIA_IMAGE)),
},
Expand All @@ -27,6 +33,9 @@ export const extensions = (graphQL: GraphQL): Extensions => {
robots: {
type: graphQL.Json,
},
siteName: {
type: graphQL.GraphQLString,
},
title: {
type: graphQL.nonNull(graphQL.GraphQLString),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import {getBlockRobots} from '/lib/common/getBlockRobots';
import {getLang} from '/lib/common/getLang';
import {getMetaDescription} from '/lib/common/getMetaDescription';
import {getPageTitle} from '/lib/common/getPageTitle';
import {getFullTitle} from '/lib/common/getFullTitle';
import {getSiteConfigFromSite} from '/lib/common/getSiteConfigFromSite';
import {getTheConfig} from '/lib/common/getTheConfig';
import {APP_CONFIG, APP_NAME, APP_NAME_PATH, MIXIN_PATH} from '/lib/common/constants';
Expand Down Expand Up @@ -62,7 +62,7 @@ export const contentMetaFieldsResolver: Resolver<
content,
site
});
const title = getPageTitle({
const title = getFullTitle({
applicationConfig: APP_CONFIG,
applicationKey: APP_NAME,
content,
Expand All @@ -77,7 +77,7 @@ export const contentMetaFieldsResolver: Resolver<
const siteConfig = getSiteConfigFromSite({
applicationKey: APP_NAME,
site
})
});
const blockRobots = siteConfig.blockRobots || getBlockRobots(content)

let canonical = null;
Expand Down Expand Up @@ -105,19 +105,19 @@ export const contentMetaFieldsResolver: Resolver<
// },{
// _id: '358cd06c-d97b-4088-963c-e32170bd7866'
// }],
locale: getLang(content, site),
openGraph: {
// description, // NOTE: Also available on toplevel
// images: appOrSiteConfig.removeOpenGraphImage ? [] : images
locale: getLang(content, site),
siteName: site.displayName,
// title, // NOTE: Also available on toplevel
type: isFrontpage ? 'website' : 'article',
url: appOrSiteConfig.removeOpenGraphUrl ? null : _path,
type: isFrontpage ? 'website' : 'article', // TODO could be expanded to support more types, see https://ogp.me/
// url: appOrSiteConfig.removeOpenGraphUrl ? null : _path,
},
robots: {
follow: !blockRobots,
index: !blockRobots,
},
siteName: site.displayName,
title,
twitter: {
// description, // NOTE: Also available on toplevel
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export const metaFieldsImagesResolver: Resolver<
}
} = context;
// log.info(`resolvers content metafields context ${JSON.stringify(context, null, 4)}`);
// log.info(`metaFieldsImagesResolver imageContentIds:${imageContentIds}`);
return runInContext({
branch,
repository: `com.enonic.cms.${project}`,
Expand All @@ -63,10 +62,8 @@ export const metaFieldsImagesResolver: Resolver<
principals
}, () => {

// const imageIds = [];
const images = [];
if (_siteConfig.seoImage) {
// imageIds.push(_siteConfig.seoImage);
const imageContent = getContentByKey({ key: _siteConfig.seoImage });
if (imageContent) {
images.push(imageContent);
Expand All @@ -79,7 +76,6 @@ export const metaFieldsImagesResolver: Resolver<
const userDefinedArray = userDefinedPaths ? commaStringToArray(userDefinedPaths) : [];
const userDefinedValue = userDefinedPaths ? findStringValueInObject(_content, userDefinedArray, _siteConfig.fullPath) : null;
if (userDefinedValue) {
// imageIds.push(userDefinedValue);
const imageContent = getContentByKey({ key: userDefinedValue });
if (imageContent) {
images.push(imageContent);
Expand All @@ -88,15 +84,13 @@ export const metaFieldsImagesResolver: Resolver<
}
} else {
if (_content.data.image) {
// imageIds.push(content.data.image);
const imageContent = getContentByKey({ key: _content.data.image as string });
if (imageContent) {
images.push(imageContent);
} else {
log.error(`content with _path:${_content._path} references a non-existing image with key:${_content.data.image}}`);
}
} else if (_content.data.images) {
// imageIds.push(content.data.images);
const imageContent = getContentByKey({ key: _content.data.images as string });
if (imageContent) {
images.push(imageContent);
Expand All @@ -107,7 +101,6 @@ export const metaFieldsImagesResolver: Resolver<
}
}
if (_siteConfig.frontpageImage) {
// imageIds.push(_siteConfig.frontpageImage);
const imageContent = getContentByKey({ key: _siteConfig.frontpageImage });
if (imageContent) {
images.push(imageContent);
Expand All @@ -116,15 +109,5 @@ export const metaFieldsImagesResolver: Resolver<
}
}
return images;
// log.info(`contentMetaFieldsResolver imageIds:${imageIds}`);

// return imageContentIds.map((imageContentId) => {
// const imageContent = getContentByKey({ key: imageContentId });
// if (imageContent) {
// return imageContent;
// }
// log.error(`image content with key:${imageContentId} not found!`);
// return null;
// }).filter((imageContent) => imageContent !== null);
});
}
2 changes: 1 addition & 1 deletion src/main/resources/lib/brand.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {BrandBase, BrandBuilder, BrandBuilderOptions, Branded} from '/lib/brand.d';


function brand<T extends Branded<Base, any>, Base = BrandBase<T>>({
export function brand<T extends Branded<Base, any>, Base = BrandBase<T>>({
validate = () => true,
}: BrandBuilderOptions<Base> = {}): BrandBuilder<T, Base> {
function assertIsBrand(value: Base): asserts value is T {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@ import {getAppendix} from '/lib/common/getAppendix';
import {getPageTitle} from '/lib/common/getPageTitle';


export function getTitle({
export function getFullTitle({
applicationConfig, // Avoid app.config so it can be used in Guillotine Extension Context
applicationKey, // Avoid app.name so it can be used in Guillotine Extension Context,
content=undefined,
content,
site,
}: {
applicationConfig: Record<string, string|boolean>
applicationKey: string
content?: Content
content: Content
site: Site<MetafieldsSiteConfig>
}) {
if (!content) {
return undefined;
}

const isFrontpage = site._path === content._path;
const titleAppendix = getAppendix({
applicationConfig,
Expand All @@ -35,7 +31,5 @@ export function getTitle({
content,
site
});
const titleHtml = "<title>" + pageTitle + titleAppendix + "</title>";

return titleHtml;
return `${pageTitle}${titleAppendix}`;
}
2 changes: 1 addition & 1 deletion src/main/resources/lib/common/getSiteConfigFromSite.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {Site} from '/lib/xp/portal';
import type { MetafieldsSiteConfig } from '/lib/common/MetafieldsSiteConfig.d';
import type {MetafieldsSiteConfig} from '/lib/common/MetafieldsSiteConfig.d';


import {forceArray} from '@enonic/js-utils/array/forceArray';
Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/lib/metadata/getFixedHtmlAttrsAsString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function getFixedHtmlAttrsAsString(htmlTag) {
if (htmlTagAttributes[i].toLowerCase().trim() === "prefix") {
prefixFound = true;
if (htmlTagAttributes[i + 1].indexOf(OG_ATTRIBUTE) === -1) {
//log.info("Before join - " + htmlTagAttributes[i+1]);
// log.info("Before join - " + htmlTagAttributes[i+1]);
htmlTagAttributes[i + 1] =
htmlTagAttributes[i + 1].substr(
0,
Expand All @@ -22,9 +22,9 @@ export function getFixedHtmlAttrsAsString(htmlTag) {
" " +
OG_ATTRIBUTE +
htmlTagAttributes[i + 1].substr(-1);
//log.info("After join - " + htmlTagAttributes[i+1]);
// log.info("After join - " + htmlTagAttributes[i+1]);
} else {
//log.info("Already in the tag!");
// log.info("Already in the tag!");
}
}
}
Expand Down
30 changes: 30 additions & 0 deletions src/main/resources/lib/metadata/getTitleHtml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type {Content} from '/lib/xp/content';
import type {Site} from '/lib/xp/portal';
import type {MetafieldsSiteConfig} from '/lib/common/MetafieldsSiteConfig.d';


import {getFullTitle} from '/lib/common/getFullTitle';


export function getTitleHtml({
applicationConfig, // Avoid app.config so it can be used in Guillotine Extension Context
applicationKey, // Avoid app.name so it can be used in Guillotine Extension Context,
content=undefined,
site,
}: {
applicationConfig: Record<string, string|boolean>
applicationKey: string
content?: Content
site: Site<MetafieldsSiteConfig>
}) {
if (!content) {
return undefined;
}

return `<title>${getFullTitle({
applicationConfig,
applicationKey,
content,
site
})}</title>`;
}
6 changes: 3 additions & 3 deletions src/main/resources/site/processors/add-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {forceArray} from '@enonic/js-utils/array/forceArray';
import {getFixedHtmlAttrsAsString} from '/lib/metadata/getFixedHtmlAttrsAsString';
import {getMetaData} from '/lib/metadata/getMetaData'
import {getReusableData} from '/lib/metadata/getReusableData';
import {getTitle} from '/lib/metadata/getTitle';
import {getTitleHtml} from '../../lib/metadata/getTitleHtml';


const HTML_MEDIA_TYPE = 'text/html';
Expand Down Expand Up @@ -36,7 +36,7 @@ export const responseProcessor = (req, res) => {
// Handle injection of title - use any existing tag by replacing its content.
// Svg are text/html can have a <title>
if (titleHasIndex && htmlIndex > -1) {
const titleHtml = getTitle({
const titleHtml = getTitleHtml({
applicationConfig: app.config, // NOTE: Using app.config is fine, since it's outside Guillotine Execution Context
applicationKey: app.name, // NOTE: Using app.name is fine, since it's outside Guillotine Execution Context
content,
Expand Down Expand Up @@ -72,7 +72,7 @@ export const responseProcessor = (req, res) => {
}

if ( !titleAdded ) {
const titleHtml = getTitle({
const titleHtml = getTitleHtml({
applicationConfig: app.config, // NOTE: Using app.config is fine, since it's outside Guillotine Execution Context
applicationKey: app.name, // NOTE: Using app.name is fine, since it's outside Guillotine Execution Context
content,
Expand Down
Loading

0 comments on commit 5c3142f

Please sign in to comment.