@ezez/utils 1.2.0 → 1.5.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.
Files changed (159) hide show
  1. package/.github/workflows/docs.yml +50 -0
  2. package/CHANGELOG.md +18 -0
  3. package/README.md +7 -1
  4. package/dist/compareArrays.d.ts +7 -0
  5. package/dist/compareArrays.d.ts.map +1 -0
  6. package/dist/compareArrays.js +12 -0
  7. package/dist/compareArrays.js.map +1 -0
  8. package/dist/ensureError.d.ts.map +1 -1
  9. package/dist/ensureError.js.map +1 -1
  10. package/dist/escapeRegExp.d.ts +3 -0
  11. package/dist/escapeRegExp.d.ts.map +1 -0
  12. package/dist/escapeRegExp.js +8 -0
  13. package/dist/escapeRegExp.js.map +1 -0
  14. package/dist/index.d.ts +6 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +6 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/isPlainObject.d.ts.map +1 -1
  19. package/dist/isPlainObject.js.map +1 -1
  20. package/dist/replace.d.ts +3 -0
  21. package/dist/replace.d.ts.map +1 -0
  22. package/dist/replace.js +10 -0
  23. package/dist/replace.js.map +1 -0
  24. package/dist/safe.d.ts +4 -0
  25. package/dist/safe.d.ts.map +1 -0
  26. package/dist/safe.js +13 -0
  27. package/dist/safe.js.map +1 -0
  28. package/dist/sortProps.d.ts +3 -0
  29. package/dist/sortProps.d.ts.map +1 -0
  30. package/dist/sortProps.js +19 -0
  31. package/dist/sortProps.js.map +1 -0
  32. package/dist/unique.d.ts +3 -0
  33. package/dist/unique.d.ts.map +1 -0
  34. package/dist/unique.js +8 -0
  35. package/dist/unique.js.map +1 -0
  36. package/docs/assets/highlight.css +14 -0
  37. package/docs/assets/main.js +1 -1
  38. package/docs/assets/search.js +1 -1
  39. package/docs/assets/style.css +4 -5
  40. package/docs/functions/cap.html +13 -6
  41. package/docs/functions/capitalize.html +13 -6
  42. package/docs/functions/coalesce.html +15 -9
  43. package/docs/functions/compareArrays.html +146 -0
  44. package/docs/functions/ensureArray.html +14 -7
  45. package/docs/functions/ensureDate.html +13 -6
  46. package/docs/functions/ensureError.html +23 -6
  47. package/docs/functions/ensurePrefix.html +13 -6
  48. package/docs/functions/ensureSuffix.html +13 -6
  49. package/docs/functions/ensureTimestamp.html +13 -6
  50. package/docs/functions/escapeRegExp.html +129 -0
  51. package/docs/functions/get.html +13 -6
  52. package/docs/functions/getMultiple.html +13 -6
  53. package/docs/functions/insertSeparator.html +13 -6
  54. package/docs/functions/isEmpty.html +13 -6
  55. package/docs/functions/isNumericString.html +13 -6
  56. package/docs/functions/isPlainObject.html +28 -6
  57. package/docs/functions/last.html +13 -6
  58. package/docs/functions/mapAsync.html +13 -6
  59. package/docs/functions/mapValues.html +13 -6
  60. package/docs/functions/match.html +13 -6
  61. package/docs/functions/merge.html +21 -14
  62. package/docs/functions/mostFrequent.html +13 -6
  63. package/docs/functions/noop.html +13 -6
  64. package/docs/functions/occurrences.html +13 -6
  65. package/docs/functions/omit.html +13 -6
  66. package/docs/functions/pick.html +13 -6
  67. package/docs/functions/pull.html +13 -6
  68. package/docs/functions/remove.html +13 -6
  69. package/docs/functions/replace.html +135 -0
  70. package/docs/functions/rethrow.html +13 -6
  71. package/docs/functions/safe.html +173 -0
  72. package/docs/functions/scale.html +13 -6
  73. package/docs/functions/seq.html +13 -6
  74. package/docs/functions/seqEarlyBreak.html +13 -6
  75. package/docs/functions/set.html +13 -6
  76. package/docs/functions/setImmutable.html +13 -6
  77. package/docs/functions/sortBy.html +13 -6
  78. package/docs/functions/sortProps.html +138 -0
  79. package/docs/functions/stripPrefix.html +13 -6
  80. package/docs/functions/stripSuffix.html +13 -6
  81. package/docs/functions/throttle.html +13 -6
  82. package/docs/functions/truthy.html +13 -6
  83. package/docs/functions/unique.html +133 -0
  84. package/docs/functions/wait.html +13 -6
  85. package/docs/functions/waitFor.html +13 -6
  86. package/docs/functions/waitSync.html +13 -6
  87. package/docs/index.html +20 -7
  88. package/docs/interfaces/GetMultipleSource.html +13 -6
  89. package/docs/interfaces/GetSource.html +13 -6
  90. package/docs/interfaces/IsNumericStringOptions.html +11 -10
  91. package/docs/interfaces/OccurencesOptions.html +8 -7
  92. package/docs/interfaces/SetImmutableSource.html +13 -6
  93. package/docs/interfaces/SetSource.html +13 -6
  94. package/docs/interfaces/ThrottleOptions.html +9 -8
  95. package/docs/interfaces/ThrottledFunctionExtras.html +9 -8
  96. package/docs/modules.html +18 -5
  97. package/docs/pages/CHANGELOG.html +778 -0
  98. package/docs/pages/Introduction.html +12 -5
  99. package/docs/types/MapValuesFn.html +13 -6
  100. package/docs/types/MatchCallback.html +13 -6
  101. package/docs/types/SeqEarlyBreaker.html +13 -6
  102. package/docs/types/SeqFn.html +13 -6
  103. package/docs/types/SeqFunctions.html +13 -6
  104. package/docs/types/SetImmutablePath.html +13 -6
  105. package/docs/types/ThrottledFunction.html +13 -6
  106. package/docs/variables/mapValuesUNSET.html +13 -6
  107. package/docs/variables/mergeUNSET.html +13 -6
  108. package/esm/compareArrays.d.ts +7 -0
  109. package/esm/compareArrays.d.ts.map +1 -0
  110. package/esm/compareArrays.js +9 -0
  111. package/esm/compareArrays.js.map +1 -0
  112. package/esm/ensureError.d.ts.map +1 -1
  113. package/esm/ensureError.js.map +1 -1
  114. package/esm/escapeRegExp.d.ts +3 -0
  115. package/esm/escapeRegExp.d.ts.map +1 -0
  116. package/esm/escapeRegExp.js +5 -0
  117. package/esm/escapeRegExp.js.map +1 -0
  118. package/esm/index.d.ts +6 -0
  119. package/esm/index.d.ts.map +1 -1
  120. package/esm/index.js +6 -0
  121. package/esm/index.js.map +1 -1
  122. package/esm/isPlainObject.d.ts.map +1 -1
  123. package/esm/isPlainObject.js.map +1 -1
  124. package/esm/replace.d.ts +3 -0
  125. package/esm/replace.d.ts.map +1 -0
  126. package/esm/replace.js +7 -0
  127. package/esm/replace.js.map +1 -0
  128. package/esm/safe.d.ts +4 -0
  129. package/esm/safe.d.ts.map +1 -0
  130. package/esm/safe.js +10 -0
  131. package/esm/safe.js.map +1 -0
  132. package/esm/sortProps.d.ts +3 -0
  133. package/esm/sortProps.d.ts.map +1 -0
  134. package/esm/sortProps.js +16 -0
  135. package/esm/sortProps.js.map +1 -0
  136. package/esm/unique.d.ts +3 -0
  137. package/esm/unique.d.ts.map +1 -0
  138. package/esm/unique.js +5 -0
  139. package/esm/unique.js.map +1 -0
  140. package/package.json +23 -23
  141. package/src/coalesce.ts +2 -2
  142. package/src/compareArrays.spec.ts +38 -0
  143. package/src/compareArrays.ts +22 -0
  144. package/src/ensureArray.ts +1 -1
  145. package/src/ensureError.ts +7 -0
  146. package/src/escapeRegExp.spec.ts +31 -0
  147. package/src/escapeRegExp.ts +17 -0
  148. package/src/index.ts +6 -0
  149. package/src/isPlainObject.spec.ts +0 -7
  150. package/src/isPlainObject.ts +5 -0
  151. package/src/replace.spec.ts +22 -0
  152. package/src/replace.ts +19 -0
  153. package/src/safe.spec.ts +52 -0
  154. package/src/safe.ts +24 -0
  155. package/src/sortProps.spec.ts +20 -0
  156. package/src/sortProps.ts +21 -0
  157. package/src/unique.spec.ts +10 -0
  158. package/src/unique.ts +12 -0
  159. package/typedoc.cjs +5 -0
