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 = ` + + + + + + + + + + + + + + + + + +
11
11
12
22
` + 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"