feed-common 1.51.6 → 1.52.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [1.52.0](https://github.com/advertikon/package-maxify-feed-common/compare/v1.51.6...v1.52.0) (2024-10-13)
2
+
3
+
4
+ ### Features
5
+
6
+ * add some source tag util functions ([b53def7](https://github.com/advertikon/package-maxify-feed-common/commit/b53def7e09e6f0842766d55dc5cff84afb282b61))
7
+
1
8
  ## [1.51.6](https://github.com/advertikon/package-maxify-feed-common/compare/v1.51.5...v1.51.6) (2024-10-13)
2
9
 
3
10
 
@@ -1,4 +1,14 @@
1
- import { MacroPartType } from '../types/profile.types.js';
1
+ import { MacroPartType, SelectItem } from '../types/profile.types.js';
2
2
  export declare function code(): string;
3
3
  export declare function parseMacrosString(textContent: string): MacroPartType[];
4
+ export declare function isJSON(input: any): input is string;
5
+ export declare function isSourceJSON(input: any): boolean;
6
+ export declare function getSourceTagParts(content: string): {
7
+ tag: string;
8
+ value: string | null;
9
+ };
10
+ export declare function getSourceTagValue(content: string): {
11
+ tag: string;
12
+ value: SelectItem[] | null;
13
+ };
4
14
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,wBAAgB,IAAI,WAEnB;AAED,wBAAgB,iBAAiB,CAAE,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CA4DvE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEtE,wBAAgB,IAAI,WAEnB;AAED,wBAAgB,iBAAiB,CAAE,WAAW,EAAE,MAAM,GAAG,aAAa,EAAE,CA4DvE;AAeD,wBAAgB,MAAM,CAAC,KAAK,EAAE,GAAG,GAAG,KAAK,IAAI,MAAM,CAOhD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAYhD;AAEH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAMA;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;CAC5B,CAOA"}
@@ -60,4 +60,36 @@ function getMacroSubtype(tagValue) {
60
60
  return 'mapping';
61
61
  }
62
62
  }
63
+ export function isJSON(input) {
64
+ try {
65
+ JSON.parse(input);
66
+ return true;
67
+ }
68
+ catch (e) {
69
+ return false;
70
+ }
71
+ }
72
+ export function isSourceJSON(input) {
73
+ if (!isJSON(input)) {
74
+ return false;
75
+ }
76
+ const content = JSON.parse(input);
77
+ if (Array.isArray(content)) {
78
+ return content.every((item) => item?.label !== undefined && item?.value !== undefined);
79
+ }
80
+ return content?.label !== undefined && content?.value !== undefined;
81
+ }
82
+ export function getSourceTagParts(content) {
83
+ const splitPoint = content.indexOf(":");
84
+ const tag = splitPoint !== -1 ? content.slice(0, splitPoint) : content;
85
+ const value = splitPoint !== -1 ? content.slice(splitPoint + 1) : null;
86
+ return { tag, value };
87
+ }
88
+ export function getSourceTagValue(content) {
89
+ const splitPoint = content.indexOf(":");
90
+ const tag = splitPoint !== -1 ? content.slice(0, splitPoint) : content;
91
+ const valueText = splitPoint !== -1 ? content.slice(splitPoint + 1) : null;
92
+ const value = isSourceJSON(valueText) ? JSON.parse(valueText) : null;
93
+ return { tag, value: value && !Array.isArray(value) ? [value] : value };
94
+ }
63
95
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,IAAI;IAChB,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAE,WAAmB;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC;IACrB,MAAM,QAAQ,GAAG,IAAI,CAAC;IACtB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,KAAK,GAAoB,EAAE,CAAC;IAElC,IAAI,CAAC,WAAW,EAAE,CAAC;QACf,OAAO;YACH;gBACI,OAAO,EAAE,EAAE;gBACX,IAAI,EAAE,QAAQ;aACjB;SACJ,CAAC;IACN,CAAC;IAED,OAAO,QAAQ,KAAK,CAAC,CAAC,IAAI,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC;QACtD,MAAM,YAAY,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAE5D,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC;gBACxC,IAAI,EAAE,QAAQ;aACjB,CAAC,CAAC;YACH,MAAM;QACV,CAAC;aAAM,IAAI,YAAY,GAAG,QAAQ,EAAE,CAAC;YACjC,KAAK,CAAC,IAAI,CAAC;gBACP,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC;gBACtD,IAAI,EAAE,QAAQ;aACjB,CAAC,CAAC;QACP,CAAC;QAED,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAE/D,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACX,oDAAoD,WAAW,mBAAmB,YAAY,EAAE,CACnG,CAAC;QACN,CAAC;QAED,wGAAwG;QACxG,MAAM,mBAAmB,GAAG,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAExF,IAAI,mBAAmB,KAAK,CAAC,CAAC,IAAI,mBAAmB,GAAG,UAAU,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CACX,6DAA6D,WAAW,mBAAmB,YAAY,EAAE,CAC5G,CAAC;QACN,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,CAAC,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAElF,KAAK,CAAC,IAAI,CAAC;YACP,OAAO,EAAE,QAAQ,CAAC,IAAI,EAAE;YACxB,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,eAAe,CAAC,QAAQ,CAAC;SACrC,CAAC,CAAC;QAEH,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC5C,CAAC;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,SAAS,eAAe,CAAE,QAAgB;IACtC,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACpC,KAAK,QAAQ;YACT,OAAO,QAAQ,CAAC;QACpB,KAAK,WAAW;YACZ,OAAO,WAAW,CAAC;QACvB,KAAK,QAAQ;YACT,OAAO,QAAQ,CAAC;QACpB;YACI,OAAO,SAAS,CAAC;IACzB,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feed-common",
3
- "version": "1.51.6",
3
+ "version": "1.52.0",
4
4
  "description": "Maxify feed common library",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,4 +1,4 @@
1
- import { MacroPartType } from '../types/profile.types.js';
1
+ import { MacroPartType, SelectItem } from '../types/profile.types.js';
2
2
 
3
3
  export function code () {
4
4
  return (Math.random() * 1000000).toFixed(0);
@@ -78,3 +78,49 @@ function getMacroSubtype (tagValue: string): MacroPartType['subtype'] {
78
78
  return 'mapping';
79
79
  }
80
80
  }
81
+
82
+ export function isJSON(input: any): input is string {
83
+ try {
84
+ JSON.parse(input);
85
+ return true;
86
+ } catch (e) {
87
+ return false;
88
+ }
89
+ }
90
+
91
+ export function isSourceJSON(input: any): boolean {
92
+ if (!isJSON(input)) {
93
+ return false;
94
+ }
95
+
96
+ const content = JSON.parse(input);
97
+
98
+ if (Array.isArray(content)) {
99
+ return content.every((item) => item?.label !== undefined && item?.value !== undefined);
100
+ }
101
+
102
+ return content?.label !== undefined && content?.value !== undefined;
103
+ }
104
+
105
+ export function getSourceTagParts(content: string): {
106
+ tag: string;
107
+ value: string | null;
108
+ } {
109
+ const splitPoint = content.indexOf(":");
110
+ const tag = splitPoint !== -1 ? content.slice(0, splitPoint) : content;
111
+ const value = splitPoint !== -1 ? content.slice(splitPoint + 1) : null;
112
+
113
+ return { tag, value };
114
+ }
115
+
116
+ export function getSourceTagValue(content: string): {
117
+ tag: string;
118
+ value: SelectItem[] | null;
119
+ } {
120
+ const splitPoint = content.indexOf(":");
121
+ const tag = splitPoint !== -1 ? content.slice(0, splitPoint) : content;
122
+ const valueText = splitPoint !== -1 ? content.slice(splitPoint + 1) : null;
123
+ const value = isSourceJSON(valueText) ? JSON.parse(valueText as string) : null;
124
+
125
+ return { tag, value: value && !Array.isArray(value) ? [value] : value };
126
+ }
@@ -0,0 +1,43 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import { getSourceTagParts, getSourceTagValue, isJSON, isSourceJSON } from "../src/utils/utils";
3
+
4
+ describe("Utils", () => {
5
+ describe('Source tag', () => {
6
+ test('isJson', () => {
7
+ expect(isJSON('{"hello": "world"}')).toBe(true);
8
+ expect(isJSON('[{"hello": "world"}]')).toBe(true);
9
+ expect(isJSON(1)).toBe(true);
10
+ expect(isJSON('1')).toBe(true);
11
+ expect(isJSON(null)).toBe(true);
12
+
13
+ expect(isJSON('{"hello": "world"')).toBe(false);
14
+ });
15
+
16
+ test('isSourceJSON', () => {
17
+ expect(isSourceJSON('{"label": "hello", "value": "world"}')).toBe(true);
18
+ expect(isSourceJSON('[{"label": "hello", "value": "world"}]')).toBe(true);
19
+
20
+ expect(isSourceJSON('{"label": "hello", "value": "world"')).toBe(false);
21
+ expect(isSourceJSON('{"label": "hello": "key": "world"}')).toBe(false);
22
+ expect(isSourceJSON(1)).toBe(false);
23
+ expect(isSourceJSON('1')).toBe(false);
24
+ expect(isSourceJSON(null)).toBe(false);
25
+ });
26
+
27
+ test('getSourceTagParts', () => {
28
+ expect(getSourceTagParts('source.world')).toEqual({ tag: 'source.world', value: null });
29
+ expect(getSourceTagParts('source.world:hello')).toEqual({ tag: 'source.world', value: 'hello' });
30
+ expect(getSourceTagParts('source.world:')).toEqual({ tag: 'source.world', value: '' });
31
+ expect(getSourceTagParts('source.world:hello:world')).toEqual({ tag: 'source.world', value: 'hello:world' });
32
+ })
33
+
34
+ test('getSourceTagValue', () => {
35
+ expect(getSourceTagValue('source.world')).toEqual({ tag: 'source.world', value: null });
36
+ expect(getSourceTagValue('source.world:hello')).toEqual({ tag: 'source.world', value: null });
37
+ expect(getSourceTagValue('source.world:hello:world')).toEqual({ tag: 'source.world', value: null });
38
+ expect(getSourceTagValue('source.world:')).toEqual({ tag: 'source.world', value: null });
39
+ expect(getSourceTagValue('source.world:{"label": "hello", "value": "world"}')).toEqual({ tag: 'source.world', value: [{ label: 'hello', value: 'world' }] });
40
+ expect(getSourceTagValue('source.world:[{"label": "hello", "value": "world"}]')).toEqual({ tag: 'source.world', value: [{ label: 'hello', value: 'world' }] });
41
+ });
42
+ });
43
+ });
@@ -9,21 +9,19 @@ describe("Validator", () => {
9
9
  expect(hasMacro('Hello {{source.world}} {{source.world:any value}}')).toBe(false);
10
10
  });
11
11
 
12
- test('language validation', () => {
13
- expect(languageSchema.safeParse('en').success).toBe(true);
14
- expect(languageSchema.safeParse('ES').success).toBe(true);
15
- expect(languageSchema.safeParse('ES\nES').success).toBe(false);
16
- expect(languageSchema.safeParse('').success).toBe(true);
17
- expect(validateIfNoMacro('en', languageSchema).success).toBe(true);
18
- expect(validateIfNoMacro('{{source.language:en}}', [languageSchema, z.string().min(1)]).success).toBe(true);
19
- expect(validateIfNoMacro('{{source.language:foo}}', [languageSchema, z.string().min(1)]).success).toBe(false);
20
- expect(validateIfNoMacro('{{source.language:}}', [languageSchema, z.string().min(2)]).success).toBe(false);
21
- })
22
-
23
12
  test('multiple validators', () => {
24
- expect(validateIfNoMacro('en', [languageSchema]).success).toBe(true);
25
- expect(validateIfNoMacro('', [languageSchema]).success).toBe(true);
26
- expect(validateIfNoMacro('', [languageSchema, z.string().min(1)]).success).toBe(false);
13
+ expect(validateIfNoMacro('en', [z.string(), z.string().min(2)]).success).toBe(true);
14
+ expect(validateIfNoMacro('en', [z.string(), z.string().min(3)]).success).toBe(false);
15
+ expect(validateIfNoMacro('en', [z.number(), z.string().min(2)]).success).toBe(false);
27
16
  });
17
+
18
+ describe('language validate', () => {
19
+ test('languageSchema', () => {
20
+ expect(languageSchema.safeParse('en').success).toBe(true);
21
+ expect(languageSchema.safeParse('ES').success).toBe(true);
22
+ expect(languageSchema.safeParse('ES\nES').success).toBe(false);
23
+ expect(languageSchema.safeParse('').success).toBe(true);
24
+ })
25
+ })
28
26
  });
29
27