@@ -0,0 +1,38 @@
1
+ import { compareArrays } from "./compareArrays.js";
2
+
3
+ describe("compareArrays", () => {
4
+ it("should mark items that are only in a or b", async () => {
5
+ compareArrays([1, 2, 3], [4, 5, 6]).must.eql({
6
+ onlyA: [1, 2, 3],
7
+ onlyB: [4, 5, 6],
8
+ both: [],
9
+ });
10
+ });
11
+
12
+ it("should mark items that exists in both arrays", async () => {
13
+ compareArrays([1, 2, 3], [3, 4, 5]).must.eql({
14
+ onlyA: [1, 2],
15
+ onlyB: [4, 5],
16
+ both: [3],
17
+ });
18
+ });
19
+
20
+ it("should not return duplicates if given", async () => {
21
+ compareArrays([1, 1, 2, 3, 3], [3, 4, 5]).must.eql({
22
+ onlyA: [1, 2],
23
+ onlyB: [4, 5],
24
+ both: [3],
25
+ });
26
+ compareArrays([1, 2, 3, 3], [3, 3, 4, 5]).must.eql({
27
+ onlyA: [1, 2],
28
+ onlyB: [4, 5],
29
+ both: [3],
30
+ });
31
+ compareArrays([1, 2, 3, 3], [3, 3, 3, 4, 5]).must.eql({
32
+ onlyA: [1, 2],
33
+ onlyB: [4, 5],
34
+ both: [3],
35
+ });
36
+ });
37
+ });
38
+
@@ -0,0 +1,22 @@
1
+ import { unique } from "./unique.js";
2
+
3
+ /**
4
+ * Compares two arrays and returns the items that are only in arrayA, only in arrayB, and in both arrays.
5
+ * @param arrayA - first array
6
+ * @param arrayB - second array
7
+ * @returns an object with three properties:
8
+ * onlyA - items that exists only in first array,
9
+ * onlyB - items that exists only in second array,
10
+ * both - items that exists in both arrays
11
+ */
12
+ const compareArrays = <T extends unknown[]>(arrayA: T, arrayB: T): { onlyA: T; onlyB: T; both: T } => {
13
+ const onlyA = unique(arrayA.filter((item) => !arrayB.includes(item)));
14
+ const onlyB = unique(arrayB.filter((item) => !arrayA.includes(item)));
15
+ const both = unique(arrayA.filter((item) => arrayB.includes(item)));
16
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
17
+ return { onlyA, onlyB, both } as { onlyA: T; onlyB: T; both: T };
18
+ };
19
+
20
+ export {
21
+ compareArrays,
22
+ };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Wraps value in an array until the value is already an array
2
+ * Wraps value in an array unless the value is already an array
3
3
  * @param {*} value - value to be wrapped
