Ver código fonte

adding tests

aanthonymax 4 meses atrás
pai
commit
b86581a8c5

+ 160 - 19
package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "hmpl-js",
-  "version": "2.2.4",
+  "version": "2.2.6",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "hmpl-js",
-      "version": "2.2.4",
+      "version": "2.2.6",
       "license": "MIT",
       "dependencies": {
         "dompurify": "^3.2.4",
@@ -59,6 +59,27 @@
         "node": ">=6.0.0"
       }
     },
+    "node_modules/@asamuzakjp/css-color": {
+      "version": "2.8.3",
+      "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz",
+      "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@csstools/css-calc": "^2.1.1",
+        "@csstools/css-color-parser": "^3.0.7",
+        "@csstools/css-parser-algorithms": "^3.0.4",
+        "@csstools/css-tokenizer": "^3.0.3",
+        "lru-cache": "^10.4.3"
+      }
+    },
+    "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true,
+      "license": "ISC"
+    },
     "node_modules/@babel/cli": {
       "version": "7.25.9",
       "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.25.9.tgz",
@@ -1739,6 +1760,121 @@
         "@jridgewell/sourcemap-codec": "^1.4.10"
       }
     },
+    "node_modules/@csstools/color-helpers": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz",
+      "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT-0",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@csstools/css-calc": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.2.tgz",
+      "integrity": "sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@csstools/css-parser-algorithms": "^3.0.4",
+        "@csstools/css-tokenizer": "^3.0.3"
+      }
+    },
+    "node_modules/@csstools/css-color-parser": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.8.tgz",
+      "integrity": "sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "@csstools/color-helpers": "^5.0.2",
+        "@csstools/css-calc": "^2.1.2"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@csstools/css-parser-algorithms": "^3.0.4",
+        "@csstools/css-tokenizer": "^3.0.3"
+      }
+    },
+    "node_modules/@csstools/css-parser-algorithms": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz",
+      "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "peerDependencies": {
+        "@csstools/css-tokenizer": "^3.0.3"
+      }
+    },
+    "node_modules/@csstools/css-tokenizer": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz",
+      "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/csstools"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/csstools"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/@esbuild/aix-ppc64": {
       "version": "0.24.0",
       "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz",
@@ -3213,14 +3349,11 @@
       }
     },
     "node_modules/agent-base": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
-      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
+      "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
       "dev": true,
       "license": "MIT",
-      "dependencies": {
-        "debug": "^4.3.4"
-      },
       "engines": {
         "node": ">= 14"
       }
@@ -3776,18 +3909,26 @@
       }
     },
     "node_modules/cssstyle": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz",
-      "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==",
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz",
+      "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "rrweb-cssom": "^0.7.1"
+        "@asamuzakjp/css-color": "^2.8.2",
+        "rrweb-cssom": "^0.8.0"
       },
       "engines": {
         "node": ">=18"
       }
     },
