mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo-client.git
synced 2026-09-21 16:52:02 -07:00
Relocate truncate helpers to shared util
Move general-purpose truncateAddr/truncateTxid out of the feed-specific post-display module into src/util so the recent-profiles view depends on the shared utility layer rather than a sibling feature module. By architect.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
# Architectural Review Summary — reduce-dry-duplication
|
||||
|
||||
## Task and commits reviewed
|
||||
- Task: `reduce-dry-duplication`
|
||||
- Source commit merged and reviewed: `eed9d70f6f` (`Reduce DRY duplication in services and components`, from refactorer)
|
||||
- Reviewed as a batch via `ready_for_next.sh`; merged into `swarmforge-architect` as a fast-forward and processed.
|
||||
|
||||
## Architectural findings and fixes applied
|
||||
Reviewed the refactorer's DRY reduction for UI/Core separation, dependency rule,
|
||||
information hiding/encapsulation, and local code quality.
|
||||
|
||||
Findings (mostly sound, two notes):
|
||||
1. **MemoDb service consolidation** (`src/services/memo-db.js`) — `getRecentProfiles`/
|
||||
`getRecentPosts` → `getRecent`, and `getProfile`/`getProfilePic`/`getName` →
|
||||
`getLevelResource`. Preserves error semantics (recent → always throws; level → null
|
||||
on 404). Good cohesion, HTTP details stay in the service. **No change needed.**
|
||||
2. **AppUtil `pasteFromClipboard`** (`src/util/index.js`) — centralizes clipboard-paste
|
||||
into the shared utility; components no longer duplicate clipboard reading. Good
|
||||
information hiding. **No change needed.**
|
||||
3. **`PlaceholderView` extraction** — shared placeholder used by placeholder2/3.
|
||||
Cohesive. **No change needed.**
|
||||
4. **`wallet-summary` blur toggle generalization** — `toggleBlur(field)` via dynamic
|
||||
setter name reduces duplication. Functional and correct; the dynamic
|
||||
`set${Capitalized}` construction is a mild readability tradeoff but acceptable to
|
||||
preserve the DRY intent. **No change.**
|
||||
5. **Cross-feature dependency (fixed)** — `recent-profiles` imported the general-purpose
|
||||
`truncateAddr`/`truncateTxid` from the feed-specific `post-feed/post-display`.
|
||||
For cohesion and dependency direction, these pure string helpers belong in the
|
||||
shared utility layer. **Applied fix:** moved `truncateAddr`/`truncateTxid` to
|
||||
`src/util/index.js`; `post-display` now imports from util and re-exports them for
|
||||
its existing consumers; `recent-profiles` imports directly from `src/util`.
|
||||
This removes a sibling-feature → sibling-feature module coupling and keeps generic
|
||||
display helpers in the shared utility.
|
||||
|
||||
## Verification results
|
||||
- **Mutation** (`mutate4javascript --scan`): memo-db.js 4 sites, util/index.js 6 sites,
|
||||
post-display.js 8 sites. No JS unit test suite exists in this project
|
||||
(`npm test` → `echo 'no tests'`); there is no coverage harness, so all sites are
|
||||
uncovered and no survivors can be killed by tests. JSX component files cannot be
|
||||
parsed by the mutation tool (no `jsx` Babel plugin); they are UI adapters and are
|
||||
outside the currently testable boundary.
|
||||
- **DRY** (`dry4javascript src`): **no duplicate candidates found** — the reduction
|
||||
is effective and my fix introduced no duplication.
|
||||
- **Gherkin acceptance mutation (soft)**: not runnable — this project has no
|
||||
`.feature` files, no acceptance pipeline, and no runner adapter.
|
||||
- Property tests: none present in this project.
|
||||
|
||||
## Suite status
|
||||
- No JavaScript unit/acceptance suite exists (`npm test` echoes "no tests").
|
||||
- `bb.edn` test task covers the swarmforge helper scripts only (unrelated to this UI work).
|
||||
|
||||
## Handoffs sent
|
||||
- `git_handoff` → coder, refactorer (priority `00`, task `reduce-dry-duplication`),
|
||||
to review the architectural commit.
|
||||
|
||||
By architect.
|
||||
@@ -8,8 +8,7 @@ import { Container, Row, Col, Spinner, Table } from 'react-bootstrap'
|
||||
|
||||
// Local libraries
|
||||
import MemoDb from '../../../services/memo-db'
|
||||
import AppUtil from '../../../util'
|
||||
import { truncateAddr, truncateTxid } from '../../post-feed/post-display'
|
||||
import AppUtil, { truncateAddr, truncateTxid } from '../../../util'
|
||||
import '../../../App.css'
|
||||
|
||||
const appUtil = new AppUtil()
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
Shared display helpers for post feed and thread views.
|
||||
*/
|
||||
|
||||
import { truncateAddr } from '../../util'
|
||||
|
||||
export { truncateAddr, truncateTxid } from '../../util'
|
||||
|
||||
export function formatRelativeSeen (seen) {
|
||||
if (!seen) return ''
|
||||
const ms = seen > 1e12 ? seen : seen * 1000
|
||||
@@ -26,16 +30,6 @@ export function formatRelativeSeen (seen) {
|
||||
return `${years}y`
|
||||
}
|
||||
|
||||
export function truncateAddr (addr, maxLen = 20) {
|
||||
if (!addr || addr.length <= maxLen) return addr
|
||||
const half = Math.floor((maxLen - 3) / 2)
|
||||
return `${addr.slice(0, half)}...${addr.slice(-half)}`
|
||||
}
|
||||
|
||||
export function truncateTxid (txid, maxLen = 20) {
|
||||
return truncateAddr(txid, maxLen)
|
||||
}
|
||||
|
||||
export function getDisplayName (addr, profiles) {
|
||||
const profile = profiles?.[addr]
|
||||
if (profile?.name) {
|
||||
|
||||
@@ -44,4 +44,15 @@ class AppUtil {
|
||||
}
|
||||
}
|
||||
|
||||
// Truncate a long string (address, txid, etc.) for compact display.
|
||||
export function truncateAddr (addr, maxLen = 20) {
|
||||
if (!addr || addr.length <= maxLen) return addr
|
||||
const half = Math.floor((maxLen - 3) / 2)
|
||||
return `${addr.slice(0, half)}...${addr.slice(-half)}`
|
||||
}
|
||||
|
||||
export function truncateTxid (txid, maxLen = 20) {
|
||||
return truncateAddr(txid, maxLen)
|
||||
}
|
||||
|
||||
export default AppUtil
|
||||
|
||||
Reference in New Issue
Block a user