4
4
  * @returns {Array}
5
5
  */
@@ -1,5 +1,12 @@
1
1
  /**
2
2
  * Ensures given value is an instance of Error.
3
+ *
4
+ * This is for simple use cases only, for maximum flexibility use `@ezez/errors` package.
5
+ * @example ensureError(new Error("test")); // returns given Error instance (not modified)
6
+ * @example ensureError("test");
7
+ * // ^ returns new Error instance with error message: "Expected error instance, got something else: test"
8
+ * @example ensureError({});
9
+ * // ^ returns new Error instance with error message: "Expected error instance, got something else: [object Object]"
3
10
  * @param {*} e - value to check
4
11
  * @returns Error - original error or new Error instance
5
12
  */
@@ -0,0 +1,31 @@
1
+ import { escapeRegExp } from "./escapeRegExp.js";
2
+
3
+ describe("escapeRegExp", () => {
4
+ it("it should escape dot", () => {
5
+ const userName = ".";
6
+ const regex = new RegExp(`^(maciek|${escapeRegExp(userName)})$`);
7
+ const result = regex.test("maciek");
8
+ result.must.be.true();
9
+
10
+ const result2 = regex.test("stefan");
11
+ result2.must.be.false();
12
+
13
+ const result3 = regex.test(",");
14
+ result3.must.be.false();
15
+
16
+ const result4 = regex.test(".");
17
+ result4.must.be.true();
18
+
19
+ const result5 = regex.test("...");
20
+ result5.must.be.false();
21
+ });
22
+
23
+ it("should escape complex string", () => {
24
+ const userName = "([{^|";
25
+ const fn = () => new RegExp(`^(maciek|${escapeRegExp(userName)})$`);
26
+ fn.must.not.throw();
27
+
28
+ const fnNoEscape = () => new RegExp(`^(maciek|${userName})$`);
29
+ fnNoEscape.must.throw();
30
+ });
31
+ });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Escapes a string to be used in a regular expression.
3
+ * From: https://stackoverflow.com/a/3561711
4
+ * @param string - string to escape
5
+ * @example ```typescript
6
+ * const badName = "([{^|";
7
+ * const regex = new RegExp(`^(maciek|${escapeRegExp(badName)})$`); // won't crash
8
+ * regex.test(badName); // true
9
+ * ```
10
+ */
11
+ const escapeRegExp = (string: string) => {
12
+ return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&");
13
+ };
14
+
15
+ export {
16
+ escapeRegExp,
17
+ };
package/src/index.ts CHANGED
@@ -4,10 +4,12 @@ export * from "./ensureSuffix.js";
4
4
  export * from "./cap.js";