+    "node_modules/cssstyle/node_modules/rrweb-cssom": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
+      "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/data-urls": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
@@ -4673,13 +4814,13 @@
       }
     },
     "node_modules/https-proxy-agent": {
-      "version": "7.0.5",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
-      "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+      "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
-        "agent-base": "^7.0.2",
+        "agent-base": "^7.1.2",
         "debug": "4"
       },
       "engines": {
@@ -7251,9 +7392,9 @@
       }
     },
     "node_modules/whatwg-url": {
-      "version": "14.0.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
-      "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
+      "version": "14.1.1",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz",
+      "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==",
       "dev": true,
       "license": "MIT",
       "dependencies": {

+ 1 - 1
src/main.ts

@@ -191,7 +191,7 @@ const DEFAULT_DISALLOWED_TAGS: HMPLDisallowedTags = [];
 const getTemplateWrapper = (str: string, sanitize: boolean = false) => {
   let sanitizedStr = str;
   if (sanitize) {
-    sanitizedStr = DOMPurify.sanitize(str);
+    sanitizedStr = (window as any).DOMPurify.sanitize(str);
   }
   const elementDocument = new DOMParser().parseFromString(
     `<template>${sanitizedStr}</template>`,

+ 4 - 0
test/config/config.ts

@@ -8,6 +8,8 @@ const INDICATORS = `indicators`;
 const AUTO_BODY = `autoBody`;
 const COMMENT = `hmpl`;
 const FORM_DATA = `formData`;
+const DISALLOWED_TAGS = `disallowedTags`;
+const SANITIZE = `sanitize`;
 const ALLOWED_CONTENT_TYPES = "allowedContentTypes";
 const REQUEST_INIT_GET = `get`;
 const RESPONSE_ERROR = `BadResponseError`;
@@ -31,6 +33,8 @@ export {
   AUTO_BODY,
   COMMENT,
   FORM_DATA,
+  DISALLOWED_TAGS,
+  SANITIZE,
   ALLOWED_CONTENT_TYPES,
   REQUEST_INIT_GET,
   RESPONSE_ERROR,

+ 47 - 3
test/core/compile.test.ts

@@ -12,7 +12,9 @@ import {
   REQUEST_OBJECT_ERROR,
   COMPILE_OPTIONS_ERROR,
   SOURCE,
-  AFTER
+  AFTER,
+  DISALLOWED_TAGS,
+  SANITIZE
 } from "../config/config";
 
 import { checkFunction } from "../shared/utils";
@@ -44,7 +46,7 @@ describe("compile function", () => {
   e(
     `only accepts the '${MEMO}' property in the COMPILE OPTIONS as a boolean`,
     () => compile("some template", { memo: 123 as unknown as boolean }),
-    `${COMPILE_OPTIONS_ERROR}: The value of the property ${MEMO} must be a boolean value`
+    `${COMPILE_OPTIONS_ERROR}: The value of the property ${MEMO} must be a boolean`
   );
 
   e(
@@ -142,7 +144,30 @@ describe("compile function", () => {
       }),
     `${COMPILE_OPTIONS_ERROR}: In the array, the element with index 0 is not a string`
   );
-
+  e(
+    ``,
+    () =>
+      compile(createTestObj2(`{{ "src":"/api/test" }}`), {
+        disallowedTags: true as any
+      }),
+    `${COMPILE_OPTIONS_ERROR}: The value of the property "${DISALLOWED_TAGS}" must be an array`
+  );
+  e(
+    ``,
+    () =>
+      compile(createTestObj2(`{{ "src":"/api/test" }}`), {
+        disallowedTags: ["div" as any]
+      }),
+    `${COMPILE_OPTIONS_ERROR}: The value "div" is not processed`
+  );
+  e(
+    ``,
+    () =>
+      compile(createTestObj2(`{{ "src":"/api/test" }}`), {
+        sanitize: ["div"] as any
+      }),
+    `${COMPILE_OPTIONS_ERROR}: The value of the property "${SANITIZE}" must be a boolean`
+  );
   e(
     `throws an error if the '${SOURCE}' property in the REQUEST OBJECT is an array instead of a string`,
     () => compile(createTestObj1({ [SOURCE]: [] })),
@@ -266,6 +291,25 @@ describe("compile function", () => {
       ),
     `${REQUEST_OBJECT_ERROR}: The "${MODE}" property doesn't work without "${AFTER}" property`
   );
+  e(
+    ``,
+    () =>
+      compile(createTestObj2(`{{ "src":"/api/test", "disallowedTags":true }}`)),
+    `${REQUEST_OBJECT_ERROR}: The value of the property "${DISALLOWED_TAGS}" must be an array`
+  );
+  e(
+    ``,
+    () =>
+      compile(
+        createTestObj2(`{{ "src":"/api/test", disallowedTags: ["div"] }}`)
+      ),
+    `${REQUEST_OBJECT_ERROR}: The value "div" is not processed`
+  );
+  e(
+    ``,
+    () => compile(createTestObj2(`{{ "src":"/api/test", sanitize: ["div"] }}`)),
+    `${REQUEST_OBJECT_ERROR}: The value of the property "${SANITIZE}" must be a boolean`
+  );
   eq(
     `returns a template function when provided a TEMPLATE with just ${SOURCE} property`,
     checkFunction(compile(createTestObj2(`{{ "src":"/api/test" }}`))),

+ 68 - 1
test/core/template-function.test.ts

@@ -9,6 +9,8 @@ import {
   REQUEST_INIT_ERROR,
   REQUEST_INIT_GET
 } from "../config/config";
+import { JSDOM } from "jsdom";
+import createDOMPurify from "dompurify";
 import { compile, stringify } from "../../src/main";
 import {
   waeq,
@@ -586,7 +588,9 @@ describe("template function", () => {
     {}
   );
   aeq(
-    createTestObj2(`{{ "src":"${BASE_URL}/api/test" }}`),
+    createTestObj2(
+      `{{ "src":"${BASE_URL}/api/test", disallowedTags:["script"] }}`
+    ),
     (res, prop, value) => {
       switch (prop) {
         case "response":
@@ -603,6 +607,69 @@ describe("template function", () => {
       template: "<div>123</div><script></script>"
     }
   );
+  aeq(
+    createTestObj2(
+      `{{ "src":"${BASE_URL}/api/test", disallowedTags:["script"] }}`
+    ),
+    (res, prop, value) => {
+      switch (prop) {
+        case "response":
+          if (value?.outerHTML === `<div><div>123</div></div>`) {
+            res(true);
+          } else {
+            res(false);
+          }
+          break;
+      }
+    },
+    {},
+    {
+      template: "<div>123</div><script></script>"
+    },
+    {
+      disallowedTags: ["style"]
+    }
+  );
+  aeq(
+    createTestObj2(`{{ "src":"${BASE_URL}/api/test", sanitize:true }}`),
+    (res, prop, value) => {
+      switch (prop) {
+        case "response":
+          if (value?.outerHTML === `<div><div>123</div></div>`) {
+            res(true);
+          } else {
+            res(false);
+          }
+          break;
+      }
+    },
+    {},
+    {
+      template: "<div>123</div><script></script>"
+    },
+    {}
+  );
+  aeq(
+    createTestObj2(`{{ "src":"${BASE_URL}/api/test", sanitize:true }}`),
+    (res, prop, value) => {
+      switch (prop) {
+        case "response":
+          if (value?.outerHTML === `<div><div>123</div></div>`) {
+            res(true);
+          } else {
+            res(false);
+          }
+          break;
+      }
+    },
+    {},
+    {
+      template: "<div>123</div><script></script>"
+    },
+    {
+      sanitize: false
+    }
+  );
   aeq(
     createTestObj2(`{{ "src":"${BASE_URL}/api/test" }}`),
     (res, prop, value) => {

+ 9 - 0
test/setup/setup.ts

@@ -1,3 +1,12 @@
 require("jsdom-global")();
+const { JSDOM } = require("jsdom");
+const createDOMPurify = require("dompurify");
 
 global.DOMParser = window.DOMParser;
+
+const jsdom = new JSDOM("");
+(global as any).window = jsdom.window;
+(global as any).document = jsdom.window.document;
+const DOMPurifyInstance = createDOMPurify(jsdom.window);
+(global as any).DOMPurify = DOMPurifyInstance;
+(global as any).window.DOMPurify = DOMPurifyInstance;

+ 2 - 1
tsconfig.json

@@ -23,7 +23,8 @@
     "skipLibCheck": true,
     "outDir": "./build",
     "paths": {
-      "json5": ["./node_modules/json5/lib/index"]
+      "json5": ["./node_modules/json5/lib/index"],
+      "dompurify": ["./node_modules/dompurify/dist/purify"]
     }
   },
   "include": ["./src/**/*"],