@jam-comments/server-utilities 4.2.0 → 4.3.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.
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const vitest_1 = require("vitest");
4
4
  const utils_1 = require("./utils");
5
+ const _1 = require(".");
5
6
  const env = process.env;
6
7
  (0, vitest_1.beforeEach)(() => {
7
8
  vitest_1.vi.resetModules();
@@ -44,3 +45,45 @@ const env = process.env;
44
45
  });
45
46
  });
46
47
  });
48
+ (0, vitest_1.describe)("createTempDirectory()", () => {
49
+ (0, vitest_1.it)("creates temp directory fresh", () => {
50
+ const mkdirSyncMock = vitest_1.vi.fn();
51
+ const existsSyncMock = vitest_1.vi.fn().mockReturnValue(false);
52
+ (0, vitest_1.expect)(() => (0, utils_1.createTempDirectory)(mkdirSyncMock, existsSyncMock)).not.toThrow();
53
+ (0, vitest_1.expect)(mkdirSyncMock).toHaveBeenCalledWith(_1.TEMP_DIRECTORY);
54
+ });
55
+ (0, vitest_1.it)("does not throw error when it already exists", () => {
56
+ const mkdirSyncMock = vitest_1.vi.fn().mockImplementation(() => {
57
+ throw new Error("Directory already exists");
58
+ });
59
+ const existsSyncMock = vitest_1.vi.fn().mockReturnValue(true);
60
+ (0, vitest_1.expect)(() => (0, utils_1.createTempDirectory)(mkdirSyncMock, existsSyncMock)).not.toThrow();
61
+ (0, vitest_1.expect)(mkdirSyncMock).not.toHaveBeenCalledWith();
62
+ });
63
+ });
64
+ (0, vitest_1.describe)("toSavedFileName()", () => {
65
+ (0, vitest_1.it)("replaces slashes with double colons", () => {
66
+ (0, vitest_1.expect)((0, utils_1.toSavedFileName)("/hey/there")).toEqual("hey::there");
67
+ });
68
+ });
69
+ (0, vitest_1.describe)("readFile()", () => {
70
+ (0, vitest_1.it)("reads the file", () => {
71
+ const readFileSyncMock = vitest_1.vi.fn().mockReturnValue("file contents");
72
+ (0, vitest_1.expect)((0, utils_1.readFile)("hey/there", readFileSyncMock)).toEqual("file contents");
73
+ (0, vitest_1.expect)(readFileSyncMock).toHaveBeenCalledWith(`${_1.TEMP_DIRECTORY}/hey::there`, "utf8");
74
+ });
75
+ (0, vitest_1.it)("returns null when file doesn't exist", () => {
76
+ const readFileSyncMock = vitest_1.vi.fn().mockImplementation(() => {
77
+ throw new Error("File not found");
78
+ });
79
+ (0, vitest_1.expect)((0, utils_1.readFile)("hey/there", readFileSyncMock)).toEqual(null);
80
+ });
81
+ });
82
+ (0, vitest_1.describe)("saveFile()", () => {
83
+ (0, vitest_1.it)("saves the file", async () => {
84
+ const writeFileMock = vitest_1.vi.fn();
85
+ const result = (0, utils_1.saveFile)("hey/there", "file contents", writeFileMock);
86
+ (0, vitest_1.expect)(writeFileMock).toHaveBeenCalledWith(`${_1.TEMP_DIRECTORY}/hey::there`, "file contents", vitest_1.expect.any(Function));
87
+ (0, vitest_1.expect)(result).toBeInstanceOf(Promise);
88
+ });
89
+ });
package/dist/esm/index.js CHANGED
@@ -1,3 +1,5 @@
1
- export { markupFetcher } from "./markupFetcher";
2
- export { reAppendMarkup } from "./utils";
1
+ import path from "path";
2
+ export const TEMP_DIRECTORY = path.join(process.cwd(), "_temp_jc");
3
+ export { markupFetcher, fetchAll } from "./markupFetcher";
4
+ export { reAppendMarkup, deleteTempDirectory } from "./utils";
3
5
  export { log, logError } from "./log";
@@ -1,37 +1,93 @@
1
1
  import { injectSchema } from "./injectSchema";