5
5
  export * from "./capitalize.js";
6
6
  export * from "./coalesce.js";
7
+ export * from "./compareArrays.js";
7
8
  export * from "./ensureArray.js";
8
9
  export * from "./ensureDate.js";
9
10
  export * from "./ensureError.js";
10
11
  export * from "./ensureTimestamp.js";
12
+ export * from "./escapeRegExp.js";
11
13
  export * from "./get.js";
12
14
  export * from "./getMultiple.js";
13
15
  export * from "./insertSeparator.js";
@@ -26,16 +28,20 @@ export * from "./omit.js";
26
28
  export * from "./pick.js";
27
29
  export * from "./pull.js";
28
30
  export * from "./remove.js";
31
+ export * from "./replace.js";
29
32
  export * from "./rethrow.js";
33
+ export * from "./safe.js";
30
34
  export * from "./scale.js";
31
35
  export * from "./seq.js";
32
36
  export * from "./set.js";
33
37
  export * from "./setImmutable.js";
34
38
  export * from "./sortBy.js";
39
+ export * from "./sortProps.js";
35
40
  export * from "./stripPrefix.js";
36
41
  export * from "./stripSuffix.js";
37
42
  export * from "./throttle.js";
38
43
  export * from "./truthy.js";
44
+ export * from "./unique.js";
39
45
  export * from "./wait.js";
40
46
  export * from "./waitFor.js";
41
47
  export * from "./waitSync.js";
@@ -22,13 +22,6 @@ describe("isPlainObject", function() {
22
22
  isPlainObject({ constructor: () => null }).must.be.true();
23
23
  });
24
24
 
