@quintype/seo 1.41.1 → 1.41.3-gsc-errors-fix.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [1.41.2](https://github.com/quintype/quintype-node-seo/compare/v1.41.1...v1.41.2) (2022-11-30)
6
+
5
7
  ### [1.41.1](https://github.com/quintype/quintype-node-seo/compare/v1.41.1-gsc-errors.0...v1.41.1) (2022-11-29)
6
8
 
7
9
  ## [1.41.0](https://github.com/quintype/quintype-node-seo/compare/v1.40.15...v1.41.0) (2022-11-29)
package/dist/index.cjs.js CHANGED
@@ -81,13 +81,14 @@ const getDomain = (url, domainSlug) => {
81
81
  * @param {...*} params See {@link Generator} for other Parameters
82
82
  */
83
83
  function StoryAmpTags(seoConfig, config, pageType, data = {}, opts) {
84
+ const templatesToIgnore = seoConfig.ignoreAmpHtmlStoryTemplates || ["visual-story"];
84
85
  const story = get__default["default"](data, ["data", "story"], {});
85
86
  const { currentHostUrl = "", domainSlug } = data;
86
87
  // TODO: Remove this condition and always make absolute URL if that's better for AMP discoverability.
87
88
  const ampUrlAppend = seoConfig.appendHostToAmpUrl ? getDomain(currentHostUrl, domainSlug) || config["sketches-host"] : "";
88
89
  const storySlug = seoConfig.decodeAmpUrl ? decodeURIComponent(story.slug) : encodeURIComponent(story.slug);
89
90
  const ampUrl = story["story-template"] === "visual-story" ? `${ampUrlAppend}/${storySlug}` : `${ampUrlAppend}/amp/story/${storySlug}`;
90
- const ignoreStoryTemplate = seoConfig.ignoreAmpHtmlStoryTemplates && seoConfig.ignoreAmpHtmlStoryTemplates.includes(story["story-template"]);
91
+ const ignoreStoryTemplate = templatesToIgnore.includes(story["story-template"]);
91
92
  if (showAmpTag(seoConfig, pageType, story) && !ignoreStoryTemplate) {
92
93
  return [{
93
94
  tag: "link",
@@ -106,13 +107,28 @@ function StoryAmpTags(seoConfig, config, pageType, data = {}, opts) {
106
107
  * @param {*} seoConfig
107
108
  * @param {...*} params See {@link Generator} for other Parameters
108
109
  */
109
- function AuthorTags(seoConfig, config, pageType, data, { url }) {
110
- if (pageType != "story-page" || pageType != "story-page-amp") return [];
111
110
 
112
- return [{
113
- name: "twitter:creator",
114
- content: lodash.get(data, ["data", "story", "author-name"])
115
- }];
111
+ function AuthorTags(seoConfig, config, pageType, data, { url }) {
112
+ if (pageType === "story-page" || pageType === "story-page-amp") {
113
+ return [{
114
+ name: "twitter:creator",
115
+ content: getTwitterCreator(data)
116
+ }];
117
+ }
118
+ return [];
119
+ }
120
+
121
+ function getTwitterCreator(storyData) {
122
+ const twitterData = lodash.get(storyData, ["data", "story", "authors", 0, "social", "twitter"], {});
123
+ const twitterUrl = twitterData.url || "";
124
+ const twitterHandle = twitterData.handle || "";
125
+ if (twitterHandle.startsWith("@")) return twitterHandle;
126
+ const twitterHandleFromUrl = twitterUrl.split("/").pop();
127
+ if (twitterHandleFromUrl) {
128
+ if (twitterHandleFromUrl.startsWith("@")) return twitterHandleFromUrl;
129
+ return `@${twitterHandleFromUrl}`;
130
+ }
131
+ return lodash.get(storyData, ["data", "story", "author-name"]);
116
132
  }
117
133
 
118
134
  function getTitle$1(config) {
@@ -122,9 +138,10 @@ function getTitle$1(config) {
122
138
  function generateStaticData(config) {
123
139
  const title = getTitle$1(config);
124
140
  const themeConfig = config["theme-attributes"] || {};
125
- const publicIntegrations = get__default["default"](config, ['public-integrations'], {});
141
+ const publicIntegrations = get__default["default"](config, ["public-integrations"], {});
142
+ const siteTwitterHandle = getSiteTwitterHandle(config, title);
126
143
  const staticData = {
127
- "twitter:site": title,
144
+ "twitter:site": siteTwitterHandle,
128
145
  "twitter:domain": config["sketches-host"],
129
146
  "twitter:app:name:ipad": themeConfig["twitter_app_name_ipad"],
130
147
  "twitter:app:name:googleplay": themeConfig["twitter_app_name_googleplay"],
@@ -133,7 +150,7 @@ function generateStaticData(config) {
133
150
  "twitter:app:id:iphone": themeConfig["twitter_app_id_iphone"],
134
151
  "apple-itunes-app": themeConfig["apple_itunes_app"],
135
152
  "google-play-app": themeConfig["google_play_app"],
136
- "fb:app_id": get__default["default"](publicIntegrations, ['facebook', 'app-id']) || get__default["default"](themeConfig, ["fb_app_id"]),
153
+ "fb:app_id": get__default["default"](publicIntegrations, ["facebook", "app-id"]) || get__default["default"](themeConfig, ["fb_app_id"]),
137
154
  "fb:pages": themeConfig["fb_pages"],
138
155
  "og:site_name": title
139
156
  };
@@ -146,12 +163,12 @@ function generateImageObject(config = {}) {
146
163
  return {
147
164
  "@context": "http://schema.org",
148
165
  "@type": "ImageObject",
149
- "author": config['publisher-name'],
150
- "contentUrl": themeConfig.logo,
151
- "url": themeConfig.logo,
152
- "name": "logo",
153
- "width": themeConfig.logo && getQueryParams(themeConfig.logo).width,
154
- "height": themeConfig.logo && getQueryParams(themeConfig.logo).height
166
+ author: config["publisher-name"],
167
+ contentUrl: themeConfig.logo,
168
+ url: themeConfig.logo,
169
+ name: "logo",
170
+ width: themeConfig.logo && getQueryParams(themeConfig.logo).width,
171
+ height: themeConfig.logo && getQueryParams(themeConfig.logo).height
155
172
  };
156
173
  }
157
174
 
@@ -163,8 +180,8 @@ function generateStructuredData(config = {}) {
163
180
  if (!themeConfig || !themeConfig.logo) {
164
181
  return {};
165
182
  }
166
- let enableStructuredDataForNewsArticle = themeConfig['structured_data_news_article'] || false;
167
- if (config.hasOwnProperty('enableStructuredDataForNewsArticle') && typeof config.enableStructuredDataForNewsArticle !== "undefined") {
183
+ let enableStructuredDataForNewsArticle = themeConfig["structured_data_news_article"] || false;
184
+ if (config.hasOwnProperty("enableStructuredDataForNewsArticle") && typeof config.enableStructuredDataForNewsArticle !== "undefined") {
168
185
  enableStructuredDataForNewsArticle = config.enableStructuredDataForNewsArticle;
169
186
  }
170
187
 
@@ -177,8 +194,8 @@ function generateStructuredData(config = {}) {
177
194
  },
178
195
  enableNewsArticle: !!enableStructuredDataForNewsArticle,
179
196
  storyUrlAsMainEntityUrl: !!enableStructuredDataForNewsArticle,
180
- enableVideo: !themeConfig['structured_data_enable_video'],
181
- enableLiveBlog: !themeConfig['structured_data_enable_live_blog'],
197
+ enableVideo: !themeConfig["structured_data_enable_video"],
198
+ enableLiveBlog: !themeConfig["structured_data_enable_live_blog"],
182
199
  website: {
183
200
  url: config["sketches-host"],
184
201
  searchpath: "search?q={query}",
@@ -190,6 +207,16 @@ function generateStructuredData(config = {}) {
190
207
  };
191
208
  }
192
209
 
210
+ function getSiteTwitterHandle(config, fallback) {
211
+ const twitterUrl = get__default["default"](config, ["social-links", "twitter-url"], "");
212
+ const twitterHandleFromUrl = twitterUrl.split("/").pop();
213
+ if (twitterHandleFromUrl) {
214
+ if (twitterHandleFromUrl.startsWith("@")) return twitterHandleFromUrl;
215
+ return `@${twitterHandleFromUrl}`;
216
+ }
217
+ return fallback;
218
+ }
219
+
193
220
  function pickImageFromCard(story, cardId) {
194
221
  const { metadata = {} } = story.cards.find(card => card.id === cardId) || {};
195
222
  if (metadata && !lodash.isEmpty(metadata) && lodash.get(metadata, ["social-share", "image", "key"], false)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quintype/seo",
3
- "version": "1.41.1",
3
+ "version": "1.41.3-gsc-errors-fix.0",
4
4
  "description": "SEO Modules for Quintype",
5
5
  "main": "dist/index.cjs.js",
6
6
  "repository": "https://github.com/quintype/quintype-node-seo",
package/src/amp-tags.js CHANGED
@@ -33,6 +33,7 @@ const getDomain = (url, domainSlug) => {
33
33
  * @param {...*} params See {@link Generator} for other Parameters
34
34
  */
35
35
  export function StoryAmpTags(seoConfig, config, pageType, data = {}, opts) {
36
+ const templatesToIgnore = seoConfig.ignoreAmpHtmlStoryTemplates || ["visual-story"];
36
37
  const story = get(data, ["data", "story"], {});
37
38
  const { currentHostUrl = "", domainSlug } = data;
38
39
  // TODO: Remove this condition and always make absolute URL if that's better for AMP discoverability.
@@ -44,8 +45,7 @@ export function StoryAmpTags(seoConfig, config, pageType, data = {}, opts) {
44
45
  story["story-template"] === "visual-story"
45
46
  ? `${ampUrlAppend}/${storySlug}`
46
47
  : `${ampUrlAppend}/amp/story/${storySlug}`;
47
- const ignoreStoryTemplate =
48
- seoConfig.ignoreAmpHtmlStoryTemplates && seoConfig.ignoreAmpHtmlStoryTemplates.includes(story["story-template"]);
48
+ const ignoreStoryTemplate = templatesToIgnore.includes(story["story-template"]);
49
49
  if (showAmpTag(seoConfig, pageType, story) && !ignoreStoryTemplate) {
50
50
  return [
51
51
  {
@@ -7,13 +7,28 @@ import { get } from "lodash";
7
7
  * @param {*} seoConfig
8
8
  * @param {...*} params See {@link Generator} for other Parameters
9
9
  */
10
+
10
11
  export function AuthorTags(seoConfig, config, pageType, data, { url }) {
11
- if (pageType != "story-page" || pageType != "story-page-amp") return [];
12
+ if (pageType === "story-page" || pageType === "story-page-amp") {
13
+ return [
14
+ {
15
+ name: "twitter:creator",
16
+ content: getTwitterCreator(data),
17
+ },
18
+ ];
19
+ }
20
+ return [];
21
+ }
12
22
 
13
- return [
14
- {
15
- name: "twitter:creator",
16
- content: get(data, ["data", "story", "author-name"]),
17
- },
18
- ];
23
+ function getTwitterCreator(storyData) {
24
+ const twitterData = get(storyData, ["data", "story", "authors", 0, "social", "twitter"], {});
25
+ const twitterUrl = twitterData.url || "";
26
+ const twitterHandle = twitterData.handle || "";
27
+ if (twitterHandle.startsWith("@")) return twitterHandle;
28
+ const twitterHandleFromUrl = twitterUrl.split("/").pop();
29
+ if (twitterHandleFromUrl) {
30
+ if (twitterHandleFromUrl.startsWith("@")) return twitterHandleFromUrl;
31
+ return `@${twitterHandleFromUrl}`;
32
+ }
33
+ return get(storyData, ["data", "story", "author-name"]);
19
34
  }
@@ -1,6 +1,6 @@
1
- import get from 'lodash/get';
2
- import isUndefined from 'lodash/isUndefined';
3
- import omitBy from 'lodash/omitBy';
1
+ import get from "lodash/get";
2
+ import isUndefined from "lodash/isUndefined";
3
+ import omitBy from "lodash/omitBy";
4
4
  import { getQueryParams } from "./utils";
5
5
 
6
6
  export function getTitle(config) {
@@ -10,9 +10,10 @@ export function getTitle(config) {
10
10
  export function generateStaticData(config) {
11
11
  const title = getTitle(config);
12
12
  const themeConfig = config["theme-attributes"] || {};
13
- const publicIntegrations = get(config, ['public-integrations'], {});
13
+ const publicIntegrations = get(config, ["public-integrations"], {});
14
+ const siteTwitterHandle = getSiteTwitterHandle(config, title);
14
15
  const staticData = {
15
- "twitter:site": title,
16
+ "twitter:site": siteTwitterHandle,
16
17
  "twitter:domain": config["sketches-host"],
17
18
  "twitter:app:name:ipad": themeConfig["twitter_app_name_ipad"],
18
19
  "twitter:app:name:googleplay": themeConfig["twitter_app_name_googleplay"],
@@ -21,38 +22,41 @@ export function generateStaticData(config) {
21
22
  "twitter:app:id:iphone": themeConfig["twitter_app_id_iphone"],
22
23
  "apple-itunes-app": themeConfig["apple_itunes_app"],
23
24
  "google-play-app": themeConfig["google_play_app"],
24
- "fb:app_id": get(publicIntegrations, ['facebook', 'app-id']) || get(themeConfig, ["fb_app_id"]),
25
+ "fb:app_id": get(publicIntegrations, ["facebook", "app-id"]) || get(themeConfig, ["fb_app_id"]),
25
26
  "fb:pages": themeConfig["fb_pages"],
26
- "og:site_name": title
27
+ "og:site_name": title,
27
28
  };
28
29
 
29
30
  return omitBy(staticData, isUndefined);
30
31
  }
31
32
 
32
33
  export function generateImageObject(config = {}) {
33
- const {"theme-attributes": themeConfig = {}} = config;
34
- return ({
34
+ const { "theme-attributes": themeConfig = {} } = config;
35
+ return {
35
36
  "@context": "http://schema.org",
36
37
  "@type": "ImageObject",
37
- "author": config['publisher-name'],
38
- "contentUrl": themeConfig.logo,
39
- "url": themeConfig.logo,
40
- "name": "logo",
41
- "width": themeConfig.logo && getQueryParams(themeConfig.logo).width,
42
- "height": themeConfig.logo && getQueryParams(themeConfig.logo).height
43
- });
38
+ author: config["publisher-name"],
39
+ contentUrl: themeConfig.logo,
40
+ url: themeConfig.logo,
41
+ name: "logo",
42
+ width: themeConfig.logo && getQueryParams(themeConfig.logo).width,
43
+ height: themeConfig.logo && getQueryParams(themeConfig.logo).height,
44
+ };
44
45
  }
45
46
 
46
47
  export function generateStructuredData(config = {}) {
47
48
  const title = getTitle(config);
48
- const { "theme-attributes":themeConfig, "social-links":socialLinks, "seo-metadata":seoMetadata = [] } = config;
49
- const homePageSeo = seoMetadata.find(page => page["owner-type"] === "home") || {};
50
- const { "page-title":pageTitle = "", description = "", keywords = "" } = get(homePageSeo, ["data"], {});
51
- if(!themeConfig || !themeConfig.logo) {
49
+ const { "theme-attributes": themeConfig, "social-links": socialLinks, "seo-metadata": seoMetadata = [] } = config;
50
+ const homePageSeo = seoMetadata.find((page) => page["owner-type"] === "home") || {};
51
+ const { "page-title": pageTitle = "", description = "", keywords = "" } = get(homePageSeo, ["data"], {});
52
+ if (!themeConfig || !themeConfig.logo) {
52
53
  return {};
53
54
  }
54
- let enableStructuredDataForNewsArticle = themeConfig['structured_data_news_article'] || false;
55
- if(config.hasOwnProperty('enableStructuredDataForNewsArticle') && typeof config.enableStructuredDataForNewsArticle !== "undefined"){
55
+ let enableStructuredDataForNewsArticle = themeConfig["structured_data_news_article"] || false;
56
+ if (
57
+ config.hasOwnProperty("enableStructuredDataForNewsArticle") &&
58
+ typeof config.enableStructuredDataForNewsArticle !== "undefined"
59
+ ) {
56
60
  enableStructuredDataForNewsArticle = config.enableStructuredDataForNewsArticle;
57
61
  }
58
62
 
@@ -61,19 +65,29 @@ export function generateStructuredData(config = {}) {
61
65
  name: title,
62
66
  url: config["sketches-host"],
63
67
  logo: generateImageObject(config),
64
- sameAs: socialLinks ? Object.values(socialLinks) : []
68
+ sameAs: socialLinks ? Object.values(socialLinks) : [],
65
69
  },
66
- enableNewsArticle: !!enableStructuredDataForNewsArticle,
67
- storyUrlAsMainEntityUrl: !!enableStructuredDataForNewsArticle,
68
- enableVideo: !themeConfig['structured_data_enable_video'],
69
- enableLiveBlog: !themeConfig['structured_data_enable_live_blog'],
70
+ enableNewsArticle: !!enableStructuredDataForNewsArticle,
71
+ storyUrlAsMainEntityUrl: !!enableStructuredDataForNewsArticle,
72
+ enableVideo: !themeConfig["structured_data_enable_video"],
73
+ enableLiveBlog: !themeConfig["structured_data_enable_live_blog"],
70
74
  website: {
71
75
  url: config["sketches-host"],
72
76
  searchpath: "search?q={query}",
73
77
  queryinput: "required name=query",
74
78
  name: pageTitle || title,
75
79
  headline: description,
76
- keywords
80
+ keywords,
77
81
  },
82
+ };
83
+ }
84
+
85
+ function getSiteTwitterHandle(config, fallback) {
86
+ const twitterUrl = get(config, ["social-links", "twitter-url"], "");
87
+ const twitterHandleFromUrl = twitterUrl.split("/").pop();
88
+ if (twitterHandleFromUrl) {
89
+ if (twitterHandleFromUrl.startsWith("@")) return twitterHandleFromUrl;
90
+ return `@${twitterHandleFromUrl}`;
78
91
  }
92
+ return fallback;
79
93
  }
@@ -1,9 +1,9 @@
1
1
  const { StoryAmpTags } = require("..");
2
2
  const { getSeoMetadata, assertContains } = require("./utils");
3
3
 
4
- const assert = require('assert');
4
+ const assert = require("assert");
5
5
 
6
- describe('AmpTags', function () {
6
+ describe("AmpTags", function () {
7
7
  const seoConfig = {
8
8
  generators: [StoryAmpTags],
9
9
  ampStoryPages: true,
@@ -19,12 +19,6 @@ describe('AmpTags', function () {
19
19
  assertContains('<link rel="amphtml" href="/amp/story/section%2Fslug"/>', string);
20
20
  });
21
21
 
22
- it("it does not append `/amp/story` to the amp tag when it's a visual story", function () {
23
- const story = { slug: "section/slug", "is-amp-supported": true };
24
- const string = getSeoMetadata(seoConfig, config, "story-page", { data: { story: { ...story, "story-template": "visual-story" } } }, {});
25
- assertContains('<link rel="amphtml" href="/section%2Fslug"/>', string);
26
- });
27
-
28
22
  it("does not rely on is-amp-supported in story API", function () {
29
23
  const story = { slug: "section/slug", "is-amp-supported": false };
30
24
  const string = getSeoMetadata(seoConfig, config, "story-page", { data: { story: story } }, {});
@@ -0,0 +1,106 @@
1
+ const { AuthorTags } = require("..");
2
+ const { getSeoMetadata } = require("./utils");
3
+ const assert = require("assert");
4
+
5
+ describe("AuthorTags", function () {
6
+ it("should take twitter handle of author if present", function () {
7
+ const storyPageMockData = {
8
+ data: {
9
+ story: {
10
+ "author-name": "John Doe",
11
+ authors: [
12
+ {
13
+ slug: "john-doe",
14
+ social: {
15
+ twitter: {
16
+ url: "https://twitter.com/JohnDoe123",
17
+ handle: "@JohnDoe123",
18
+ },
19
+ },
20
+ name: "John Doe",
21
+ },
22
+ ],
23
+ },
24
+ },
25
+ };
26
+ const seoConfig = {
27
+ generators: [AuthorTags],
28
+ };
29
+ const string = getSeoMetadata(seoConfig, {}, "story-page", storyPageMockData, {});
30
+ assert.equal('<meta name="twitter:creator" content="@JohnDoe123"/>', string);
31
+ });
32
+
33
+ it("should generate twitter handle from url if twitter handle is not present", function () {
34
+ const storyPageMockData = {
35
+ data: {
36
+ story: {
37
+ "author-name": "John Doe",
38
+ authors: [
39
+ {
40
+ slug: "john-doe",
41
+ social: {
42
+ twitter: {
43
+ url: "https://twitter.com/JohnDoe123",
44
+ handle: "",
45
+ },
46
+ },
47
+ name: "John Doe",
48
+ },
49
+ ],
50
+ },
51
+ },
52
+ };
53
+ const seoConfig = {
54
+ generators: [AuthorTags],
55
+ };
56
+ const string = getSeoMetadata(seoConfig, {}, "story-page", storyPageMockData, {});
57
+ assert.equal('<meta name="twitter:creator" content="@JohnDoe123"/>', string);
58
+ });
59
+
60
+ it("should correctly generate twitter handle from url", function () {
61
+ const storyPageMockData = {
62
+ data: {
63
+ story: {
64
+ "author-name": "John Doe",
65
+ authors: [
66
+ {
67
+ slug: "john-doe",
68
+ social: {
69
+ twitter: {
70
+ url: "https://twitter.com/@JohnDoe123",
71
+ handle: "",
72
+ },
73
+ },
74
+ name: "John Doe",
75
+ },
76
+ ],
77
+ },
78
+ },
79
+ };
80
+ const seoConfig = {
81
+ generators: [AuthorTags],
82
+ };
83
+ const string = getSeoMetadata(seoConfig, {}, "story-page", storyPageMockData, {});
84
+ assert.equal('<meta name="twitter:creator" content="@JohnDoe123"/>', string);
85
+ });
86
+ it("should take author name for twitter:creator if no twitter data about author is present", function () {
87
+ const storyPageMockData = {
88
+ data: {
89
+ story: {
90
+ "author-name": "John Doe",
91
+ authors: [
92
+ {
93
+ slug: "john-doe",
94
+ name: "John Doe",
95
+ },
96
+ ],
97
+ },
98
+ },
99
+ };
100
+ const seoConfig = {
101
+ generators: [AuthorTags],
102
+ };
103
+ const string = getSeoMetadata(seoConfig, {}, "story-page", storyPageMockData, {});
104
+ assert.equal('<meta name="twitter:creator" content="John Doe"/>', string);
105
+ });
106
+ });
@@ -1,33 +1,33 @@
1
1
  const assert = require("assert");
2
- const {generateStaticData, generateStructuredData} = require("..");
2
+ const { generateStaticData, generateStructuredData } = require("..");
3
3
 
4
- describe('Seo Helpers', function() {
5
- describe('Static Data Generator', function() {
6
- it('generates static data', function() {
4
+ describe("Seo Helpers", function () {
5
+ describe("Static Data Generator", function () {
6
+ it("generates static data", function () {
7
7
  const config = {
8
8
  "public-integrations": {
9
- "facebook": {
10
- "app-id": "4"
11
- }
9
+ facebook: {
10
+ "app-id": "4",
11
+ },
12
12
  },
13
13
  "publisher-settings": {
14
- "title": "abc"
14
+ title: "abc",
15
15
  },
16
16
  "sketches-host": "abc.com",
17
17
  "publisher-name": "Abc",
18
18
  "theme-attributes": {
19
- "twitter_app_name_ipad": "twitter-app-name-ipad",
20
- "twitter_app_name_googleplay": "twitter-app-name-googleplay",
21
- "twitter_app_id_googleplay": "twitter-app-id-googleplay",
22
- "twitter_app_name_iphone": "twitter-app-name-iphone",
23
- "twitter_app_id_iphone": "twitter-app-id-phone",
24
- "apple_itunes_app": "apple-itunes-app",
25
- "google_play_app": "google-play-app",
26
- "fb_app_id": "fb-app-id",
27
- "fb_pages": "fb-pages",
28
- "logo": "https://quintype.com/abc.png"
29
- }
30
- }
19
+ twitter_app_name_ipad: "twitter-app-name-ipad",
20
+ twitter_app_name_googleplay: "twitter-app-name-googleplay",
21
+ twitter_app_id_googleplay: "twitter-app-id-googleplay",
22
+ twitter_app_name_iphone: "twitter-app-name-iphone",
23
+ twitter_app_id_iphone: "twitter-app-id-phone",
24
+ apple_itunes_app: "apple-itunes-app",
25
+ google_play_app: "google-play-app",
26
+ fb_app_id: "fb-app-id",
27
+ fb_pages: "fb-pages",
28
+ logo: "https://quintype.com/abc.png",
29
+ },
30
+ };
31
31
  const expectedStaticData = {
32
32
  "twitter:site": "abc",
33
33
  "twitter:domain": "abc.com",
@@ -40,82 +40,93 @@ describe('Seo Helpers', function() {
40
40
  "google-play-app": "google-play-app",
41
41
  "fb:app_id": "4",
42
42
  "fb:pages": "fb-pages",
43
- "og:site_name": "abc"
43
+ "og:site_name": "abc",
44
44
  };
45
45
  const actualStaticData = generateStaticData(config);
46
- assert.deepEqual(actualStaticData, expectedStaticData)
46
+ assert.deepEqual(actualStaticData, expectedStaticData);
47
47
  });
48
-
49
- it('does not crash when the config is empty', function() {
48
+
49
+ it("does not crash when the config is empty", function () {
50
50
  const actualStaticData = generateStaticData({});
51
51
  assert.deepEqual(actualStaticData, {});
52
52
  });
53
-
54
- it('does not crash when theme attributes is null', function() {
53
+
54
+ it("does not crash when theme attributes is null", function () {
55
55
  const config = {
56
56
  "publisher-settings": {
57
- "title": "abc"
57
+ title: "abc",
58
58
  },
59
59
  "sketches-host": "abc.com",
60
60
  "theme-attributes": null,
61
- }
62
-
61
+ };
62
+
63
63
  const expectedStaticData = {
64
64
  "twitter:site": "abc",
65
65
  "twitter:domain": "abc.com",
66
- "og:site_name": "abc"
67
- }
68
-
69
- const actualStaticData = generateStaticData(config)
70
- assert.deepEqual(actualStaticData, expectedStaticData)
71
- })
72
-
73
- it('fallback to publisher-name if title is empty', function() {
66
+ "og:site_name": "abc",
67
+ };
68
+
69
+ const actualStaticData = generateStaticData(config);
70
+ assert.deepEqual(actualStaticData, expectedStaticData);
71
+ });
72
+
73
+ it("fallback to publisher-name if title is empty", function () {
74
74
  const config = {
75
75
  "publisher-name": "Abc",
76
- }
76
+ };
77
77
  const expectedStaticData = {
78
78
  "twitter:site": "Abc",
79
- "og:site_name": "Abc"
80
- }
81
-
82
- const actualStaticData = generateStaticData(config)
83
- assert.deepEqual(actualStaticData, expectedStaticData)
84
- })
85
- })
79
+ "og:site_name": "Abc",
80
+ };
86
81
 
87
- describe('Structured Data Generator', function() {
88
- it('generates structured data', function() {
82
+ const actualStaticData = generateStaticData(config);
83
+ assert.deepEqual(actualStaticData, expectedStaticData);
84
+ });
85
+ });
86
+
87
+ describe("Structured Data Generator", function () {
88
+ it("generates structured data", function () {
89
89
  const config = {
90
90
  "publisher-settings": {
91
- "title": "abc"
91
+ title: "abc",
92
92
  },
93
- 'publisher-name': 'abc',
93
+ "publisher-name": "abc",
94
94
  "sketches-host": "abc.com",
95
95
  "theme-attributes": {
96
- "logo": "https://quintype.com/abc.png?w=300&h=300"
96
+ logo: "https://quintype.com/abc.png?w=300&h=300",
97
97
  },
98
98
  "social-links": {
99
99
  "facebook-url": "https://www.facebook.com/abc/",
100
100
  "google-plus-url": "",
101
101
  "instagram-url": "https://www.instagram.com/abc",
102
- "twitter-url": "https://twitter.com/abc"
102
+ "twitter-url": "https://twitter.com/abc",
103
103
  },
104
- "seo-metadata": [{
105
- "owner-type": "home",
106
- "data": {
107
- "page-title": "Abc",
108
- "description": "News platform",
109
- "keywords": "abc,news,quintype"
110
- }
111
- }]
104
+ "seo-metadata": [
105
+ {
106
+ "owner-type": "home",
107
+ data: {
108
+ "page-title": "Abc",
109
+ description: "News platform",
110
+ keywords: "abc,news,quintype",
111
+ },
112
+ },
113
+ ],
112
114
  };
113
115
  const expectedStructuredData = {
114
116
  organization: {
115
117
  name: "abc",
116
118
  url: "abc.com",
117
- logo: {"@context": "http://schema.org","@type": "ImageObject","author": "abc","contentUrl": "https://quintype.com/abc.png?w=300&h=300","url": "https://quintype.com/abc.png?w=300&h=300","name": "logo","width": "300","height":"300"},
118
- sameAs: ["https://www.facebook.com/abc/", "", "https://www.instagram.com/abc", "https://twitter.com/abc"]
119
+ logo: {
120
+ "@context": "http://schema.org",
121
+ "@type": "ImageObject",
122
+ author: "abc",
123
+ contentUrl: "https://quintype.com/abc.png?w=300&h=300",
124
+ url: "https://quintype.com/abc.png?w=300&h=300",
125
+ name: "logo",
126
+ width: "300",
127
+ height: "300",
128
+ },
129
+ sameAs: ["https://www.facebook.com/abc/", "", "https://www.instagram.com/abc", "https://twitter.com/abc"],
119
130
  },
120
131
  enableNewsArticle: false,
121
132
  storyUrlAsMainEntityUrl: false,
@@ -127,45 +138,56 @@ describe('Seo Helpers', function() {
127
138
  queryinput: "required name=query",
128
139
  name: "Abc",
129
140
  headline: "News platform",
130
- keywords: "abc,news,quintype"
141
+ keywords: "abc,news,quintype",
131
142
  },
132
143
  };
133
- const actualStructuredData = generateStructuredData(config)
134
- assert.deepEqual(actualStructuredData, expectedStructuredData)
144
+ const actualStructuredData = generateStructuredData(config);
145
+ assert.deepEqual(actualStructuredData, expectedStructuredData);
135
146
  });
136
147
 
137
- it('generate mainEntityStructured & NewsArticle data with theme-attributes', function() {
148
+ it("generate mainEntityStructured & NewsArticle data with theme-attributes", function () {
138
149
  const config = {
139
150
  "publisher-settings": {
140
- "title": "abc"
151
+ title: "abc",
141
152
  },
142
- 'publisher-name': 'abc',
153
+ "publisher-name": "abc",
143
154
  "sketches-host": "abc.com",
144
155
  "theme-attributes": {
145
- "logo": "https://quintype.com/abc.png?w=300&h=300",
146
- "structured_data_news_article": true
156
+ logo: "https://quintype.com/abc.png?w=300&h=300",
157
+ structured_data_news_article: true,
147
158
  },
148
159
  "social-links": {
149
160
  "facebook-url": "https://www.facebook.com/abc/",
150
161
  "google-plus-url": "",
151
162
  "instagram-url": "https://www.instagram.com/abc",
152
- "twitter-url": "https://twitter.com/abc"
163
+ "twitter-url": "https://twitter.com/abc",
153
164
  },
154
- "seo-metadata": [{
155
- "owner-type": "home",
156
- "data": {
157
- "page-title": "Abc",
158
- "description": "News platform",
159
- "keywords": "abc,news,quintype"
160
- }
161
- }]
165
+ "seo-metadata": [
166
+ {
167
+ "owner-type": "home",
168
+ data: {
169
+ "page-title": "Abc",
170
+ description: "News platform",
171
+ keywords: "abc,news,quintype",
172
+ },
173
+ },
174
+ ],
162
175
  };
163
176
  const expectedStructuredData = {
164
177
  organization: {
165
178
  name: "abc",
166
179
  url: "abc.com",
167
- logo: {"@context": "http://schema.org","@type": "ImageObject","author": "abc","contentUrl": "https://quintype.com/abc.png?w=300&h=300","url": "https://quintype.com/abc.png?w=300&h=300","name": "logo","width": "300","height":"300"},
168
- sameAs: ["https://www.facebook.com/abc/", "", "https://www.instagram.com/abc", "https://twitter.com/abc"]
180
+ logo: {
181
+ "@context": "http://schema.org",
182
+ "@type": "ImageObject",
183
+ author: "abc",
184
+ contentUrl: "https://quintype.com/abc.png?w=300&h=300",
185
+ url: "https://quintype.com/abc.png?w=300&h=300",
186
+ name: "logo",
187
+ width: "300",
188
+ height: "300",
189
+ },
190
+ sameAs: ["https://www.facebook.com/abc/", "", "https://www.instagram.com/abc", "https://twitter.com/abc"],
169
191
  },
170
192
  enableNewsArticle: true,
171
193
  storyUrlAsMainEntityUrl: true,
@@ -177,46 +199,57 @@ describe('Seo Helpers', function() {
177
199
  queryinput: "required name=query",
178
200
  name: "Abc",
179
201
  headline: "News platform",
180
- keywords: "abc,news,quintype"
202
+ keywords: "abc,news,quintype",
181
203
  },
182
204
  };
183
- const actualStructuredData = generateStructuredData(config)
184
- assert.deepEqual(actualStructuredData, expectedStructuredData)
205
+ const actualStructuredData = generateStructuredData(config);
206
+ assert.deepEqual(actualStructuredData, expectedStructuredData);
185
207
  });
186
-
187
- it('does not crash when the config is empty', function() {
208
+
209
+ it("does not crash when the config is empty", function () {
188
210
  const expectedStructuredData = {};
189
211
  const actualStructuredData = generateStructuredData({});
190
212
  assert.deepEqual(actualStructuredData, expectedStructuredData);
191
213
  });
192
-
193
- it('does not crash when social links is null', function() {
214
+
215
+ it("does not crash when social links is null", function () {
194
216
  const config = {
195
217
  "publisher-settings": {
196
- "title": "abc"
218
+ title: "abc",
197
219
  },
198
220
  "sketches-host": "abc.com",
199
221
  "publisher-name": "Abc",
200
222
  "theme-attributes": {
201
- "logo": "https://quintype.com/abc.png"
223
+ logo: "https://quintype.com/abc.png",
202
224
  },
203
225
  "social-links": null,
204
- "seo-metadata": [{
205
- "owner-type": "home",
206
- "data": {
207
- "page-title": "Abc",
208
- "description": "News platform",
209
- "keywords": "abc,news,quintype"
210
- }
211
- }]
226
+ "seo-metadata": [
227
+ {
228
+ "owner-type": "home",
229
+ data: {
230
+ "page-title": "Abc",
231
+ description: "News platform",
232
+ keywords: "abc,news,quintype",
233
+ },
234
+ },
235
+ ],
212
236
  };
213
-
237
+
214
238
  const expectedStructuredData = {
215
239
  organization: {
216
240
  name: "abc",
217
241
  url: "abc.com",
218
- logo: {"@context": "http://schema.org","@type": "ImageObject","author": "Abc","contentUrl": "https://quintype.com/abc.png","url": "https://quintype.com/abc.png","name": "logo","width": "","height":""},
219
- sameAs: []
242
+ logo: {
243
+ "@context": "http://schema.org",
244
+ "@type": "ImageObject",
245
+ author: "Abc",
246
+ contentUrl: "https://quintype.com/abc.png",
247
+ url: "https://quintype.com/abc.png",
248
+ name: "logo",
249
+ width: "",
250
+ height: "",
251
+ },
252
+ sameAs: [],
220
253
  },
221
254
  storyUrlAsMainEntityUrl: false,
222
255
  enableNewsArticle: false,
@@ -228,18 +261,18 @@ describe('Seo Helpers', function() {
228
261
  queryinput: "required name=query",
229
262
  name: "Abc",
230
263
  headline: "News platform",
231
- keywords: "abc,news,quintype"
264
+ keywords: "abc,news,quintype",
232
265
  },
233
266
  };
234
-
267
+
235
268
  const actualStructuredData = generateStructuredData(config);
236
- assert.deepEqual(actualStructuredData, expectedStructuredData)
269
+ assert.deepEqual(actualStructuredData, expectedStructuredData);
237
270
  });
238
-
239
- it('does not crash when theme attributes is null', function() {
271
+
272
+ it("does not crash when theme attributes is null", function () {
240
273
  const config = {
241
274
  "publisher-settings": {
242
- "title": "abc"
275
+ title: "abc",
243
276
  },
244
277
  "sketches-host": "abc.com",
245
278
  "publisher-name": "Abc",
@@ -248,19 +281,70 @@ describe('Seo Helpers', function() {
248
281
  "facebook-url": "https://www.facebook.com/abc/",
249
282
  "google-plus-url": "",
250
283
  "instagram-url": "https://www.instagram.com/abc",
251
- "twitter-url": "https://twitter.com/abc"
284
+ "twitter-url": "https://twitter.com/abc",
252
285
  },
253
- "seo-metadata": [{
254
- "owner-type": "home",
255
- "data": {
256
- "page-title": "Abc",
257
- "description": "News platform",
258
- "keywords": "abc,news,quintype"
259
- }
260
- }]
286
+ "seo-metadata": [
287
+ {
288
+ "owner-type": "home",
289
+ data: {
290
+ "page-title": "Abc",
291
+ description: "News platform",
292
+ keywords: "abc,news,quintype",
293
+ },
294
+ },
295
+ ],
261
296
  };
262
297
  const actualStructuredData = generateStructuredData(config);
263
298
  assert.deepEqual(actualStructuredData, {});
264
- })
265
- })
266
- });
299
+ });
300
+
301
+ it("takes the site twitter handle for twitter:site if present", function () {
302
+ const config = {
303
+ "publisher-settings": {
304
+ title: "abc",
305
+ },
306
+ "sketches-host": "abc.com",
307
+ "publisher-name": "Abc",
308
+ "theme-attributes": null,
309
+ "social-links": {
310
+ "twitter-url": "https://twitter.com/abc",
311
+ },
312
+ "seo-metadata": [
313
+ {
314
+ "owner-type": "home",
315
+ data: {
316
+ "page-title": "Abc",
317
+ description: "News platform",
318
+ keywords: "abc,news,quintype",
319
+ },
320
+ },
321
+ ],
322
+ };
323
+ const actualStaticData = generateStaticData(config);
324
+ assert.strictEqual(actualStaticData["twitter:site"], "@abc");
325
+ });
326
+
327
+ it("takes the title for twitter:site site twitter handle not present", function () {
328
+ const config = {
329
+ "publisher-settings": {
330
+ title: "this is the site title",
331
+ },
332
+ "sketches-host": "abc.com",
333
+ "publisher-name": "Abc",
334
+ "theme-attributes": null,
335
+ "seo-metadata": [
336
+ {
337
+ "owner-type": "home",
338
+ data: {
339
+ "page-title": "Abc",
340
+ description: "News platform",
341
+ keywords: "abc,news,quintype",
342
+ },
343
+ },
344
+ ],
345
+ };
346
+ const actualStaticData = generateStaticData(config);
347
+ assert.strictEqual(actualStaticData["twitter:site"], "this is the site title");
348
+ });
349
+ });
350
+ });