Skip to content

Commit e28c074

Browse files
poc(RI-8216): extract array index util into a shared UI/API location
Proves out a single in-repo location for code consumed by both the UI and the API: the source lives at api/src/ri-shared/ (inside the api compile root, because nest build's tsc rootDir inference restructures dist/ when sources live outside it, breaking node dist/src/main and the desktop packaging) and the UI reaches it through a bare riShared/* alias, the same pattern as apiClient. The mirrored array-index helpers collapse into one module with one spec; gatekeeping rules live in ri-shared/README.md. References: #RI-8216 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 867e49c commit e28c074

13 files changed

Lines changed: 59 additions & 112 deletions

File tree

.storybook/vite.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ export default defineConfig({
4646
apiClient: fileURLToPath(
4747
new URL('../redisinsight/api-client', import.meta.url),
4848
),
49+
'riShared': fileURLToPath(
50+
new URL('../redisinsight/api/src/ri-shared', import.meta.url),
51+
),
4952
},
5053
},
5154
server: {

jest.config.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = {
1616
'uiSrc/(.*)': '<rootDir>/redisinsight/ui/src/$1',
1717
'^apiClient$': '<rootDir>/redisinsight/api-client',
1818
'apiClient/(.*)': '<rootDir>/redisinsight/api-client/$1',
19+
'^riShared/(.*)$': '<rootDir>/redisinsight/api/src/ri-shared/$1',
1920
'@redislabsdev/redis-ui-components': '@redis-ui/components',
2021
'@redislabsdev/redis-ui-styles': '@redis-ui/styles',
2122
'@redislabsdev/redis-ui-icons': '@redis-ui/icons',
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export * from './array-index.helper';
1+
export * from '../../ri-shared/utils/array-index';
22
export * from './certificate-import.util';
33
export * from './errors.util';
44
export * from './merge.util';

redisinsight/api/src/common/validators/array-index.validator.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ import {
33
ValidatorConstraint,
44
ValidatorConstraintInterface,
55
} from 'class-validator';
6-
import {
7-
ARRAY_INDEX_MAX,
8-
parseArrayIndex,
9-
} from 'src/common/utils/array-index.helper';
6+
import { ARRAY_INDEX_MAX, parseArrayIndex } from 'src/common/utils';
107

118
@ValidatorConstraint({ name: 'ArrayIndexValidator', async: false })
129
export class ArrayIndexValidator implements ValidatorConstraintInterface {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# ri-shared — code shared across the RedisInsight apps (API + UI)
2+
3+
Modules here are consumed by **both** the API (relative imports, e.g.
4+
`src/ri-shared/utils/array-index`) and the UI (the `riShared/*` path alias). They live
5+
inside `api/src` because the api's production build (`nest build``node dist/src/main`)
6+
compiles with `api/src` as the tsc rootDir — sources outside it restructure `dist/` and
7+
break the packaged app. The UI/Storybook/jest aliases simply point into this folder, so
8+
shared code ships with zero extra packaging surface (desktop bundles it like any api file).
9+
10+
## What belongs here
11+
12+
- Cross-boundary **contracts**: value formats both sides must agree on (e.g. the
13+
BigInt-as-string array index format), stable message formats, shared constants.
14+
- Small **dependency-free** utilities needed verbatim on both sides.
15+
16+
## Rules
17+
18+
- **No imports** from Nest, React, ioredis, lodash or anything else — dependency-free
19+
TypeScript only (the UI and API have separate node_modules; nothing here may assume
20+
either).
21+
- **es2019-compatible**: the api compiles this folder with `target: es2019` — no BigInt
22+
literals (`1n` is TS2737; use `BigInt('...')`), no newer syntax.
23+
- API code style (semicolons) — this folder is linted by `yarn lint:api`.
24+
- Tests live next to the module (`*.spec.ts`, runs under the api jest config) and define
25+
the shared behavior once — UI consumers exercise it through their barrel imports.
26+
27+
## Alias wiring (when adding the alias to a new consumer)
28+
29+
`redisinsight/ui/tsconfig.json` + `redisinsight/ui/vite.config.mjs` +
30+
`jest.config.cjs` (root, UI tests) + `.storybook/vite.config.ts` +
31+
`redisinsight/desktop/tsconfig.json` all map `riShared/*`
32+
`redisinsight/api/src/ri-shared/*`.

redisinsight/api/src/common/utils/array-index.helper.spec.ts renamed to redisinsight/api/src/ri-shared/utils/array-index.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import {
22
ARRAY_INDEX_MAX,
33
isValidArrayIndex,
44
parseArrayIndex,
5-
} from 'src/common/utils';
5+
} from './array-index';
66

7-
describe('array-index.helper', () => {
7+
// Single source of truth for the previously-mirrored UI/API table —
8+
// runs under the api jest config (rootDir src picks it up automatically).
9+
describe('shared array-index', () => {
810
it('should expose max unsigned 64-bit value', () => {
911
expect(ARRAY_INDEX_MAX).toEqual(BigInt('18446744073709551615'));
1012
});

redisinsight/api/src/common/utils/array-index.helper.ts renamed to redisinsight/api/src/ri-shared/utils/array-index.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
/**
22
* Redis array indexes are unsigned 64-bit integers (0 … 2^64−1) and exceed
33
* Number.MAX_SAFE_INTEGER, so they travel as numeric strings end-to-end —
4-
* never parseInt/Number, no JS-side arithmetic on indexes.
4+
* never parseInt/Number, no JS-side arithmetic on indexes (the UI's Redux
5+
* store keeps them as strings too).
56
*
6-
* Mirrored in redisinsight/ui/src/utils/arrayIndex.ts — keep semantics and
7-
* tests in sync.
7+
* Shared by the UI and the API (see src/ri-shared/README.md): the API
8+
* imports it relatively (it lives in the api compile root, so `nest build`
9+
* emits it into dist like any other api source), the UI through the
10+
* `riShared/*` alias (wired in redisinsight/ui/vite.config.mjs,
11+
* redisinsight/ui/tsconfig.json, .storybook/vite.config.ts and
12+
* jest.config.cjs). It must stay dependency-free and es2019-compatible —
13+
* BigInt('...') calls only, since BigInt literals are a syntax error
14+
* (TS2737) under the api's es2019 target.
815
*/
9-
// 2^64 - 1; BigInt() call (not a literal) — this tsconfig targets es2019,
10-
// where BigInt literals are a syntax error (TS2737).
16+
// 2^64 - 1
1117
export const ARRAY_INDEX_MAX = BigInt('18446744073709551615');
1218

1319
const ARRAY_INDEX_REGEX = /^\d+$/;

redisinsight/desktop/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"apiSrc/*": ["redisinsight/api/src/*"],
3030
"uiSrc/*": ["redisinsight/ui/src/*"],
3131
"apiClient": ["redisinsight/api-client"],
32-
"apiClient/*": ["redisinsight/api-client/*"]
32+
"apiClient/*": ["redisinsight/api-client/*"],
33+
"riShared/*": ["redisinsight/api/src/ri-shared/*"]
3334
}
3435
},
3536
"include": ["**/*"],

redisinsight/ui/src/utils/arrayIndex.ts

Lines changed: 0 additions & 44 deletions
This file was deleted.

redisinsight/ui/src/utils/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import RouterWithSubRoutes from './routerWithSubRoutes'
44

55
export * from './common'
66
export * from './validations'
7-
export * from './arrayIndex'
7+
export * from 'riShared/utils/array-index'
88
export * from './statuses'
99
export * from './instance'
1010
export * from './apiResponse'

0 commit comments

Comments
 (0)