25
- it("accepts plain objects", function() {
26
- isPlainObject({}).must.be.true();
27
- isPlainObject({ some: "data" }).must.be.true();
28
- isPlainObject({ some: function fn() {} }).must.be.true();
29
- isPlainObject(Object.create(null)).must.be.true();
30
- });
31
-
32
25
  it("shouldn't accept any instances", function() {
33
26
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
34
27
  class X {}
@@ -1,5 +1,10 @@
1
1
  /**
2
2
  * Checks if given value is a plain object. Plain object should be an object that's not an instance of anything.
3
+ * @example isPlainObject({}); // returns true
4
+ * @example isPlainObject(Object.create(null)); // returns true
5
+ * @example isPlainObject(new URL("https://ezez.dev")); // returns false
6
+ * @example isPlainObject([]); // returns false
7
+ * @example isPlainObject(5); // returns false
3
8
  * @param value - value to test
4
9
  */
5
10
  const isPlainObject = (value: unknown) => Boolean(
@@ -0,0 +1,22 @@
1
+ import { replace } from "./replace.js";
2
+
3
+ describe("replace", () => {
4
+ it("does a basic replace", () => {
5
+ replace("Hello, %name%!", { "%name%": "John" }).must.equal("Hello, John!");
6
+ });
7
+
8
+ it("replaces multiple occurrences", () => {
9
+ replace("Hello, %name%! Nice to meet you %name%!", { "%name%": "Jane" })
10
+ .must.equal("Hello, Jane! Nice to meet you Jane!");
11
+ });
12
+
13
+ it("replaces multiple occurences of multiple variables", () => {
14
+ replace("Hello, %name%, your age is %age%! Nice to meet you %age% yo %name%!",
15
+ { "%name%": "Jane", "%age%": "30" },
16
+ ).must.equal("Hello, Jane, your age is 30! Nice to meet you 30 yo Jane!");
17
+ });
18
+
19
+ it("doesn't break on regexp characters", () => {
20
+ replace("Hello.", { ".": "!" }).must.equal("Hello!");
21
+ });
22
+ });
package/src/replace.ts ADDED
@@ -0,0 +1,19 @@
1
+ /* eslint-disable max-len */
2
+ import { escapeRegExp } from "./escapeRegExp.js";
3
+
4
+ /**
5
+ * Replaces all occurrences of the keys in the replaceMap with the values.
6
+ * @param source - source string
7
+ * @param replaceMap - keys from this object will be replaced with values in source string
8
+ * @example replace("Hello, %name%!", { "%name%: "John" }) // "Hello, John!"
9
+ * @example replace("Hello, %name%! Nice to meet you %name%!", { "%name%": "Jane" }) // "Hello, Jane! Nice to meet you Jane!"
10
+ */
11
+ const replace = (source: string, replaceMap: Record<string, string>) => {
12
+ /* eslint-enable max-len */
13
+ const regex = new RegExp(Object.keys(replaceMap).map(escapeRegExp).join("|"), "g");
14
+ return source.replace(regex, (matched) => replaceMap[matched]);
15
+ };
16
+
17
+ export {
18
+ replace,
19
+ };
@@ -0,0 +1,52 @@
1
+ import { safe } from "./safe.js";
2
+
3
+ describe("safe", () => {
4
+ it("returns value from a function if it doesn't throw", () => {
5
+ const result = safe(() => 5);
6
+ result.must.equal(5);
7
+ });
8
+
9
+ it("returns undefined if function throws and no default value is given", () => {
10
+ // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
11
+ const result = safe(() => {
12
+ throw new Error("Boo");
13
+ });
14
+ (result === undefined).must.be.true();
15
+ });
16
+
17
+ it("returns given default value if function throws", () => {
18
+ const result = safe(() => {
19
+ throw new Error("Boo");
20
+ }, 15);
21
+ result.must.equal(15);
22
+ });
23
+
24
+ it("returns undefined if function throws and default value is undefined", () => {
25
+ // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
26
+ const result = safe(() => {
27
+ throw new Error("Boo");
28
+ }, undefined);
29
+ (result === undefined).must.be.true();
30
+ });
31
+
32
+ it("returns value from function if it doesn't throw and default is given", () => {
33
+ const result = safe(() => 5, 15);
34
+ result.must.equal(5);
35
+ });
36
+
37
+ it("doesn't unwrap promises", () => {
38
+ const result = safe(() => Promise.resolve(5));
39
+ result.must.be.instanceof(Promise);
40
+ });
41
+
42
+ it("doesn't 'work' with promises", () => {
43
+ // eslint-disable-next-line @typescript-eslint/require-await
44
+ const result = safe(async () => {
45
+ throw new Error("Boo!!!");
46
+ });
47
+ result.must.be.instanceof(Promise);
48
+
49
+ // prevent unhandled rejection warning
50
+ result.catch(() => null);
51
+ });
52
+ });
package/src/safe.ts ADDED
@@ -0,0 +1,24 @@
1
+ function safe<T>(fn: () => T): T | undefined;
2
+ function safe<T, Y>(fn: () => T, def: Y): T | Y;
3
+
4
+ /* eslint-disable max-len */
5
+ /**
6
+ * Safely execute a function, return its return value or default value if the function throws.
7
+ * @param fn - function to run
8
+ * @param def - default value
9
+ *
10
+ * @example
11
+ * safe(() => JSON.parse(unknownString), null); // if unknownString is not a valid JSON, null will be returned
12
+ * safe(() => trySomethingComplicated(), defaultValue); // if trySomethingComplicated throws, defaultValue will be returned
13
+ */
14
+ function safe<T, Y>(fn: () => T, def?: Y) { // eslint-disable-line func-style
15
+ /* eslint-enable max-len */
16
+ try {
17
+ return fn();
18
+ }
19
+ catch {
20
+ return def;
21
+ }
22
+ }
23
+
24
+ export { safe };
@@ -0,0 +1,20 @@
1
+ import { sortProps } from "./sortProps.js";
2
+
3
+ describe("sort props", () => {
4
+ it("can sort props ascending", () => {
5
+ const sorted = sortProps({ b: 2, a: 1, z: 26 });
6
+ Object.keys(sorted).must.eql(["a", "b", "z"]);
7
+ });
8
+
9
+ it("can sort props descending", () => {
10
+ const sorted = sortProps({ b: 2, a: 1, z: 26 }, false);
11
+ Object.keys(sorted).must.eql(["z", "b", "a"]);
12
+ });
13
+
14
+ it("doesn't modify original object", () => {
15
+ const source = { b: 2, a: 1, z: 26 };
16
+ const sorted = sortProps(source);
17
+ Object.keys(source).must.eql(["b", "a", "z"]);
18
+ Object.keys(sorted).must.eql(["a", "b", "z"]);
19
+ });
20
+ });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Sorts the properties of an object alphabetically, ascending or descending.
3
+ * REMEMBER: In theory JS engines do not guarantee the order of object properties. In practice most popular engines do.
4
+ * @param object - source object
5
+ * @param asc - sort ascending?
6
+ * @example sortProps({ b: 2, a: 1, z: 26 }) // { a: 1, b: 2, z: 26 }
7
+ */
8
+ const sortProps = <T extends Record<string, unknown>>(object: T, asc = true): T => {
9
+ const sorted: Record<string, unknown> = {};
10
+ const keys = Object.keys(object);
11
+ if (asc) { keys.sort(); }
12
+ else { keys.sort().reverse(); }
13
+ for (const key of keys) {
14
+ sorted[key] = object[key];
15
+ }
16
+ return sorted as T;
17
+ };
18
+
19
+ export {
20
+ sortProps,
21
+ };
@@ -0,0 +1,10 @@
1
+ import { unique } from "./unique.js";
2
+
3
+ describe("unique", () => {
4
+ it("returns unique values in array", async () => {
5
+ unique([1, 2, 3, 2, 1]).must.eql([1, 2, 3]);
6
+ unique([{ a: true }, { a: true }]).must.eql([{ a: true }, { a: true }]);
7
+ const a = { a: true };
8
+ unique([a, a]).must.eql([a]);
9
+ });
10
+ });
package/src/unique.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Returns a new array with unique values of given array.
3
+ * @param arr - source array
4
+ * @example unique([1, 2, 3, 2, 1]) // [1, 2, 3]
5
+ */
6
+ const unique = <T extends unknown[]>(arr: T): T => {
7
+ return [...new Set(arr)] as T;
8
+ };
9
+
10
+ export {
11
+ unique,
12
+ };
package/typedoc.cjs ADDED
@@ -0,0 +1,5 @@
1
+ const json = require("./pagesconfig.json");
2
+
3
+ module.exports = {
4
+ pluginPages: json,
5
+ };