@jam-comments/server-utilities 4.0.2 → 4.2.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/dist/cjs/injectSchema.js +19 -0
- package/dist/cjs/injectSchema.test.js +63 -0
- package/dist/cjs/markupFetcher.js +12 -2
- package/dist/cjs/markupFetcher.test.js +91 -0
- package/dist/cjs/utils.js +42 -1
- package/dist/esm/injectSchema.js +15 -0
- package/dist/esm/injectSchema.test.js +61 -0
- package/dist/esm/markupFetcher.js +13 -3
- package/dist/esm/markupFetcher.test.js +68 -0
- package/dist/esm/utils.js +39 -0
- package/dist/types/injectSchema.d.ts +1 -0
- package/dist/types/injectSchema.test.d.ts +1 -0
- package/dist/types/markupFetcher.d.ts +2 -1
- package/dist/types/utils.d.ts +2 -0
- package/package.json +6 -6
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.injectSchema = void 0;
|
|
4
|
+
const utils_1 = require("./utils");
|
|
5
|
+
function injectSchema(markup, schema) {
|
|
6
|
+
const commentSchema = markup.match(/<div jc-data="jcSchema" data-schema="(.*)"><\/div>/)?.[1];
|
|
7
|
+
if (!commentSchema) {
|
|
8
|
+
return markup;
|
|
9
|
+
}
|
|
10
|
+
const json = (0, utils_1.parseJson)((0, utils_1.unescapeHTML)(commentSchema));
|
|
11
|
+
if (!json) {
|
|
12
|
+
return markup;
|
|
13
|
+
}
|
|
14
|
+
schema.comment = json;
|
|
15
|
+
return markup
|
|
16
|
+
.replace("<!-- JC:SCHEMA -->", `<script type="application/ld+json">${JSON.stringify(schema)}</script>`)
|
|
17
|
+
.replace(/<div jc-data="jcSchema" data-schema=".*"><\/div>(?:\n+)?/, "");
|
|
18
|
+
}
|
|
19
|
+
exports.injectSchema = injectSchema;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const injectSchema_1 = require("./injectSchema");
|
|
5
|
+
(0, vitest_1.it)("injects schema into markup", () => {
|
|
6
|
+
const markup = `
|
|
7
|
+
<div id="jcComments">
|
|
8
|
+
<div jc-data="jcSchema" data-schema="[{"@context":"https:\/\/schema.org","@type":"Comment","name":"Alexis","dateCreated":"2022-10-28T10:41:49+00:00","url":"https:\/\/macarthur.me\/posts\/dynamic-routing#comment-133"}]"></div>
|
|
9
|
+
|
|
10
|
+
<!-- JC:SCHEMA -->
|
|
11
|
+
</div>`;
|
|
12
|
+
const blogPostSchema = {
|
|
13
|
+
"@context": "http://schema.org",
|
|
14
|
+
"@type": "BlogPosting",
|
|
15
|
+
};
|
|
16
|
+
const result = (0, injectSchema_1.injectSchema)(markup, blogPostSchema);
|
|
17
|
+
(0, vitest_1.expect)(result).toEqual(`
|
|
18
|
+
<div id="jcComments">
|
|
19
|
+
<script type="application/ld+json">{"@context":"http://schema.org","@type":"BlogPosting","comment":[{"@context":"https://schema.org","@type":"Comment","name":"Alexis","dateCreated":"2022-10-28T10:41:49+00:00","url":"https://macarthur.me/posts/dynamic-routing#comment-133"}]}</script>
|
|
20
|
+
</div>`);
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)("returns markup if schema is not found", () => {
|
|
23
|
+
const markup = `
|
|
24
|
+
<div id="jcComments">
|
|
25
|
+
<!-- JC:SCHEMA -->
|
|
26
|
+
</div>`;
|
|
27
|
+
const blogPostSchema = {
|
|
28
|
+
"@context": "http://schema.org",
|
|
29
|
+
"@type": "BlogPosting",
|
|
30
|
+
};
|
|
31
|
+
const result = (0, injectSchema_1.injectSchema)(markup, blogPostSchema);
|
|
32
|
+
(0, vitest_1.expect)(result).toEqual(markup);
|
|
33
|
+
});
|
|
34
|
+
(0, vitest_1.it)("returns markup if schema is not valid JSON", () => {
|
|
35
|
+
const markup = `
|
|
36
|
+
<div id="jcComments">
|
|
37
|
+
<div jc-data="jcSchema" data-schema="not-valid-json"></div>
|
|
38
|
+
<!-- JC:SCHEMA -->
|
|
39
|
+
</div>`;
|
|
40
|
+
const blogPostSchema = {
|
|
41
|
+
"@context": "http://schema.org",
|
|
42
|
+
"@type": "BlogPosting",
|
|
43
|
+
};
|
|
44
|
+
const result = (0, injectSchema_1.injectSchema)(markup, blogPostSchema);
|
|
45
|
+
(0, vitest_1.expect)(result).toEqual(markup);
|
|
46
|
+
});
|
|
47
|
+
(0, vitest_1.it)("injects even when JSON is not HTML-encoded", () => {
|
|
48
|
+
const markup = `
|
|
49
|
+
<div id="jcComments">
|
|
50
|
+
<div jc-data="jcSchema" data-schema="[{"@context":"https://schema.org","@type":"Comment","name":"Alexis","dateCreated":"2022-10-28T10:41:49+00:00","url":"https://macarthur.me/posts/dynamic-routing#comment-133"}]"></div>
|
|
51
|
+
|
|
52
|
+
<!-- JC:SCHEMA -->
|
|
53
|
+
</div>`;
|
|
54
|
+
const blogPostSchema = {
|
|
55
|
+
"@context": "http://schema.org",
|
|
56
|
+
"@type": "BlogPosting",
|
|
57
|
+
};
|
|
58
|
+
const result = (0, injectSchema_1.injectSchema)(markup, blogPostSchema);
|
|
59
|
+
(0, vitest_1.expect)(result).toEqual(`
|
|
60
|
+
<div id="jcComments">
|
|
61
|
+
<script type="application/ld+json">{"@context":"http://schema.org","@type":"BlogPosting","comment":[{"@context":"https://schema.org","@type":"Comment","name":"Alexis","dateCreated":"2022-10-28T10:41:49+00:00","url":"https://macarthur.me/posts/dynamic-routing#comment-133"}]}</script>
|
|
62
|
+
</div>`);
|
|
63
|
+
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.markupFetcher = void 0;
|
|
4
|
+
const injectSchema_1 = require("./injectSchema");
|
|
4
5
|
const utils_1 = require("./utils");
|
|
5
6
|
const markupFetcher = (platform, fetchImplementation = fetch) => {
|
|
6
|
-
return async ({ tz = undefined, path, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = (0, utils_1.getEnvironment)(), }) => {
|
|
7
|
+
return async ({ tz = undefined, path, domain, apiKey, schema, baseUrl = "https://go.jamcomments.com", environment = (0, utils_1.getEnvironment)(), }) => {
|
|
7
8
|
const trimmedTimezone = tz?.trim();
|
|
8
9
|
if (trimmedTimezone && !(0, utils_1.isValidTimezone)(trimmedTimezone)) {
|
|
9
10
|
throw new Error(`The timezone passed to JamComments is invalid: ${trimmedTimezone}`);
|
|
@@ -33,7 +34,16 @@ const markupFetcher = (platform, fetchImplementation = fetch) => {
|
|
|
33
34
|
if (!response.ok) {
|
|
34
35
|
throw new Error(`JamComments request failed! Status code: ${response.status}, message: ${response.statusText}, request URL: ${requestUrl}`);
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
+
const markup = await response.text();
|
|
38
|
+
if (schema) {
|
|
39
|
+
const preparedSchema = typeof schema !== "string" ? JSON.stringify(schema) : schema;
|
|
40
|
+
const parsedSchema = (0, utils_1.parseJson)(preparedSchema);
|
|
41
|
+
if (!parsedSchema) {
|
|
42
|
+
return markup;
|
|
43
|
+
}
|
|
44
|
+
return (0, injectSchema_1.injectSchema)(markup, parsedSchema);
|
|
45
|
+
}
|
|
46
|
+
return markup;
|
|
37
47
|
};
|
|
38
48
|
};
|
|
39
49
|
exports.markupFetcher = markupFetcher;
|
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
26
|
const vitest_1 = require("vitest");
|
|
27
|
+
const injectSchema = __importStar(require("./injectSchema"));
|
|
4
28
|
const markupFetcher_1 = require("./markupFetcher");
|
|
5
29
|
(0, vitest_1.describe)("markupFetcher", () => {
|
|
6
30
|
(0, vitest_1.it)("constructs fetch request correctly", async () => {
|
|
31
|
+
const injectSchemaSpy = vitest_1.vi.spyOn(injectSchema, "injectSchema");
|
|
7
32
|
const fetchMock = vitest_1.vi.fn().mockImplementation(() => {
|
|
8
33
|
return {
|
|
9
34
|
status: 200,
|
|
@@ -18,6 +43,7 @@ const markupFetcher_1 = require("./markupFetcher");
|
|
|
18
43
|
apiKey: "123abc",
|
|
19
44
|
environment: "production",
|
|
20
45
|
});
|
|
46
|
+
(0, vitest_1.expect)(injectSchemaSpy).not.toHaveBeenCalled();
|
|
21
47
|
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", vitest_1.expect.objectContaining({
|
|
22
48
|
headers: vitest_1.expect.objectContaining({
|
|
23
49
|
Accept: "application/json",
|
|
@@ -185,3 +211,68 @@ const markupFetcher_1 = require("./markupFetcher");
|
|
|
185
211
|
});
|
|
186
212
|
});
|
|
187
213
|
});
|
|
214
|
+
(0, vitest_1.describe)("passing schema", function () {
|
|
215
|
+
(0, vitest_1.it)("first stringifies schema if given an object", async () => {
|
|
216
|
+
const injectSchemaSpy = vitest_1.vi.spyOn(injectSchema, "injectSchema");
|
|
217
|
+
const fetchMock = vitest_1.vi.fn().mockImplementation(() => {
|
|
218
|
+
return {
|
|
219
|
+
status: 200,
|
|
220
|
+
ok: true,
|
|
221
|
+
text: () => "results!",
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
|
|
225
|
+
const result = await fetcher({
|
|
226
|
+
path: "/test",
|
|
227
|
+
domain: "test.com",
|
|
228
|
+
apiKey: "123abc",
|
|
229
|
+
schema: { foo: "bar" },
|
|
230
|
+
environment: "production",
|
|
231
|
+
});
|
|
232
|
+
(0, vitest_1.expect)(injectSchemaSpy).toHaveBeenCalledWith("results!", { foo: "bar" });
|
|
233
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", vitest_1.expect.anything());
|
|
234
|
+
(0, vitest_1.expect)(result).toEqual("results!");
|
|
235
|
+
});
|
|
236
|
+
(0, vitest_1.it)("does not stringify schema if given a string", async () => {
|
|
237
|
+
const injectSchemaSpy = vitest_1.vi.spyOn(injectSchema, "injectSchema");
|
|
238
|
+
const fetchMock = vitest_1.vi.fn().mockImplementation(() => {
|
|
239
|
+
return {
|
|
240
|
+
status: 200,
|
|
241
|
+
ok: true,
|
|
242
|
+
text: () => "results!",
|
|
243
|
+
};
|
|
244
|
+
});
|
|
245
|
+
const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
|
|
246
|
+
const result = await fetcher({
|
|
247
|
+
path: "/test",
|
|
248
|
+
domain: "test.com",
|
|
249
|
+
apiKey: "123abc",
|
|
250
|
+
schema: '{"foo":"bar"}',
|
|
251
|
+
environment: "production",
|
|
252
|
+
});
|
|
253
|
+
(0, vitest_1.expect)(injectSchemaSpy).toHaveBeenCalledWith("results!", { foo: "bar" });
|
|
254
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", vitest_1.expect.anything());
|
|
255
|
+
(0, vitest_1.expect)(result).toEqual("results!");
|
|
256
|
+
});
|
|
257
|
+
(0, vitest_1.it)("returns markup if invalid json is provided", async () => {
|
|
258
|
+
const injectSchemaSpy = vitest_1.vi.spyOn(injectSchema, "injectSchema");
|
|
259
|
+
const fetchMock = vitest_1.vi.fn().mockImplementation(() => {
|
|
260
|
+
return {
|
|
261
|
+
status: 200,
|
|
262
|
+
ok: true,
|
|
263
|
+
text: () => "results!",
|
|
264
|
+
};
|
|
265
|
+
});
|
|
266
|
+
const fetcher = (0, markupFetcher_1.markupFetcher)("test", fetchMock);
|
|
267
|
+
const result = await fetcher({
|
|
268
|
+
path: "/test",
|
|
269
|
+
domain: "test.com",
|
|
270
|
+
apiKey: "123abc",
|
|
271
|
+
schema: "not-valid-json",
|
|
272
|
+
environment: "production",
|
|
273
|
+
});
|
|
274
|
+
(0, vitest_1.expect)(injectSchemaSpy).not.toHaveBeenCalled();
|
|
275
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", vitest_1.expect.anything());
|
|
276
|
+
(0, vitest_1.expect)(result).toEqual("results!");
|
|
277
|
+
});
|
|
278
|
+
});
|
package/dist/cjs/utils.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.reAppendMarkup = exports.getEnvironment = exports.isValidTimezone = void 0;
|
|
3
|
+
exports.unescapeHTML = exports.parseJson = exports.reAppendMarkup = exports.getEnvironment = exports.isValidTimezone = void 0;
|
|
4
4
|
function isValidTimezone(tz) {
|
|
5
5
|
try {
|
|
6
6
|
Intl.DateTimeFormat(undefined, { timeZone: tz });
|
|
@@ -28,3 +28,44 @@ function reAppendMarkup(element, markup) {
|
|
|
28
28
|
element.append(documentFragment);
|
|
29
29
|
}
|
|
30
30
|
exports.reAppendMarkup = reAppendMarkup;
|
|
31
|
+
function parseJson(json) {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(json);
|
|
34
|
+
}
|
|
35
|
+
catch (ex) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.parseJson = parseJson;
|
|
40
|
+
var htmlEntities = {
|
|
41
|
+
nbsp: " ",
|
|
42
|
+
cent: "¢",
|
|
43
|
+
pound: "£",
|
|
44
|
+
yen: "¥",
|
|
45
|
+
euro: "€",
|
|
46
|
+
copy: "©",
|
|
47
|
+
reg: "®",
|
|
48
|
+
lt: "<",
|
|
49
|
+
gt: ">",
|
|
50
|
+
quot: '"',
|
|
51
|
+
amp: "&",
|
|
52
|
+
apos: "'",
|
|
53
|
+
};
|
|
54
|
+
function unescapeHTML(str) {
|
|
55
|
+
return str.replace(/\&([^;]+);/g, function (entity, entityCode) {
|
|
56
|
+
var match;
|
|
57
|
+
if (entityCode in htmlEntities) {
|
|
58
|
+
return htmlEntities[entityCode];
|
|
59
|
+
}
|
|
60
|
+
else if ((match = entityCode.match(/^#x([\da-fA-F]+)$/))) {
|
|
61
|
+
return String.fromCharCode(parseInt(match[1], 16));
|
|
62
|
+
}
|
|
63
|
+
else if ((match = entityCode.match(/^#(\d+)$/))) {
|
|
64
|
+
return String.fromCharCode(~~match[1]);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
return entity;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
exports.unescapeHTML = unescapeHTML;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { parseJson, unescapeHTML } from "./utils";
|
|
2
|
+
export function injectSchema(markup, schema) {
|
|
3
|
+
const commentSchema = markup.match(/<div jc-data="jcSchema" data-schema="(.*)"><\/div>/)?.[1];
|
|
4
|
+
if (!commentSchema) {
|
|
5
|
+
return markup;
|
|
6
|
+
}
|
|
7
|
+
const json = parseJson(unescapeHTML(commentSchema));
|
|
8
|
+
if (!json) {
|
|
9
|
+
return markup;
|
|
10
|
+
}
|
|
11
|
+
schema.comment = json;
|
|
12
|
+
return markup
|
|
13
|
+
.replace("<!-- JC:SCHEMA -->", `<script type="application/ld+json">${JSON.stringify(schema)}</script>`)
|
|
14
|
+
.replace(/<div jc-data="jcSchema" data-schema=".*"><\/div>(?:\n+)?/, "");
|
|
15
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { expect, it } from "vitest";
|
|
2
|
+
import { injectSchema } from "./injectSchema";
|
|
3
|
+
it("injects schema into markup", () => {
|
|
4
|
+
const markup = `
|
|
5
|
+
<div id="jcComments">
|
|
6
|
+
<div jc-data="jcSchema" data-schema="[{"@context":"https:\/\/schema.org","@type":"Comment","name":"Alexis","dateCreated":"2022-10-28T10:41:49+00:00","url":"https:\/\/macarthur.me\/posts\/dynamic-routing#comment-133"}]"></div>
|
|
7
|
+
|
|
8
|
+
<!-- JC:SCHEMA -->
|
|
9
|
+
</div>`;
|
|
10
|
+
const blogPostSchema = {
|
|
11
|
+
"@context": "http://schema.org",
|
|
12
|
+
"@type": "BlogPosting",
|
|
13
|
+
};
|
|
14
|
+
const result = injectSchema(markup, blogPostSchema);
|
|
15
|
+
expect(result).toEqual(`
|
|
16
|
+
<div id="jcComments">
|
|
17
|
+
<script type="application/ld+json">{"@context":"http://schema.org","@type":"BlogPosting","comment":[{"@context":"https://schema.org","@type":"Comment","name":"Alexis","dateCreated":"2022-10-28T10:41:49+00:00","url":"https://macarthur.me/posts/dynamic-routing#comment-133"}]}</script>
|
|
18
|
+
</div>`);
|
|
19
|
+
});
|
|
20
|
+
it("returns markup if schema is not found", () => {
|
|
21
|
+
const markup = `
|
|
22
|
+
<div id="jcComments">
|
|
23
|
+
<!-- JC:SCHEMA -->
|
|
24
|
+
</div>`;
|
|
25
|
+
const blogPostSchema = {
|
|
26
|
+
"@context": "http://schema.org",
|
|
27
|
+
"@type": "BlogPosting",
|
|
28
|
+
};
|
|
29
|
+
const result = injectSchema(markup, blogPostSchema);
|
|
30
|
+
expect(result).toEqual(markup);
|
|
31
|
+
});
|
|
32
|
+
it("returns markup if schema is not valid JSON", () => {
|
|
33
|
+
const markup = `
|
|
34
|
+
<div id="jcComments">
|
|
35
|
+
<div jc-data="jcSchema" data-schema="not-valid-json"></div>
|
|
36
|
+
<!-- JC:SCHEMA -->
|
|
37
|
+
</div>`;
|
|
38
|
+
const blogPostSchema = {
|
|
39
|
+
"@context": "http://schema.org",
|
|
40
|
+
"@type": "BlogPosting",
|
|
41
|
+
};
|
|
42
|
+
const result = injectSchema(markup, blogPostSchema);
|
|
43
|
+
expect(result).toEqual(markup);
|
|
44
|
+
});
|
|
45
|
+
it("injects even when JSON is not HTML-encoded", () => {
|
|
46
|
+
const markup = `
|
|
47
|
+
<div id="jcComments">
|
|
48
|
+
<div jc-data="jcSchema" data-schema="[{"@context":"https://schema.org","@type":"Comment","name":"Alexis","dateCreated":"2022-10-28T10:41:49+00:00","url":"https://macarthur.me/posts/dynamic-routing#comment-133"}]"></div>
|
|
49
|
+
|
|
50
|
+
<!-- JC:SCHEMA -->
|
|
51
|
+
</div>`;
|
|
52
|
+
const blogPostSchema = {
|
|
53
|
+
"@context": "http://schema.org",
|
|
54
|
+
"@type": "BlogPosting",
|
|
55
|
+
};
|
|
56
|
+
const result = injectSchema(markup, blogPostSchema);
|
|
57
|
+
expect(result).toEqual(`
|
|
58
|
+
<div id="jcComments">
|
|
59
|
+
<script type="application/ld+json">{"@context":"http://schema.org","@type":"BlogPosting","comment":[{"@context":"https://schema.org","@type":"Comment","name":"Alexis","dateCreated":"2022-10-28T10:41:49+00:00","url":"https://macarthur.me/posts/dynamic-routing#comment-133"}]}</script>
|
|
60
|
+
</div>`);
|
|
61
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { injectSchema } from "./injectSchema";
|
|
2
|
+
import { getEnvironment, isValidTimezone, parseJson } from "./utils";
|
|
2
3
|
export const markupFetcher = (platform, fetchImplementation = fetch) => {
|
|
3
|
-
return async ({ tz = undefined, path, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }) => {
|
|
4
|
+
return async ({ tz = undefined, path, domain, apiKey, schema, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }) => {
|
|
4
5
|
const trimmedTimezone = tz?.trim();
|
|
5
6
|
if (trimmedTimezone && !isValidTimezone(trimmedTimezone)) {
|
|
6
7
|
throw new Error(`The timezone passed to JamComments is invalid: ${trimmedTimezone}`);
|
|
@@ -30,6 +31,15 @@ export const markupFetcher = (platform, fetchImplementation = fetch) => {
|
|
|
30
31
|
if (!response.ok) {
|
|
31
32
|
throw new Error(`JamComments request failed! Status code: ${response.status}, message: ${response.statusText}, request URL: ${requestUrl}`);
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
+
const markup = await response.text();
|
|
35
|
+
if (schema) {
|
|
36
|
+
const preparedSchema = typeof schema !== "string" ? JSON.stringify(schema) : schema;
|
|
37
|
+
const parsedSchema = parseJson(preparedSchema);
|
|
38
|
+
if (!parsedSchema) {
|
|
39
|
+
return markup;
|
|
40
|
+
}
|
|
41
|
+
return injectSchema(markup, parsedSchema);
|
|
42
|
+
}
|
|
43
|
+
return markup;
|
|
34
44
|
};
|
|
35
45
|
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import * as injectSchema from "./injectSchema";
|
|
2
3
|
import { markupFetcher } from "./markupFetcher";
|
|
3
4
|
describe("markupFetcher", () => {
|
|
4
5
|
it("constructs fetch request correctly", async () => {
|
|
6
|
+
const injectSchemaSpy = vi.spyOn(injectSchema, "injectSchema");
|
|
5
7
|
const fetchMock = vi.fn().mockImplementation(() => {
|
|
6
8
|
return {
|
|
7
9
|
status: 200,
|
|
@@ -16,6 +18,7 @@ describe("markupFetcher", () => {
|
|
|
16
18
|
apiKey: "123abc",
|
|
17
19
|
environment: "production",
|
|
18
20
|
});
|
|
21
|
+
expect(injectSchemaSpy).not.toHaveBeenCalled();
|
|
19
22
|
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.objectContaining({
|
|
20
23
|
headers: expect.objectContaining({
|
|
21
24
|
Accept: "application/json",
|
|
@@ -183,3 +186,68 @@ describe("markupFetcher", () => {
|
|
|
183
186
|
});
|
|
184
187
|
});
|
|
185
188
|
});
|
|
189
|
+
describe("passing schema", function () {
|
|
190
|
+
it("first stringifies schema if given an object", async () => {
|
|
191
|
+
const injectSchemaSpy = vi.spyOn(injectSchema, "injectSchema");
|
|
192
|
+
const fetchMock = vi.fn().mockImplementation(() => {
|
|
193
|
+
return {
|
|
194
|
+
status: 200,
|
|
195
|
+
ok: true,
|
|
196
|
+
text: () => "results!",
|
|
197
|
+
};
|
|
198
|
+
});
|
|
199
|
+
const fetcher = markupFetcher("test", fetchMock);
|
|
200
|
+
const result = await fetcher({
|
|
201
|
+
path: "/test",
|
|
202
|
+
domain: "test.com",
|
|
203
|
+
apiKey: "123abc",
|
|
204
|
+
schema: { foo: "bar" },
|
|
205
|
+
environment: "production",
|
|
206
|
+
});
|
|
207
|
+
expect(injectSchemaSpy).toHaveBeenCalledWith("results!", { foo: "bar" });
|
|
208
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.anything());
|
|
209
|
+
expect(result).toEqual("results!");
|
|
210
|
+
});
|
|
211
|
+
it("does not stringify schema if given a string", async () => {
|
|
212
|
+
const injectSchemaSpy = vi.spyOn(injectSchema, "injectSchema");
|
|
213
|
+
const fetchMock = vi.fn().mockImplementation(() => {
|
|
214
|
+
return {
|
|
215
|
+
status: 200,
|
|
216
|
+
ok: true,
|
|
217
|
+
text: () => "results!",
|
|
218
|
+
};
|
|
219
|
+
});
|
|
220
|
+
const fetcher = markupFetcher("test", fetchMock);
|
|
221
|
+
const result = await fetcher({
|
|
222
|
+
path: "/test",
|
|
223
|
+
domain: "test.com",
|
|
224
|
+
apiKey: "123abc",
|
|
225
|
+
schema: '{"foo":"bar"}',
|
|
226
|
+
environment: "production",
|
|
227
|
+
});
|
|
228
|
+
expect(injectSchemaSpy).toHaveBeenCalledWith("results!", { foo: "bar" });
|
|
229
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.anything());
|
|
230
|
+
expect(result).toEqual("results!");
|
|
231
|
+
});
|
|
232
|
+
it("returns markup if invalid json is provided", async () => {
|
|
233
|
+
const injectSchemaSpy = vi.spyOn(injectSchema, "injectSchema");
|
|
234
|
+
const fetchMock = vi.fn().mockImplementation(() => {
|
|
235
|
+
return {
|
|
236
|
+
status: 200,
|
|
237
|
+
ok: true,
|
|
238
|
+
text: () => "results!",
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
const fetcher = markupFetcher("test", fetchMock);
|
|
242
|
+
const result = await fetcher({
|
|
243
|
+
path: "/test",
|
|
244
|
+
domain: "test.com",
|
|
245
|
+
apiKey: "123abc",
|
|
246
|
+
schema: "not-valid-json",
|
|
247
|
+
environment: "production",
|
|
248
|
+
});
|
|
249
|
+
expect(injectSchemaSpy).not.toHaveBeenCalled();
|
|
250
|
+
expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.anything());
|
|
251
|
+
expect(result).toEqual("results!");
|
|
252
|
+
});
|
|
253
|
+
});
|
package/dist/esm/utils.js
CHANGED
|
@@ -22,3 +22,42 @@ export function reAppendMarkup(element, markup) {
|
|
|
22
22
|
element.innerHTML = "";
|
|
23
23
|
element.append(documentFragment);
|
|
24
24
|
}
|
|
25
|
+
export function parseJson(json) {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(json);
|
|
28
|
+
}
|
|
29
|
+
catch (ex) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
var htmlEntities = {
|
|
34
|
+
nbsp: " ",
|
|
35
|
+
cent: "¢",
|
|
36
|
+
pound: "£",
|
|
37
|
+
yen: "¥",
|
|
38
|
+
euro: "€",
|
|
39
|
+
copy: "©",
|
|
40
|
+
reg: "®",
|
|
41
|
+
lt: "<",
|
|
42
|
+
gt: ">",
|
|
43
|
+
quot: '"',
|
|
44
|
+
amp: "&",
|
|
45
|
+
apos: "'",
|
|
46
|
+
};
|
|
47
|
+
export function unescapeHTML(str) {
|
|
48
|
+
return str.replace(/\&([^;]+);/g, function (entity, entityCode) {
|
|
49
|
+
var match;
|
|
50
|
+
if (entityCode in htmlEntities) {
|
|
51
|
+
return htmlEntities[entityCode];
|
|
52
|
+
}
|
|
53
|
+
else if ((match = entityCode.match(/^#x([\da-fA-F]+)$/))) {
|
|
54
|
+
return String.fromCharCode(parseInt(match[1], 16));
|
|
55
|
+
}
|
|
56
|
+
else if ((match = entityCode.match(/^#(\d+)$/))) {
|
|
57
|
+
return String.fromCharCode(~~match[1]);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
return entity;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function injectSchema(markup: string, schema: Record<string, any>): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,8 +2,9 @@ export interface IFetchData {
|
|
|
2
2
|
path: string;
|
|
3
3
|
domain: string;
|
|
4
4
|
apiKey: string;
|
|
5
|
+
schema?: string | object;
|
|
5
6
|
tz?: string;
|
|
6
7
|
baseUrl?: string;
|
|
7
8
|
environment?: string;
|
|
8
9
|
}
|
|
9
|
-
export declare const markupFetcher: (platform: string, fetchImplementation?: typeof fetch) => (args: IFetchData) => Promise<string
|
|
10
|
+
export declare const markupFetcher: (platform: string, fetchImplementation?: typeof fetch) => ((args: IFetchData) => Promise<string>);
|
package/dist/types/utils.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export declare function isValidTimezone(tz: string): boolean;
|
|
2
2
|
export declare function getEnvironment(): string;
|
|
3
3
|
export declare function reAppendMarkup(element: HTMLElement, markup: string): void;
|
|
4
|
+
export declare function parseJson(json: string): any;
|
|
5
|
+
export declare function unescapeHTML(str: any): any;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jam-comments/server-utilities",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Various JavaScript utilities for JamComments.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"types": "dist/types/index.d.ts",
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"homepage": "https://jamcomments.com",
|
|
22
22
|
"license": "GPL-2.0",
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@types/node": "^20.
|
|
25
|
-
"prettier": "^3.
|
|
26
|
-
"typescript": "^5.
|
|
27
|
-
"vite": "^
|
|
28
|
-
"vitest": "^
|
|
24
|
+
"@types/node": "^20.12.11",
|
|
25
|
+
"prettier": "^3.2.5",
|
|
26
|
+
"typescript": "^5.4.5",
|
|
27
|
+
"vite": "^5.2.11",
|
|
28
|
+
"vitest": "^1.6.0"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|