2
- import { getEnvironment, isValidTimezone, parseJson } from "./utils";
3
- export const markupFetcher = (platform, fetchImplementation = fetch) => {
4
- return async ({ tz = undefined, path, domain, apiKey, schema, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }) => {
5
- const trimmedTimezone = tz?.trim();
6
- if (trimmedTimezone && !isValidTimezone(trimmedTimezone)) {
7
- throw new Error(`The timezone passed to JamComments is invalid: ${trimmedTimezone}`);
8
- }
9
- const params = new URLSearchParams({
10
- path: path || "/",
11
- domain,
12
- });
13
- if (trimmedTimezone) {
14
- params.set("tz", trimmedTimezone);
15
- }
16
- if (environment !== "production") {
17
- params.set("stub", "true");
18
- }
19
- const requestUrl = `${baseUrl}/api/v3/markup?${params}`;
20
- const response = await fetchImplementation(requestUrl, {
21
- method: "GET",
22
- headers: {
23
- Authorization: `Bearer ${apiKey}`,
24
- Accept: "application/json",
25
- "X-Platform": platform,
26
- },
27
- });
28
- if (response.status === 401) {
29
- throw new Error(`Unauthorized! Are your domain and JamComments API key set correctly?`);
30
- }
31
- if (!response.ok) {
32
- throw new Error(`JamComments request failed! Status code: ${response.status}, message: ${response.statusText}, request URL: ${requestUrl}`);
2
+ import { createTempDirectory, deleteTempDirectory, getEnvironment, isValidTimezone, parseJson, readFile, saveFile, } from "./utils";
3
+ export async function fetchAll({ tz = undefined, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }, platform, fetchImplementation, batchMarkupFetcherImpl = batchMarkupFetcher) {
4
+ const fetchBatchMarkup = batchMarkupFetcherImpl(platform, fetchImplementation);
5
+ createTempDirectory();
6
+ let shouldKeepFetching = true;
7
+ let page = 1;
8
+ console.log("Fetching comments from JamComments! This might take a sec.");
9
+ try {
10
+ while (shouldKeepFetching) {
11
+ const { data: items, meta: { current_page, last_page }, } = await fetchBatchMarkup({
12
+ domain,
13
+ apiKey,
14
+ baseUrl,
15
+ environment,
16
+ page,
17
+ tz,
18
+ });
19
+ console.log(`Checking for comment data. Batch: ${current_page}/${last_page}`);
20
+ const saveMarkupPromises = items.map((item) => {
21
+ return saveFile(item.path, item.markup);
22
+ });
23
+ await Promise.all(saveMarkupPromises);
24
+ if (current_page === last_page) {
25
+ shouldKeepFetching = false;
26
+ }
27
+ else {
28
+ page++;
29
+ }
33
30
  }
34
- const markup = await response.text();
31
+ }
32
+ catch (error) {
33
+ deleteTempDirectory();
34
+ throw error;
35
+ }
36
+ }
37
+ export function batchMarkupFetcher(platform, fetchImplementation = fetch) {
38
+ return async ({ tz = undefined, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), page = 1, }) => {
39
+ const response = await makeMarkupRequest({ tz, domain, apiKey, baseUrl, environment, page }, "/api/v3/markup/all", fetchImplementation, platform);
40
+ return response.json();
41
+ };
42
+ }
43
+ export async function fetchFreshMarkup({ tz = undefined, path, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }, fetchImplementation = fetch, platform) {
44
+ const response = await makeMarkupRequest({ tz, path, domain, apiKey, baseUrl, environment }, "/api/v3/markup", fetchImplementation, platform);
45
+ return response.text();
46
+ }
47
+ export async function makeMarkupRequest({ tz = undefined, path = undefined, domain, apiKey, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), page = undefined, }, baseServicePath, fetchImplementation = fetch, platform) {
48
+ const trimmedTimezone = tz?.trim();
49
+ if (trimmedTimezone && !isValidTimezone(trimmedTimezone)) {
50
+ throw new Error(`The timezone passed to JamComments is invalid: ${trimmedTimezone}`);
51
+ }
52
+ const params = new URLSearchParams({
53
+ domain,
54
+ });
55
+ if (path) {
56
+ params.set("path", path);
57
+ }
58
+ if (page) {
59
+ params.set("page", page.toString());
60
+ }
61
+ if (trimmedTimezone) {
62
+ params.set("tz", trimmedTimezone);
63
+ }
64
+ if (environment !== "production") {
65
+ params.set("stub", "true");
66
+ }
67
+ const requestUrl = `${baseUrl}${baseServicePath}?${params}`;
68
+ const response = await fetchImplementation(requestUrl, {
69
+ method: "GET",
70
+ headers: {
71
+ Authorization: `Bearer ${apiKey}`,
72
+ Accept: "application/json",
73
+ "X-Platform": platform,
74
+ },
75
+ });
76
+ if (response.status === 401) {
77
+ throw new Error(`Unauthorized! Are your domain and JamComments API key set correctly?`);
78
+ }
79
+ if (!response.ok) {
80
+ throw new Error(`JamComments request failed! Status code: ${response.status}, message: ${response.statusText}, request URL: ${requestUrl}`);
81
+ }
82
+ return response;
83
+ }
84
+ export function markupFetcher(platform, fetchImplementation = fetch) {
85
+ return async ({ tz = undefined, path, domain, apiKey, schema, baseUrl = "https://go.jamcomments.com", environment = getEnvironment(), }) => {
86
+ path = path || "/";
87
+ const savedFile = readFile(path);
88
+ const markup = savedFile
89
+ ? savedFile
90
+ : await fetchFreshMarkup({ tz, path, domain, apiKey, baseUrl, environment }, fetchImplementation, platform);
35
91
  if (schema) {
36
92
  const preparedSchema = typeof schema !== "string" ? JSON.stringify(schema) : schema;
37
93
  const parsedSchema = parseJson(preparedSchema);
@@ -42,4 +98,4 @@ export const markupFetcher = (platform, fetchImplementation = fetch) => {
42
98
  }
43
99
  return markup;
44
100
  };
45
- };
101
+ }
@@ -1,6 +1,201 @@
1
- import { describe, expect, it, vi } from "vitest";
1
+ import { beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import * as injectSchema from "./injectSchema";
3
- import { markupFetcher } from "./markupFetcher";
3
+ import * as fetcherExports from "./markupFetcher";
4
+ import { afterEach } from "node:test";
5
+ import * as utilsExports from "./utils";
6
+ const { deleteTempDirectory } = utilsExports;
7
+ const { markupFetcher, batchMarkupFetcher } = fetcherExports;
8
+ beforeEach(() => {
9
+ deleteTempDirectory();
10
+ });
11
+ afterEach(() => {
12
+ vi.resetAllMocks();
13
+ });
14
+ describe("fetchAll()", () => {
15
+ it("fetches all comments in a single request", async () => {
16
+ const saveFileSpy = vi.spyOn(utilsExports, "saveFile");
17
+ const mockBatchFetcher = vi.fn().mockReturnValue({
18
+ data: [
19
+ { path: "/test", markup: "markup1" },
20
+ { path: "/test2", markup: "markup2" },
21
+ ],
22
+ meta: {
23
+ current_page: 1,
24
+ from: 1,
25
+ last_page: 1,
26
+ path: "/test",
27
+ per_page: 10,
28
+ to: 2,
29
+ total: 2,
30
+ },
31
+ });
32
+ const batchMarkupFetcherMock = vi.fn().mockImplementation((a, b) => {
33
+ return mockBatchFetcher;
34
+ });
35
+ await fetcherExports.fetchAll({
36
+ domain: "test.com",
37
+ apiKey: "123abc",
38
+ environment: "production",
39
+ }, "test_platform", vi.fn(), batchMarkupFetcherMock);
40
+ expect(batchMarkupFetcherMock).toHaveBeenCalledWith("test_platform", expect.anything());
41
+ expect(mockBatchFetcher).toHaveBeenCalledWith({
42
+ domain: "test.com",
43
+ apiKey: "123abc",
44
+ baseUrl: "https://go.jamcomments.com",
45
+ environment: "production",
46
+ page: 1,
47
+ tz: undefined,
48
+ });
49
+ expect(saveFileSpy).toHaveBeenCalledTimes(2);
50
+ expect(saveFileSpy).toHaveBeenCalledWith("/test", "markup1");
51
+ expect(saveFileSpy).toHaveBeenCalledWith("/test2", "markup2");
52
+ });
53
+ it("fetches all comments in multiple requests", async () => {
54
+ const saveFileSpy = vi.spyOn(utilsExports, "saveFile");
55
+ const mockBatchFetcher = vi
56
+ .fn()
57
+ .mockReturnValueOnce({
58
+ data: [
59
+ { path: "/test", markup: "markup1" },
60
+ { path: "/test2", markup: "markup2" },
61
+ ],
62
+ meta: {
63
+ current_page: 1,
64
+ from: 1,
65
+ last_page: 2,
66
+ path: "/test",
67
+ per_page: 2,
68
+ to: 2,
69
+ },
70
+ })
71
+ .mockReturnValueOnce({
72
+ data: [
73
+ { path: "/test3", markup: "markup3" },
74
+ { path: "/test4", markup: "markup4" },
75
+ ],
76
+ meta: {
77
+ current_page: 2,
78
+ from: 3,
79
+ last_page: 2,
80
+ path: "/test",
81
+ per_page: 2,
82
+ to: 4,
83
+ },
84
+ });
85
+ const batchMarkupFetcherMock = vi.fn().mockImplementation((a, b) => {
86
+ return mockBatchFetcher;
87
+ });
88
+ await fetcherExports.fetchAll({
89
+ domain: "test.com",
90
+ apiKey: "123abc",
91
+ environment: "production",
92
+ }, "test_platform", vi.fn(), batchMarkupFetcherMock);
93
+ expect(batchMarkupFetcherMock).toHaveBeenCalledWith("test_platform", expect.anything());
94
+ expect(mockBatchFetcher).toHaveBeenCalledWith({
95
+ domain: "test.com",
96
+ apiKey: "123abc",
97
+ baseUrl: "https://go.jamcomments.com",
98
+ environment: "production",
99
+ page: 1,
100
+ tz: undefined,
101
+ });
102
+ expect(mockBatchFetcher).toHaveBeenCalledTimes(2);
103
+ expect(mockBatchFetcher).toHaveBeenCalledWith({
104
+ domain: "test.com",
105
+ apiKey: "123abc",
106
+ baseUrl: "https://go.jamcomments.com",
107
+ environment: "production",
108
+ page: 2,
109
+ tz: undefined,
110
+ });
111
+ expect(saveFileSpy).toHaveBeenCalledTimes(4);
112
+ expect(saveFileSpy).toHaveBeenCalledWith("/test", "markup1");
113
+ expect(saveFileSpy).toHaveBeenCalledWith("/test2", "markup2");
114
+ });
115
+ it("deletes the temp directory of anything fails", async () => {
116
+ const deleteTempDirectorySpy = vi.spyOn(utilsExports, "deleteTempDirectory");
117
+ const mockBatchFetcher = vi.fn().mockImplementation(() => {
118
+ throw new Error("test error");
119
+ });
120
+ const batchMarkupFetcherMock = vi.fn().mockImplementation((a, b) => {
121
+ return mockBatchFetcher;
122
+ });
123
+ try {
124
+ await fetcherExports.fetchAll({
125
+ domain: "test.com",
126
+ apiKey: "123abc",
127
+ environment: "production",
128
+ }, "test_platform", vi.fn(), batchMarkupFetcherMock);
129
+ }
130
+ catch (e) {
131
+ expect(e.message).toEqual("test error");
132
+ }
133
+ expect(deleteTempDirectorySpy).toHaveBeenCalledOnce();
134
+ });
135
+ });
136
+ describe("batchMarkupFetcher", () => {
137
+ it("constructs fetch request correctly", async () => {
138
+ const injectSchemaSpy = vi.spyOn(injectSchema, "injectSchema");
139
+ const fetchMock = vi.fn().mockImplementation(() => {
140
+ return {
141
+ status: 200,
142
+ ok: true,
143
+ json: () => "results!",
144
+ };
145
+ });
146
+ const fetcher = batchMarkupFetcher("test", fetchMock);
147
+ const result = await fetcher({
148
+ domain: "test.com",
149
+ apiKey: "123abc",
150
+ environment: "production",
151
+ });
152
+ expect(injectSchemaSpy).not.toHaveBeenCalled();
153
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup/all?domain=test.com&page=1", expect.objectContaining({
154
+ headers: expect.objectContaining({
155
+ Accept: "application/json",
156
+ Authorization: "Bearer 123abc",
157
+ "X-Platform": "test",
158
+ }),
159
+ method: "GET",
160
+ }));
161
+ expect(result).toEqual("results!");
162
+ });
163
+ it("stubs comments", async () => {
164
+ const fetchMock = vi.fn().mockImplementation(() => {
165
+ return {
166
+ status: 200,
167
+ ok: true,
168
+ json: () => "results!",
169
+ };
170
+ });
171
+ const fetcher = batchMarkupFetcher("test", fetchMock);
172
+ const result = await fetcher({
173
+ domain: "test.com",
174
+ apiKey: "123abc",
175
+ environment: "development",
176
+ });
177
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup/all?domain=test.com&page=1&stub=true", expect.anything());
178
+ expect(result).toEqual("results!");
179
+ });
180
+ it("uses different base URL", async () => {
181
+ const fetchMock = vi.fn().mockImplementation(() => {
182
+ return {
183
+ status: 200,
184
+ ok: true,
185
+ json: () => "results!",
186
+ };
187
+ });
188
+ const fetcher = batchMarkupFetcher("test", fetchMock);
189
+ const result = await fetcher({
190
+ domain: "test.com",
191
+ apiKey: "123abc",
192
+ baseUrl: "http://ur-mom.com",
193
+ environment: "production",
194
+ });
195
+ expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup/all?domain=test.com&page=1", expect.anything());
196
+ expect(result).toEqual("results!");
197
+ });
198
+ });
4
199
  describe("markupFetcher", () => {
5
200
  it("constructs fetch request correctly", async () => {
6
201
  const injectSchemaSpy = vi.spyOn(injectSchema, "injectSchema");
@@ -19,7 +214,7 @@ describe("markupFetcher", () => {
19
214
  environment: "production",
20
215
  });
21
216
  expect(injectSchemaSpy).not.toHaveBeenCalled();
22
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.objectContaining({
217
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.objectContaining({
23
218
  headers: expect.objectContaining({
24
219
  Accept: "application/json",
25
220
  Authorization: "Bearer 123abc",
@@ -44,7 +239,7 @@ describe("markupFetcher", () => {
44
239
  apiKey: "123abc",
45
240
  environment: "development",
46
241
  });
47
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com&stub=true", expect.anything());
242
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest&stub=true", expect.anything());
48
243
  expect(result).toEqual("results!");
49
244
  });
50
245
  it("uses different base URL", async () => {
@@ -63,7 +258,7 @@ describe("markupFetcher", () => {
63
258
  baseUrl: "http://ur-mom.com",
64
259
  environment: "production",
65
260
  });
66
- expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.anything());
261
+ expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
67
262
  expect(result).toEqual("results!");
68
263
  });
69
264
  it("respects production!!!", async () => {
@@ -82,7 +277,7 @@ describe("markupFetcher", () => {
82
277
  baseUrl: "http://ur-mom.com",
83
278
  environment: "production",
84
279
  });
85
- expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.anything());
280
+ expect(fetchMock).toHaveBeenCalledWith("http://ur-mom.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
86
281
  expect(result).toEqual("results!");
87
282
  });
88
283
  it("falls back to root path", async () => {
@@ -100,7 +295,7 @@ describe("markupFetcher", () => {
100
295
  apiKey: "123abc",
101
296
  environment: "production",
102
297
  });
103
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2F&domain=test.com", expect.anything());
298
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2F", expect.anything());
104
299
  expect(result).toEqual("results!");
105
300
  });
106
301
  it("credentials are invalid", async () => {
@@ -135,9 +330,9 @@ describe("markupFetcher", () => {
135
330
  });
136
331
  describe("timezone validation", () => {
137
332
  it("throws error when invalid timezone is provided", async () => {
138
- const fetchMock = vi.fn();
139
- const fetcher = markupFetcher("test", fetchMock);
140
- expect(fetchMock).not.toHaveBeenCalled();
333
+ const fetchImplMock = vi.fn();
334
+ const fetcher = markupFetcher("test", fetchImplMock);
335
+ expect(fetchImplMock).not.toHaveBeenCalled();
141
336
  expect(fetcher({
142
337
  path: "/test",
143
338
  domain: "test.com",
@@ -156,13 +351,13 @@ describe("markupFetcher", () => {
156
351
  });
157
352
  const fetcher = markupFetcher("test", fetchMock);
158
353
  const result = await fetcher({
159
- path: null,
354
+ path: "/some/path",
160
355
  domain: "test.com",
161
356
  apiKey: "123abc",
162
357
  tz: "America/New_York",
163
358
  environment: "production",
164
359
  });
165
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2F&domain=test.com&tz=America%2FNew_York", expect.anything());
360
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Fsome%2Fpath&tz=America%2FNew_York", expect.anything());
166
361
  expect(result).toEqual("results!");
167
362
  });
168
363
  it("trims a valid timezone", async () => {
@@ -175,13 +370,13 @@ describe("markupFetcher", () => {
175
370
  });
176
371
  const fetcher = markupFetcher("test", fetchMock);
177
372
  const result = await fetcher({
178
- path: null,
373
+ path: "/some/path",
179
374
  domain: "test.com",
180
375
  apiKey: "123abc",
181
376
  tz: " America/Chicago ",
182
377
  environment: "production",
183
378
  });
184
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2F&domain=test.com&tz=America%2FChicago", expect.anything());
379
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Fsome%2Fpath&tz=America%2FChicago", expect.anything());
185
380
  expect(result).toEqual("results!");
186
381
  });
187
382
  });
@@ -205,7 +400,7 @@ describe("passing schema", function () {
205
400
  environment: "production",
206
401
  });
207
402
  expect(injectSchemaSpy).toHaveBeenCalledWith("results!", { foo: "bar" });
208
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.anything());
403
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
209
404
  expect(result).toEqual("results!");
210
405
  });
211
406
  it("does not stringify schema if given a string", async () => {
@@ -226,7 +421,7 @@ describe("passing schema", function () {
226
421
  environment: "production",
227
422
  });
228
423
  expect(injectSchemaSpy).toHaveBeenCalledWith("results!", { foo: "bar" });
229
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.anything());
424
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
230
425
  expect(result).toEqual("results!");
231
426
  });
232
427
  it("returns markup if invalid json is provided", async () => {
@@ -247,7 +442,7 @@ describe("passing schema", function () {
247
442
  environment: "production",
248
443
  });
249
444
  expect(injectSchemaSpy).not.toHaveBeenCalled();
250
- expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?path=%2Ftest&domain=test.com", expect.anything());
445
+ expect(fetchMock).toHaveBeenCalledWith("https://go.jamcomments.com/api/v3/markup?domain=test.com&path=%2Ftest", expect.anything());
251
446
  expect(result).toEqual("results!");
252
447
  });
253
448
  });
package/dist/esm/utils.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { existsSync, mkdirSync, readFileSync, rmdirSync, writeFile } from "fs";
2
+ import { TEMP_DIRECTORY } from ".";
1
3
  export function isValidTimezone(tz) {
2
4
  try {
3
5
  Intl.DateTimeFormat(undefined, { timeZone: tz });
@@ -30,21 +32,21 @@ export function parseJson(json) {
30
32
  return null;
31
33
  }
32
34
  }
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
35
  export function unescapeHTML(str) {
36
+ var htmlEntities = {
37
+ nbsp: " ",
38
+ cent: "¢",
39
+ pound: "£",
40
+ yen: "¥",
41
+ euro: "€",
42
+ copy: "©",
43
+ reg: "®",
44
+ lt: "<",
45
+ gt: ">",
46
+ quot: '"',
47
+ amp: "&",
48
+ apos: "'",
49
+ };
48
50
  return str.replace(/\&([^;]+);/g, function (entity, entityCode) {
49
51
  var match;
50
52
  if (entityCode in htmlEntities) {
@@ -61,3 +63,33 @@ export function unescapeHTML(str) {
61
63
  }
62
64
  });
63
65
  }
66
+ export function deleteTempDirectory() {
67
+ if (existsSync(TEMP_DIRECTORY)) {
68
+ rmdirSync(TEMP_DIRECTORY, { recursive: true });
69
+ }
70
+ }
71
+ export function createTempDirectory(mkdirSyncImpl = mkdirSync, existsSyncImpl = existsSync) {
72
+ if (!existsSyncImpl(TEMP_DIRECTORY)) {
73
+ mkdirSyncImpl(TEMP_DIRECTORY);
74
+ }
75
+ }
76
+ export function toSavedFileName(name) {
77
+ return name.replace(/^\//, "").replace(/\//g, "::");
78
+ }
79
+ export function readFile(name, readFileSyncImpl = readFileSync) {
80
+ const fileName = toSavedFileName(name);
81
+ try {
82
+ return readFileSyncImpl(`${TEMP_DIRECTORY}/${fileName}`, "utf8");
83
+ }
84
+ catch (error) {
85
+ return null;
86
+ }
87
+ }
88
+ export function saveFile(name, data, writeFileImpl = writeFile) {
89
+ const fileName = toSavedFileName(name);
90
+ return new Promise((resolve) => {
91
+ writeFileImpl(`${TEMP_DIRECTORY}/${fileName}`, data, () => {
92
+ resolve();
93
+ });
94
+ });
95
+ }
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
- import { getEnvironment } from "./utils";
2
+ import { getEnvironment, createTempDirectory, toSavedFileName, readFile, saveFile, } from "./utils";
3
+ import { TEMP_DIRECTORY } from ".";
3
4
  const env = process.env;
4
5
  beforeEach(() => {
5
6
  vi.resetModules();
@@ -42,3 +43,45 @@ describe("getEnvironment()", () => {
42
43
  });
43
44
  });
44
45
  });
46
+ describe("createTempDirectory()", () => {
47
+ it("creates temp directory fresh", () => {
48
+ const mkdirSyncMock = vi.fn();
49
+ const existsSyncMock = vi.fn().mockReturnValue(false);
50
+ expect(() => createTempDirectory(mkdirSyncMock, existsSyncMock)).not.toThrow();
51
+ expect(mkdirSyncMock).toHaveBeenCalledWith(TEMP_DIRECTORY);
52
+ });
53
+ it("does not throw error when it already exists", () => {
54
+ const mkdirSyncMock = vi.fn().mockImplementation(() => {
55
+ throw new Error("Directory already exists");
56
+ });
57
+ const existsSyncMock = vi.fn().mockReturnValue(true);
58
+ expect(() => createTempDirectory(mkdirSyncMock, existsSyncMock)).not.toThrow();
59
+ expect(mkdirSyncMock).not.toHaveBeenCalledWith();
60
+ });
61
+ });
62
+ describe("toSavedFileName()", () => {
63
+ it("replaces slashes with double colons", () => {
64
+ expect(toSavedFileName("/hey/there")).toEqual("hey::there");
65
+ });
66
+ });
67
+ describe("readFile()", () => {
68
+ it("reads the file", () => {
69
+ const readFileSyncMock = vi.fn().mockReturnValue("file contents");
70
+ expect(readFile("hey/there", readFileSyncMock)).toEqual("file contents");
71
+ expect(readFileSyncMock).toHaveBeenCalledWith(`${TEMP_DIRECTORY}/hey::there`, "utf8");
72
+ });
73
+ it("returns null when file doesn't exist", () => {
74
+ const readFileSyncMock = vi.fn().mockImplementation(() => {
75
+ throw new Error("File not found");
76
+ });
77
+ expect(readFile("hey/there", readFileSyncMock)).toEqual(null);
78
+ });
79
+ });
80
+ describe("saveFile()", () => {
81
+ it("saves the file", async () => {
82
+ const writeFileMock = vi.fn();
83
+ const result = saveFile("hey/there", "file contents", writeFileMock);
84
+ expect(writeFileMock).toHaveBeenCalledWith(`${TEMP_DIRECTORY}/hey::there`, "file contents", expect.any(Function));
85
+ expect(result).toBeInstanceOf(Promise);
86
+ });
87
+ });
@@ -1,3 +1,4 @@
1
- export { markupFetcher } from "./markupFetcher";
2
- export { reAppendMarkup } from "./utils";
1
+ export declare const TEMP_DIRECTORY: string;
2
+ export { markupFetcher, fetchAll } from "./markupFetcher";
3
+ export { reAppendMarkup, deleteTempDirectory } from "./utils";
3
4
  export { log, logError } from "./log";