From 27daaa3554d7f035fdea86341a2b689bf31cfbce Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Fri, 22 May 2026 18:31:06 -0400 Subject: [PATCH 1/6] chore(deps): install Fallow code analysis tool --- .fallowrc.json | 14 +++ .gitignore | 3 +- package.json | 7 ++ .../common/src/filters/filterUtilities.ts | 2 +- packages/excel-export/src/excelUtils.ts | 4 +- packages/graphql/src/services/index.ts | 1 - .../components/slick-vanilla-grid-bundle.ts | 2 - pnpm-lock.yaml | 85 +++++++++++++++++++ pnpm-workspace.yaml | 13 +-- 9 files changed, 118 insertions(+), 13 deletions(-) create mode 100644 .fallowrc.json diff --git a/.fallowrc.json b/.fallowrc.json new file mode 100644 index 0000000000..0a7d377e49 --- /dev/null +++ b/.fallowrc.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json", + "entry": ["src/index.ts", "src/main.ts"], + "ignorePatterns": ["**/package.json", "/__tests__/"], + "workspaces": { + "packages": ["frameworks/**", "frameworks-plugins/**", "packages/**", "!**/dist/**"] + }, + "duplicates": { + "minOccurrences": 3 + }, + "rules": { + "unused-dependencies": "warn" + } +} diff --git a/.gitignore b/.gitignore index e1c1fac30e..f3e6c48ae0 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ jest-coverage test/cypress/screenshots/*.png # Environment variables -.env \ No newline at end of file +.env +.fallow/ diff --git a/package.json b/package.json index 93bfa18521..d878aec8b8 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,12 @@ "roll-new-release": "pnpm build && pnpm new-version && pnpm new-publish", "build:dev": "pnpm -r --filter=vanilla-demo build:dev", "serve:vite": "pnpm -r --filter=vanilla-demo dev", + "fallow": "fallow", + "fallow:dead-code": "fallow dead-code", + "fallow:dupes": "fallow dupes", + "fallow:health": "fallow health", + "fallow:fix:preview": "fallow fix --dry-run", + "fallow:fix": "fallow fix", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "prettier:check": "prettier --check **/*.{html,js,ts,tsx,vue}", @@ -129,6 +135,7 @@ "cypress-real-events": "catalog:", "eslint-plugin-cypress": "^6.4.1", "eslint-plugin-local-import-ext": "0.2.0", + "fallow": "^2.76.0", "globals": "catalog:", "jsdom": "catalog:", "jsdom-global": "catalog:", diff --git a/packages/common/src/filters/filterUtilities.ts b/packages/common/src/filters/filterUtilities.ts index ea409403f4..ff2a9c846d 100644 --- a/packages/common/src/filters/filterUtilities.ts +++ b/packages/common/src/filters/filterUtilities.ts @@ -96,7 +96,7 @@ export async function renderCollectionOptionsAsync( } /** Create or recreate an Observable Subject and reassign it to the "collectionAsync" object so user can call a "collectionAsync.next()" on it */ -export function createCollectionAsyncSubject( +function createCollectionAsyncSubject( columnDef: Column, renderDomElementCallback: (collection: any) => void, rxjs?: RxJsFacade, diff --git a/packages/excel-export/src/excelUtils.ts b/packages/excel-export/src/excelUtils.ts index 46a52c4833..c2fd2de140 100644 --- a/packages/excel-export/src/excelUtils.ts +++ b/packages/excel-export/src/excelUtils.ts @@ -22,7 +22,7 @@ export const getExcelNumberCallback: GetDataValueCallback = (data, { columnDef, }); /** Parse a number which the user might have provided formatter options (for example a user might have provided { decimalSeparator: ',', thousandSeparator: ' '}) */ -export function parseNumberWithFormatterOptions(value: any, column: Column, gridOptions: GridOption): any { +function parseNumberWithFormatterOptions(value: any, column: Column, gridOptions: GridOption): any { let outValue = value; if (typeof value === 'string' && value) { const decimalSeparator = getValueFromParamsOrFormatterOptions( @@ -126,7 +126,7 @@ export function getNumericFormatterOptions( return retrieveFormatterOptions(columnDef, grid, dataType!, formatterType); } -export function getFormatterNumericDataType(formatter?: Formatter): 'currency' | 'decimal' | 'percent' { +function getFormatterNumericDataType(formatter?: Formatter): 'currency' | 'decimal' | 'percent' { let dataType: 'currency' | 'decimal' | 'percent' | 'regular'; switch (formatter) { diff --git a/packages/graphql/src/services/index.ts b/packages/graphql/src/services/index.ts index f39ef8772c..16c26e4ee1 100644 --- a/packages/graphql/src/services/index.ts +++ b/packages/graphql/src/services/index.ts @@ -1,2 +1 @@ export * from './graphql.service.js'; -export { default as GraphqlQueryBuilder } from './graphqlQueryBuilder.js'; diff --git a/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts b/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts index ee1997af6c..41ff1eb49f 100644 --- a/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts +++ b/packages/vanilla-bundle/src/components/slick-vanilla-grid-bundle.ts @@ -107,8 +107,6 @@ export class SlickVanillaGridBundle { extensionService!: ExtensionService; filterFactory!: FilterFactory; filterService!: FilterService; - gridClass!: string; - gridClassName!: string; gridEventService!: GridEventService; gridService!: GridService; gridStateService!: GridStateService; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9acbaa4982..1d63256f43 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -203,6 +203,9 @@ importers: eslint-plugin-local-import-ext: specifier: 0.2.0 version: 0.2.0 + fallow: + specifier: ^2.76.0 + version: 2.76.0 globals: specifier: 'catalog:' version: 17.6.0 @@ -2392,6 +2395,46 @@ packages: resolution: {integrity: sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} + '@fallow-cli/darwin-arm64@2.76.0': + resolution: {integrity: sha512-6yspnFAzVXErJlucLPmZwzTOvN38WWaMioeLjU8HiOEqtacoI4tS/vUutGPnQYV7iZ4dRnZGvj/9lEodMs2YGg==} + cpu: [arm64] + os: [darwin] + + '@fallow-cli/darwin-x64@2.76.0': + resolution: {integrity: sha512-5ARqPI4Jo+1D6TB7QA7XZy42SkKfokK9buUhsW5vN869bPm3seB3/NcBZSAboV9PVLjvdg0w2Gow53ltMn6xmA==} + cpu: [x64] + os: [darwin] + + '@fallow-cli/linux-arm64-gnu@2.76.0': + resolution: {integrity: sha512-1QFtpLGBO5mqi5CU2Yq1z7mZQlhtI4sGq7oQIYEqYAccN8aP35iRVQU64VC+bUmurfKMlNB1eIh0nmVNuf24NA==} + cpu: [arm64] + os: [linux] + + '@fallow-cli/linux-arm64-musl@2.76.0': + resolution: {integrity: sha512-NqYwMJYEQcG5l9szwxJunySbLTABkQUwdi8lB+1iJ9ONABvjOAR2fUBNAYRdxE/iAOcf7WvfJFepk2GTUz3fCg==} + cpu: [arm64] + os: [linux] + + '@fallow-cli/linux-x64-gnu@2.76.0': + resolution: {integrity: sha512-lrVeUbPeQpPndTyBKPlOHzwws4flkJ5dCzn4MPtzTwnGfdNXOtHQtSX2XDaDuUhAMG9FSEfhQsNEZk0bmsO6OA==} + cpu: [x64] + os: [linux] + + '@fallow-cli/linux-x64-musl@2.76.0': + resolution: {integrity: sha512-RoIS2W+ZKi0TghZiPZlMj2Ecxj7cK928eU+VVPhLjKm5pg3kumKSuA9wu8OFWyJ7OrbHPU1uWMOBJj6+l9KzsA==} + cpu: [x64] + os: [linux] + + '@fallow-cli/win32-arm64-msvc@2.76.0': + resolution: {integrity: sha512-sjTIR4L5Vr3x4wUWiHbdAbKWm6QSIK1tQUej11kX8Ucm/khXByG/Dy3Jhh3KuYrf1walVDvXcjCWeHPQioKUpg==} + cpu: [arm64] + os: [win32] + + '@fallow-cli/win32-x64-msvc@2.76.0': + resolution: {integrity: sha512-9m6hvgEUiqZ/r0C16eJ+eXk1kTRmRy980GzCKKdDNUdd9v9gcdFqhaj8f6ChAjfcC0JOMyfoHZ+WSRSpiTyQOg==} + cpu: [x64] + os: [win32] + '@floating-ui/core@1.7.5': resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} @@ -5568,6 +5611,11 @@ packages: resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} engines: {'0': node >=0.6.0} + fallow@2.76.0: + resolution: {integrity: sha512-Z/09g/mPw4wkkbA5nuL7P9k7hbdQ4QpYxmgX+z4RzsosGa3BFfkaBoaMeqdo0ERU529WnbWjnRjY4QLyVyCOIQ==} + engines: {node: '>=16'} + hasBin: true + fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -9111,6 +9159,30 @@ snapshots: '@faker-js/faker@10.4.0': {} + '@fallow-cli/darwin-arm64@2.76.0': + optional: true + + '@fallow-cli/darwin-x64@2.76.0': + optional: true + + '@fallow-cli/linux-arm64-gnu@2.76.0': + optional: true + + '@fallow-cli/linux-arm64-musl@2.76.0': + optional: true + + '@fallow-cli/linux-x64-gnu@2.76.0': + optional: true + + '@fallow-cli/linux-x64-musl@2.76.0': + optional: true + + '@fallow-cli/win32-arm64-msvc@2.76.0': + optional: true + + '@fallow-cli/win32-x64-msvc@2.76.0': + optional: true + '@floating-ui/core@1.7.5': dependencies: '@floating-ui/utils': 0.2.11 @@ -12951,6 +13023,19 @@ snapshots: extsprintf@1.3.0: {} + fallow@2.76.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + '@fallow-cli/darwin-arm64': 2.76.0 + '@fallow-cli/darwin-x64': 2.76.0 + '@fallow-cli/linux-arm64-gnu': 2.76.0 + '@fallow-cli/linux-arm64-musl': 2.76.0 + '@fallow-cli/linux-x64-gnu': 2.76.0 + '@fallow-cli/linux-x64-musl': 2.76.0 + '@fallow-cli/win32-arm64-msvc': 2.76.0 + '@fallow-cli/win32-x64-msvc': 2.76.0 + fast-content-type-parse@3.0.0: {} fast-deep-equal@3.1.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 57f5f802cd..b5fed06908 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,12 +5,6 @@ packages: - packages/** - '!**/dist/**' -minimumReleaseAge: 2880 # 2 days in minutes -minimumReleaseAgeExclude: - # exclude packages that I personally maintain and are safe to use on the same day - - '@lerna-lite/*' - - 'eslint-plugin-local-import-ext' - catalog: '@4tw/cypress-drag-drop': ^2.3.1 '@angular-eslint/eslint-plugin': ^21.4.0 @@ -56,6 +50,13 @@ catalog: vitest: ^5.0.0-beta.2 vue: ^3.5.34 +minimumReleaseAge: 2880 # 2 days in minutes + +minimumReleaseAgeExclude: + # exclude packages that I personally maintain and are safe to use on the same day + - '@lerna-lite/*' + - eslint-plugin-local-import-ext + overrides: '@hono/node-server': ^2.0.2 '@isaacs/brace-expansion': ^5.0.1 From b1444b35b61c201395b6c30d9eb730839a4a84c4 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Fri, 22 May 2026 18:41:43 -0400 Subject: [PATCH 2/6] chore: improve fallow config & usage --- .fallowrc.json | 2 +- frameworks/slickgrid-react/src/contexts/i18nextContext.ts | 1 - frameworks/slickgrid-react/src/services/singletons.ts | 4 ---- package.json | 6 +++--- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/.fallowrc.json b/.fallowrc.json index 0a7d377e49..209bc55b67 100644 --- a/.fallowrc.json +++ b/.fallowrc.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json", "entry": ["src/index.ts", "src/main.ts"], - "ignorePatterns": ["**/package.json", "/__tests__/"], + "ignorePatterns": ["**/package.json", "/__tests__/", "**/demos/**"], "workspaces": { "packages": ["frameworks/**", "frameworks-plugins/**", "packages/**", "!**/dist/**"] }, diff --git a/frameworks/slickgrid-react/src/contexts/i18nextContext.ts b/frameworks/slickgrid-react/src/contexts/i18nextContext.ts index 1c4777dd48..e4f41797ef 100644 --- a/frameworks/slickgrid-react/src/contexts/i18nextContext.ts +++ b/frameworks/slickgrid-react/src/contexts/i18nextContext.ts @@ -3,4 +3,3 @@ import type { I18Next } from '../models/i18next.interface.js'; export const I18nextContext = React.createContext(null); export const I18nextProvider = I18nextContext.Provider; -export const useI18next = () => React.useContext(I18nextContext); diff --git a/frameworks/slickgrid-react/src/services/singletons.ts b/frameworks/slickgrid-react/src/services/singletons.ts index ad1ca31623..fa0357d360 100644 --- a/frameworks/slickgrid-react/src/services/singletons.ts +++ b/frameworks/slickgrid-react/src/services/singletons.ts @@ -1,7 +1,3 @@ -import { SharedService } from '@slickgrid-universal/common'; -import { EventPubSubService } from '@slickgrid-universal/event-pub-sub'; import { ContainerService } from './container.service.js'; -export const GlobalEventPubSubService = new EventPubSubService(); -export const GlobalEventSharedService = new SharedService(); export const GlobalContainerService = new ContainerService(); diff --git a/package.json b/package.json index d878aec8b8..1cf2387cfa 100644 --- a/package.json +++ b/package.json @@ -49,11 +49,11 @@ "build:dev": "pnpm -r --filter=vanilla-demo build:dev", "serve:vite": "pnpm -r --filter=vanilla-demo dev", "fallow": "fallow", - "fallow:dead-code": "fallow dead-code", + "fallow:dead-code": "fallow dead-code --production", "fallow:dupes": "fallow dupes", "fallow:health": "fallow health", - "fallow:fix:preview": "fallow fix --dry-run", - "fallow:fix": "fallow fix", + "fallow:fix:preview": "fallow fix --dry-run --production", + "fallow:fix": "fallow fix --production", "lint": "oxlint .", "lint:fix": "oxlint . --fix", "prettier:check": "prettier --check **/*.{html,js,ts,tsx,vue}", From 73c040740062a11187a2bebf380ca28e6cb0caf1 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Fri, 22 May 2026 22:15:02 -0400 Subject: [PATCH 3/6] chore: fix fallow glob pattern --- .fallowrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.fallowrc.json b/.fallowrc.json index 209bc55b67..76fb819859 100644 --- a/.fallowrc.json +++ b/.fallowrc.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json", "entry": ["src/index.ts", "src/main.ts"], - "ignorePatterns": ["**/package.json", "/__tests__/", "**/demos/**"], + "ignorePatterns": ["**/package.json", "**/__tests__/**", "**/demos/**", "**/*.{cy,spec}.ts"], "workspaces": { "packages": ["frameworks/**", "frameworks-plugins/**", "packages/**", "!**/dist/**"] }, From 131971f8d033507ff29442882c55543881f7e37d Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Sat, 23 May 2026 00:03:30 -0400 Subject: [PATCH 4/6] chore: remove function export only for test --- .../__tests__/filterUtilities.spec.ts | 119 ++++++++++++++++-- .../common/src/filters/filterUtilities.ts | 2 +- 2 files changed, 113 insertions(+), 8 deletions(-) diff --git a/packages/common/src/filter-conditions/__tests__/filterUtilities.spec.ts b/packages/common/src/filter-conditions/__tests__/filterUtilities.spec.ts index b920165e72..051b7d6cf3 100644 --- a/packages/common/src/filter-conditions/__tests__/filterUtilities.spec.ts +++ b/packages/common/src/filter-conditions/__tests__/filterUtilities.spec.ts @@ -1,6 +1,8 @@ +import { of } from 'rxjs'; import { describe, expect, it, vi } from 'vitest'; import { Filters } from '../../filters/filters.index.js'; -import { renderDomElementFromCollectionAsync } from '../../filters/filterUtilities.js'; +import { renderCollectionOptionsAsync } from '../../filters/filterUtilities.js'; +import { Column } from '../../interfaces/column.interface.js'; import { compareObjects, testFilterCondition } from '../filterUtilities.js'; describe('filterUtilities', () => { @@ -41,8 +43,8 @@ describe('filterUtilities', () => { }); }); - describe('renderDomElementFromCollectionAsync method', () => { - it('should get collection found in inner object property when "collectionInsideObjectProperty" is enabled and replace collection prop', () => { + describe('renderCollectionOptionsAsync method', () => { + it('should get collection found in inner object property when "collectionInsideObjectProperty" is enabled and replace collection prop', async () => { const collection = [ { value: 'other', description: 'other' }, { value: 'male', description: 'male' }, @@ -64,13 +66,42 @@ describe('filterUtilities', () => { }, }; const mockCallback = vi.fn(); - renderDomElementFromCollectionAsync(mockColumn.filter.collection, mockColumn, mockCallback); + const collection$ = of(collection); + await renderCollectionOptionsAsync( + collection$, + mockColumn, + mockCallback, + { + isObservable: () => true, + firstValueFrom: () => Promise.resolve(collection), + createSubject: () => { + const subscribers: Array<(...args: any[]) => void> = []; + return { + subscribe: (cb: (...args: any[]) => void) => { + subscribers.push(cb); + return { + unsubscribe: () => { + const idx = subscribers.indexOf(cb); + if (idx >= 0) subscribers.splice(idx, 1); + }, + }; + }, + next: (val: any) => subscribers.slice().forEach((cb) => cb(val)), + } as any; + }, + } as any, + [] + ); expect(mockColumn.filter.collection).toEqual(collection); expect(mockCallback).toHaveBeenCalledWith(collection); }); - it('should throw when collection is not a valid array', () => { + it('should throw when collection is not a valid array', async () => { + const initialCollection = [ + { value: 'other', description: 'other' }, + { value: 'male', description: 'male' }, + ]; const mockColumn = { id: 'gender', field: 'gender', @@ -78,7 +109,7 @@ describe('filterUtilities', () => { filter: { collection: { deep: { - myCollection: null, + myCollection: initialCollection, }, } as any, collectionOptions: { collectionInsideObjectProperty: 'deep.myCollection' }, @@ -87,7 +118,81 @@ describe('filterUtilities', () => { }, }; - expect(() => renderDomElementFromCollectionAsync(mockColumn.filter.collection, mockColumn, vi.fn())).toThrow( + const mockCallback = vi.fn(); + const rxjsMock = { + isObservable: () => true, + firstValueFrom: () => Promise.resolve(initialCollection), + createSubject: () => { + const subscribers: Array<(...args: any[]) => void> = []; + return { + subscribe: (cb: (...args: any[]) => void) => { + subscribers.push(cb); + return { + unsubscribe: () => { + const idx = subscribers.indexOf(cb); + if (idx >= 0) subscribers.splice(idx, 1); + }, + }; + }, + next: (val: any) => subscribers.slice().forEach((cb) => cb(val)), + } as any; + }, + } as any; + + // create subject by awaiting the initial collection + await renderCollectionOptionsAsync(of(initialCollection), mockColumn, mockCallback, rxjsMock, []); + + // now simulate an async emission with an invalid collection inside the object property + const invalidPayload = { deep: { myCollection: null } }; + + expect(() => (mockColumn.filter as any).collectionAsync.next(invalidPayload)).toThrow( + 'Something went wrong while trying to pull the collection from the "collectionAsync" call in the Filter, the collection is not a valid array.' + ); + }); + + it('should throw when collection is not a valid array and "collectionInsideObjectProperty" is not enabled', async () => { + const initialCollection = [ + { value: 'one', description: 'one' }, + { value: 'two', description: 'two' }, + ]; + const mockColumn: Column = { + id: 'gender', + field: 'gender', + filterable: true, + filter: { + collection: initialCollection, + collectionOptions: { collectionInsideObjectProperty: null as any }, + customStructure: { value: 'value', label: 'description' }, + model: Filters.multipleSelect, + }, + }; + + const mockCallback = vi.fn(); + const rxjsMock = { + isObservable: () => true, + firstValueFrom: () => Promise.resolve(initialCollection), + createSubject: () => { + const subscribers: Array<(...args: any[]) => void> = []; + return { + subscribe: (cb: (...args: any[]) => void) => { + subscribers.push(cb); + return { + unsubscribe: () => { + const idx = subscribers.indexOf(cb); + if (idx >= 0) subscribers.splice(idx, 1); + }, + }; + }, + next: (val: any) => subscribers.slice().forEach((cb) => cb(val)), + } as any; + }, + } as any; + + // create subject by awaiting the initial collection + await renderCollectionOptionsAsync(of(initialCollection), mockColumn, mockCallback, rxjsMock, []); + + // now simulate an async emission with an invalid collection (null) + expect(() => (mockColumn.filter as any).collectionAsync.next(null)).toThrow( 'Something went wrong while trying to pull the collection from the "collectionAsync" call in the Filter, the collection is not a valid array.' ); }); diff --git a/packages/common/src/filters/filterUtilities.ts b/packages/common/src/filters/filterUtilities.ts index ff2a9c846d..2da2b497c9 100644 --- a/packages/common/src/filters/filterUtilities.ts +++ b/packages/common/src/filters/filterUtilities.ts @@ -34,7 +34,7 @@ export function buildSelectOperator(optionValues: OperatorDetail[], grid: SlickG * When user use a CollectionAsync we will use the returned collection to render the filter DOM element * and reinitialize filter collection with this new collection */ -export function renderDomElementFromCollectionAsync( +function renderDomElementFromCollectionAsync( collection: any[], columnDef: Column, renderDomElementCallback: (collection: any) => void From c13dab3a4606a21113733445103a972f9e6f5503 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Sat, 23 May 2026 01:03:10 -0400 Subject: [PATCH 5/6] chore: move duplicate Aggregator code into BaseAggregator --- .../common/src/aggregators/avgAggregator.ts | 22 ++++--------------- .../common/src/aggregators/baseAggregator.ts | 22 +++++++++++++++++++ .../common/src/aggregators/cloneAggregator.ts | 21 ++++-------------- .../common/src/aggregators/countAggregator.ts | 22 ++++--------------- .../src/aggregators/distinctAggregator.ts | 21 ++++-------------- .../common/src/aggregators/maxAggregator.ts | 22 ++++--------------- .../common/src/aggregators/minAggregator.ts | 22 ++++--------------- .../common/src/aggregators/sumAggregator.ts | 22 ++++--------------- 8 files changed, 50 insertions(+), 124 deletions(-) create mode 100644 packages/common/src/aggregators/baseAggregator.ts diff --git a/packages/common/src/aggregators/avgAggregator.ts b/packages/common/src/aggregators/avgAggregator.ts index 794ea6b513..0e5d96ca0c 100644 --- a/packages/common/src/aggregators/avgAggregator.ts +++ b/packages/common/src/aggregators/avgAggregator.ts @@ -1,29 +1,15 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; +import { BaseAggregator } from './baseAggregator.js'; -export class AvgAggregator implements Aggregator { - private _isInitialized = false; - private _isTreeAggregator = false; +export class AvgAggregator extends BaseAggregator implements Aggregator { private _nonNullCount = 0; private _sum = 0; - private _field: number | string; - private _type = 'avg'; constructor(field: number | string) { - this._field = field; - } - - get field(): number | string { - return this._field; - } - - get isInitialized(): boolean { - return this._isInitialized; - } - - get type(): string { - return this._type; + super(field); + this._type = 'avg' as const; } init(item?: any, isTreeAggregator = false): void { diff --git a/packages/common/src/aggregators/baseAggregator.ts b/packages/common/src/aggregators/baseAggregator.ts new file mode 100644 index 0000000000..ff2a705394 --- /dev/null +++ b/packages/common/src/aggregators/baseAggregator.ts @@ -0,0 +1,22 @@ +export class BaseAggregator { + protected _isInitialized = false; + protected _isTreeAggregator = false; + protected _field: number | string; + protected _type = ''; + + constructor(field: number | string) { + this._field = field; + } + + get field(): number | string { + return this._field; + } + + get isInitialized(): boolean { + return this._isInitialized; + } + + get type(): string { + return this._type; + } +} diff --git a/packages/common/src/aggregators/cloneAggregator.ts b/packages/common/src/aggregators/cloneAggregator.ts index 36b5039703..504604382a 100644 --- a/packages/common/src/aggregators/cloneAggregator.ts +++ b/packages/common/src/aggregators/cloneAggregator.ts @@ -1,26 +1,13 @@ import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; +import { BaseAggregator } from './baseAggregator.js'; -export class CloneAggregator implements Aggregator { - private _isInitialized = false; - private _field: number | string; +export class CloneAggregator extends BaseAggregator implements Aggregator { private _data = ''; - private _type = 'clone' as const; constructor(field: number | string) { - this._field = field; - } - - get field(): number | string { - return this._field; - } - - get isInitialized(): boolean { - return this._isInitialized; - } - - get type(): string { - return this._type; + super(field); + this._type = 'clone' as const; } init(_item?: any, isTreeAggregator = false): void { diff --git a/packages/common/src/aggregators/countAggregator.ts b/packages/common/src/aggregators/countAggregator.ts index 4e27538386..62d53190ef 100644 --- a/packages/common/src/aggregators/countAggregator.ts +++ b/packages/common/src/aggregators/countAggregator.ts @@ -1,28 +1,14 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; +import { BaseAggregator } from './baseAggregator.js'; -export class CountAggregator implements Aggregator { - private _isInitialized = false; - private _isTreeAggregator = false; - private _field: number | string; +export class CountAggregator extends BaseAggregator implements Aggregator { private _count = 0; - private _type = 'count'; constructor(field: number | string) { - this._field = field; - } - - get field(): number | string { - return this._field; - } - - get isInitialized(): boolean { - return this._isInitialized; - } - - get type(): string { - return this._type; + super(field); + this._type = 'count' as const; } init(item?: any, isTreeAggregator = false): void { diff --git a/packages/common/src/aggregators/distinctAggregator.ts b/packages/common/src/aggregators/distinctAggregator.ts index 47077f9460..5f83555372 100644 --- a/packages/common/src/aggregators/distinctAggregator.ts +++ b/packages/common/src/aggregators/distinctAggregator.ts @@ -1,26 +1,13 @@ import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; +import { BaseAggregator } from './baseAggregator.js'; -export class DistinctAggregator implements Aggregator { - private _isInitialized = false; - private _field: number | string; +export class DistinctAggregator extends BaseAggregator implements Aggregator { private _distinctValues: any[] = []; - private _type = 'distinct' as const; constructor(field: number | string) { - this._field = field; - } - - get field(): number | string { - return this._field; - } - - get isInitialized(): boolean { - return this._isInitialized; - } - - get type(): string { - return this._type; + super(field); + this._type = 'distinct' as const; } init(_item?: any, isTreeAggregator = false): void { diff --git a/packages/common/src/aggregators/maxAggregator.ts b/packages/common/src/aggregators/maxAggregator.ts index 5bc4775c88..7cf6ab4564 100644 --- a/packages/common/src/aggregators/maxAggregator.ts +++ b/packages/common/src/aggregators/maxAggregator.ts @@ -1,28 +1,14 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; +import { BaseAggregator } from './baseAggregator.js'; -export class MaxAggregator implements Aggregator { - private _isInitialized = false; - private _isTreeAggregator = false; +export class MaxAggregator extends BaseAggregator implements Aggregator { private _max: number | null = null; - private _field: number | string; - private _type = 'max'; constructor(field: number | string) { - this._field = field; - } - - get field(): number | string { - return this._field; - } - - get isInitialized(): boolean { - return this._isInitialized; - } - - get type(): string { - return this._type; + super(field); + this._type = 'max' as const; } init(item?: any, isTreeAggregator = false): void { diff --git a/packages/common/src/aggregators/minAggregator.ts b/packages/common/src/aggregators/minAggregator.ts index ca18b13efe..6b5a3f5486 100644 --- a/packages/common/src/aggregators/minAggregator.ts +++ b/packages/common/src/aggregators/minAggregator.ts @@ -1,28 +1,14 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; +import { BaseAggregator } from './baseAggregator.js'; -export class MinAggregator implements Aggregator { - private _isInitialized = false; - private _isTreeAggregator = false; +export class MinAggregator extends BaseAggregator implements Aggregator { private _min: number | null = null; - private _field: number | string; - private _type = 'min'; constructor(field: number | string) { - this._field = field; - } - - get field(): number | string { - return this._field; - } - - get isInitialized(): boolean { - return this._isInitialized; - } - - get type(): string { - return this._type; + super(field); + this._type = 'min' as const; } init(item?: any, isTreeAggregator = false): void { diff --git a/packages/common/src/aggregators/sumAggregator.ts b/packages/common/src/aggregators/sumAggregator.ts index dfec727693..42ec9f3220 100644 --- a/packages/common/src/aggregators/sumAggregator.ts +++ b/packages/common/src/aggregators/sumAggregator.ts @@ -1,29 +1,15 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; +import { BaseAggregator } from './baseAggregator.js'; -export class SumAggregator implements Aggregator { - private _isInitialized = false; - private _isTreeAggregator = false; +export class SumAggregator extends BaseAggregator implements Aggregator { private _sum = 0; private _itemCount = 0; - private _field: number | string; - private _type = 'sum'; constructor(field: number | string) { - this._field = field; - } - - get field(): number | string { - return this._field; - } - - get isInitialized(): boolean { - return this._isInitialized; - } - - get type(): string { - return this._type; + super(field); + this._type = 'sum' as const; } init(item?: any, isTreeAggregator = false): void { From 6cb8a33e747ba543cac894b8d2a360da154d2006 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Sat, 23 May 2026 20:49:49 -0400 Subject: [PATCH 6/6] chore: rename BaseAggregatorClass to be more explicit --- packages/common/src/aggregators/avgAggregator.ts | 4 ++-- .../aggregators/{baseAggregator.ts => baseAggregatorClass.ts} | 2 +- packages/common/src/aggregators/cloneAggregator.ts | 4 ++-- packages/common/src/aggregators/countAggregator.ts | 4 ++-- packages/common/src/aggregators/distinctAggregator.ts | 4 ++-- packages/common/src/aggregators/maxAggregator.ts | 4 ++-- packages/common/src/aggregators/minAggregator.ts | 4 ++-- packages/common/src/aggregators/sumAggregator.ts | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) rename packages/common/src/aggregators/{baseAggregator.ts => baseAggregatorClass.ts} (91%) diff --git a/packages/common/src/aggregators/avgAggregator.ts b/packages/common/src/aggregators/avgAggregator.ts index 0e5d96ca0c..9464f66c65 100644 --- a/packages/common/src/aggregators/avgAggregator.ts +++ b/packages/common/src/aggregators/avgAggregator.ts @@ -1,9 +1,9 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; -import { BaseAggregator } from './baseAggregator.js'; +import { BaseAggregatorClass } from './baseAggregatorClass.js'; -export class AvgAggregator extends BaseAggregator implements Aggregator { +export class AvgAggregator extends BaseAggregatorClass implements Aggregator { private _nonNullCount = 0; private _sum = 0; diff --git a/packages/common/src/aggregators/baseAggregator.ts b/packages/common/src/aggregators/baseAggregatorClass.ts similarity index 91% rename from packages/common/src/aggregators/baseAggregator.ts rename to packages/common/src/aggregators/baseAggregatorClass.ts index ff2a705394..1f4e381e10 100644 --- a/packages/common/src/aggregators/baseAggregator.ts +++ b/packages/common/src/aggregators/baseAggregatorClass.ts @@ -1,4 +1,4 @@ -export class BaseAggregator { +export class BaseAggregatorClass { protected _isInitialized = false; protected _isTreeAggregator = false; protected _field: number | string; diff --git a/packages/common/src/aggregators/cloneAggregator.ts b/packages/common/src/aggregators/cloneAggregator.ts index 504604382a..efd7385b78 100644 --- a/packages/common/src/aggregators/cloneAggregator.ts +++ b/packages/common/src/aggregators/cloneAggregator.ts @@ -1,8 +1,8 @@ import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; -import { BaseAggregator } from './baseAggregator.js'; +import { BaseAggregatorClass } from './baseAggregatorClass.js'; -export class CloneAggregator extends BaseAggregator implements Aggregator { +export class CloneAggregator extends BaseAggregatorClass implements Aggregator { private _data = ''; constructor(field: number | string) { diff --git a/packages/common/src/aggregators/countAggregator.ts b/packages/common/src/aggregators/countAggregator.ts index 62d53190ef..4ee953ba63 100644 --- a/packages/common/src/aggregators/countAggregator.ts +++ b/packages/common/src/aggregators/countAggregator.ts @@ -1,9 +1,9 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; -import { BaseAggregator } from './baseAggregator.js'; +import { BaseAggregatorClass } from './baseAggregatorClass.js'; -export class CountAggregator extends BaseAggregator implements Aggregator { +export class CountAggregator extends BaseAggregatorClass implements Aggregator { private _count = 0; constructor(field: number | string) { diff --git a/packages/common/src/aggregators/distinctAggregator.ts b/packages/common/src/aggregators/distinctAggregator.ts index 5f83555372..5984b81de6 100644 --- a/packages/common/src/aggregators/distinctAggregator.ts +++ b/packages/common/src/aggregators/distinctAggregator.ts @@ -1,8 +1,8 @@ import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; -import { BaseAggregator } from './baseAggregator.js'; +import { BaseAggregatorClass } from './baseAggregatorClass.js'; -export class DistinctAggregator extends BaseAggregator implements Aggregator { +export class DistinctAggregator extends BaseAggregatorClass implements Aggregator { private _distinctValues: any[] = []; constructor(field: number | string) { diff --git a/packages/common/src/aggregators/maxAggregator.ts b/packages/common/src/aggregators/maxAggregator.ts index 7cf6ab4564..68e2b2c462 100644 --- a/packages/common/src/aggregators/maxAggregator.ts +++ b/packages/common/src/aggregators/maxAggregator.ts @@ -1,9 +1,9 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; -import { BaseAggregator } from './baseAggregator.js'; +import { BaseAggregatorClass } from './baseAggregatorClass.js'; -export class MaxAggregator extends BaseAggregator implements Aggregator { +export class MaxAggregator extends BaseAggregatorClass implements Aggregator { private _max: number | null = null; constructor(field: number | string) { diff --git a/packages/common/src/aggregators/minAggregator.ts b/packages/common/src/aggregators/minAggregator.ts index 6b5a3f5486..5314d43970 100644 --- a/packages/common/src/aggregators/minAggregator.ts +++ b/packages/common/src/aggregators/minAggregator.ts @@ -1,9 +1,9 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; -import { BaseAggregator } from './baseAggregator.js'; +import { BaseAggregatorClass } from './baseAggregatorClass.js'; -export class MinAggregator extends BaseAggregator implements Aggregator { +export class MinAggregator extends BaseAggregatorClass implements Aggregator { private _min: number | null = null; constructor(field: number | string) { diff --git a/packages/common/src/aggregators/sumAggregator.ts b/packages/common/src/aggregators/sumAggregator.ts index 42ec9f3220..09b2723972 100644 --- a/packages/common/src/aggregators/sumAggregator.ts +++ b/packages/common/src/aggregators/sumAggregator.ts @@ -1,9 +1,9 @@ import { isNumber } from '@slickgrid-universal/utils'; import type { Aggregator } from './../interfaces/aggregator.interface.js'; import type { GroupTotals } from './../interfaces/grouping.interface.js'; -import { BaseAggregator } from './baseAggregator.js'; +import { BaseAggregatorClass } from './baseAggregatorClass.js'; -export class SumAggregator extends BaseAggregator implements Aggregator { +export class SumAggregator extends BaseAggregatorClass implements Aggregator { private _sum = 0; private _itemCount = 0;