diff --git a/README.md b/README.md
index d2df51d..e02102b 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# merge-cells [![Node.js CI](https://github.com/piglovesyou/merge-cells/actions/workflows/node.js.yml/badge.svg)](https://github.com/piglovesyou/merge-cells/actions/workflows/node.js.yml)
+# merge-cells [![Node.js CI](https://github.com/piglovesyou/merge-cells/actions/workflows/node.js.yml/badge.svg)](https://github.com/piglovesyou/merge-cells/actions/workflows/node.js.yml) [![npm version](https://badge.fury.io/js/merge-cells.svg)](https://badge.fury.io/js/merge-cells) [![npm](https://img.shields.io/npm/dw/merge-cells)](https://www.npmjs.com/package/merge-cells) [![Codecov](https://img.shields.io/codecov/c/github/piglovesyou/merge-cells)](https://app.codecov.io/github/piglovesyou/merge-cells)
Provide JavaScript/TypeScript functions to help you merge cells with vertically the same values.
diff --git a/jest.config.js b/jest.config.js
index d750b84..b756ed6 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -193,6 +193,8 @@ const config = {
// Whether to use watchman for file crawling
// watchman: true,
+
+ prettierPath: null,
}
module.exports = config
diff --git a/src/merge-cells.test.ts b/src/merge-cells.test.ts
index 5bb2bbc..725657f 100644
--- a/src/merge-cells.test.ts
+++ b/src/merge-cells.test.ts
@@ -1,114 +1,179 @@
-import { calcRowspanFromObjectArray } from './merge-cells'
+import { calcRowspanFromObjectArray, calcRowspanWithTableRows, mergeCells } from './merge-cells'
+import { JSDOM } from 'jsdom'
describe('lib.test.ts', () => {
- test('merge two on top', () => {
- expect(
- calcRowspanFromObjectArray(
- [
- { c_1: 'a', c_2: 'a' },
- { c_1: 'a', c_2: 'a' },
- { c_1: 'b', c_2: 'a' },
- ],
- ['c_1', 'c_2'],
- ),
- ).toStrictEqual([
- { c_1: 2, c_2: 2 },
- { c_1: 0, c_2: 0 },
- { c_1: 1, c_2: 1 },
- ])
- })
+ describe('calcRowspanFromObjectArray', () => {
+ test('merge two on top', () => {
+ expect(
+ calcRowspanFromObjectArray(
+ [
+ { c_1: 'a', c_2: 'a' },
+ { c_1: 'a', c_2: 'a' },
+ { c_1: 'b', c_2: 'a' },
+ ],
+ ['c_1', 'c_2'],
+ ),
+ ).toStrictEqual([
+ { c_1: 2, c_2: 2 },
+ { c_1: 0, c_2: 0 },
+ { c_1: 1, c_2: 1 },
+ ])
+ })
- test('merge two on bottom', () => {
- expect(
- calcRowspanFromObjectArray(
- [
- { c_1: 'a', c_2: 'a' },
- { c_1: 'b', c_2: 'a' },
- { c_1: 'b', c_2: 'a' },
- ],
- ['c_1', 'c_2'],
- ),
- ).toStrictEqual([
- { c_1: 1, c_2: 1 },
- { c_1: 2, c_2: 2 },
- { c_1: 0, c_2: 0 },
- ])
- })
+ test('merge two on bottom', () => {
+ expect(
+ calcRowspanFromObjectArray(
+ [
+ { c_1: 'a', c_2: 'a' },
+ { c_1: 'b', c_2: 'a' },
+ { c_1: 'b', c_2: 'a' },
+ ],
+ ['c_1', 'c_2'],
+ ),
+ ).toStrictEqual([
+ { c_1: 1, c_2: 1 },
+ { c_1: 2, c_2: 2 },
+ { c_1: 0, c_2: 0 },
+ ])
+ })
- test('merge two on top and bottom', () => {
- expect(
- calcRowspanFromObjectArray(
- [
- { c_1: 'a', c_2: 'a' },
- { c_1: 'a', c_2: 'a' },
- { c_1: 'b', c_2: 'a' },
- { c_1: 'c', c_2: 'a' },
- { c_1: 'c', c_2: 'a' },
- ],
- ['c_1', 'c_2'],
- ),
- ).toStrictEqual([
- { c_1: 2, c_2: 2 },
- { c_1: 0, c_2: 0 },
- { c_1: 1, c_2: 1 },
- { c_1: 2, c_2: 2 },
- { c_1: 0, c_2: 0 },
- ])
- })
+ test('merge two on top and bottom', () => {
+ expect(
+ calcRowspanFromObjectArray(
+ [
+ { c_1: 'a', c_2: 'a' },
+ { c_1: 'a', c_2: 'a' },
+ { c_1: 'b', c_2: 'a' },
+ { c_1: 'c', c_2: 'a' },
+ { c_1: 'c', c_2: 'a' },
+ ],
+ ['c_1', 'c_2'],
+ ),
+ ).toStrictEqual([
+ { c_1: 2, c_2: 2 },
+ { c_1: 0, c_2: 0 },
+ { c_1: 1, c_2: 1 },
+ { c_1: 2, c_2: 2 },
+ { c_1: 0, c_2: 0 },
+ ])
+ })
- test('merge 1st level when values are different on 2nd level', () => {
- expect(
- calcRowspanFromObjectArray(
- [
- { c_1: 'a', c_2: 'a' },
- { c_1: 'a', c_2: 'b' },
- { c_1: 'b', c_2: 'a' },
- { c_1: 'b', c_2: 'b' },
- ],
- ['c_1', 'c_2'],
- ),
- ).toStrictEqual([
- { c_1: 2, c_2: 1 },
- { c_1: 0, c_2: 1 },
- { c_1: 2, c_2: 1 },
- { c_1: 0, c_2: 1 },
- ])
+ test('merge 1st level when values are different on 2nd level', () => {
+ expect(
+ calcRowspanFromObjectArray(
+ [
+ { c_1: 'a', c_2: 'a' },
+ { c_1: 'a', c_2: 'b' },
+ { c_1: 'b', c_2: 'a' },
+ { c_1: 'b', c_2: 'b' },
+ ],
+ ['c_1', 'c_2'],
+ ),
+ ).toStrictEqual([
+ { c_1: 2, c_2: 1 },
+ { c_1: 0, c_2: 1 },
+ { c_1: 2, c_2: 1 },
+ { c_1: 0, c_2: 1 },
+ ])
+ })
+
+ test('not merge 2nd level when values are different on 1st level', () => {
+ expect(
+ calcRowspanFromObjectArray(
+ [
+ { c_1: 'a', c_2: 'a' },
+ { c_1: 'b', c_2: 'a' },
+ { c_1: 'c', c_2: 'a' },
+ ],
+ ['c_1', 'c_2'],
+ ),
+ ).toStrictEqual([
+ { c_1: 1, c_2: 1 },
+ { c_1: 1, c_2: 1 },
+ { c_1: 1, c_2: 1 },
+ ])
+ })
+
+ test('respectColumnLevels: false to merge vertically regardless of column levels', () => {
+ expect(
+ calcRowspanFromObjectArray(
+ [
+ { c_1: 'a', c_2: 'a', c_3: 'c' },
+ { c_1: 'a', c_2: 'b', c_3: 'c' },
+ { c_1: 'b', c_2: 'b', c_3: 'a' },
+ ],
+ ['c_1', 'c_2', 'c_3'],
+ {
+ respectColumnLevels: false,
+ },
+ ),
+ ).toStrictEqual([
+ { c_1: 2, c_2: 1, c_3: 2 },
+ { c_1: 0, c_2: 2, c_3: 0 },
+ { c_1: 1, c_2: 0, c_3: 1 },
+ ])
+ })
})
- test('not merge 2nd level when values are different on 1st level', () => {
- expect(
- calcRowspanFromObjectArray(
- [
- { c_1: 'a', c_2: 'a' },
- { c_1: 'b', c_2: 'a' },
- { c_1: 'c', c_2: 'a' },
- ],
- ['c_1', 'c_2'],
- ),
- ).toStrictEqual([
- { c_1: 1, c_2: 1 },
- { c_1: 1, c_2: 1 },
- { c_1: 1, c_2: 1 },
- ])
+ describe('mergeCells', () => {
+ test('merge cells', () => {
+ document.body.innerHTML = `
+
+
+ 1 |
+ 1 |
+
+
+ 1 |
+ 1 |
+
+
+ 1 |
+ 2 |
+
+
+ 2 |
+ 2 |
+
+
`
+ const table = document.querySelector('table') as HTMLTableElement
+ mergeCells(table)
+ expect(table.innerHTML).toMatchInlineSnapshot(`
+"
+
+ 1 |
+ 1 |
+
+
+ 1 |
+ 1 |
+
+
+ 1 |
+ 2 |
+
+
+ 2 |
+ 2 |
+
+ "
+`)
+ })
+
+ test('pass with an empty table', () => {
+ document.body.innerHTML = `
+ `
+ const table = document.querySelector('table') as HTMLTableElement
+ mergeCells(table)
+ expect(table.innerHTML).toMatchInlineSnapshot(`""`)
+ })
})
- test('merge vertically regardless of levels', () => {
- expect(
- calcRowspanFromObjectArray(
- [
- { c_1: 'a', c_2: 'a', c_3: 'c' },
- { c_1: 'a', c_2: 'b', c_3: 'c' },
- { c_1: 'b', c_2: 'b', c_3: 'a' },
- ],
- ['c_1', 'c_2', 'c_3'],
- {
- respectColumnLevels: false,
- },
- ),
- ).toStrictEqual([
- { c_1: 2, c_2: 1, c_3: 2 },
- { c_1: 0, c_2: 2, c_3: 0 },
- { c_1: 1, c_2: 0, c_3: 1 },
- ])
+ describe('calcRowspanWithTableRows', () => {
+ test('pass with empty rows', () => {
+ expect(calcRowspanWithTableRows({} as HTMLCollectionOf, undefined, {})).toStrictEqual(
+ [],
+ )
+ })
})
})
diff --git a/yarn.lock b/yarn.lock
index 3e87aff..2042db9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1736,7 +1736,7 @@ chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^4.0.0, chalk@^4.1.0:
+chalk@^4.0.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -2032,14 +2032,6 @@ emoji-regex@^8.0.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-enhanced-resolve@^5.0.0:
- version "5.15.0"
- resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35"
- integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==
- dependencies:
- graceful-fs "^4.2.4"
- tapable "^2.2.0"
-
entities@^4.4.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
@@ -2415,7 +2407,7 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
-graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -3373,7 +3365,7 @@ merge-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
-micromatch@4.0.5, micromatch@^4.0.0, micromatch@^4.0.4:
+micromatch@4.0.5, micromatch@^4.0.4:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
@@ -3985,7 +3977,7 @@ semver@^6.0.0, semver@^6.3.0, semver@^6.3.1:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-semver@^7.3.4, semver@^7.5.3, semver@^7.5.4:
+semver@^7.5.3, semver@^7.5.4:
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
@@ -4098,11 +4090,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-source-map@^0.7.4:
- version "0.7.4"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
- integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
-
spdx-correct@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c"
@@ -4285,11 +4272,6 @@ symbol-tree@^3.2.4:
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
-tapable@^2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
- integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
-
test-exclude@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
@@ -4345,17 +4327,6 @@ trim-repeated@^1.0.0:
dependencies:
escape-string-regexp "^1.0.2"
-ts-loader@^9.5.1:
- version "9.5.1"
- resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.1.tgz#63d5912a86312f1fbe32cef0859fb8b2193d9b89"
- integrity sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==
- dependencies:
- chalk "^4.1.0"
- enhanced-resolve "^5.0.0"
- micromatch "^4.0.0"
- semver "^7.3.4"
- source-map "^0.7.4"
-
ts-node@^10.9.2:
version "10.9.2"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f"
@@ -4434,11 +4405,6 @@ typescript@^5.3.3:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
-uglify-js@^3.17.4:
- version "3.17.4"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c"
- integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==
-
unbox-primitive@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"