Skip to content

Commit

Permalink
feat: add @pnstack/utils package with utility functions and documenta…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
npv2k1 committed Jan 23, 2025
1 parent 86efa68 commit 941807c
Show file tree
Hide file tree
Showing 7 changed files with 263 additions and 0 deletions.
52 changes: 52 additions & 0 deletions packages/utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# @pnstack/utils

A collection of utility functions for PNStack applications.

## Installation

```bash
pnpm add @pnstack/utils
```

## Usage

```typescript
import { get, isEmpty, delay, randomString } from '@pnstack/utils';

// Access nested object properties safely
const obj = { user: { profile: { name: 'John' } } };
const name = get(obj, 'user.profile.name'); // 'John'
const age = get(obj, 'user.profile.age', 0); // 0 (default value)

// Check if value is empty
isEmpty(''); // true
isEmpty([]); // true
isEmpty({}); // true
isEmpty(null); // true
isEmpty(undefined); // true
isEmpty('hello'); // false

// Delay execution
await delay(1000); // waits for 1 second

// Generate random string
const id = randomString(10); // e.g. "a1b2c3d4e5"
```

## API Reference

### get(obj: any, path: string, defaultValue?: T): T | undefined
Safely access nested object properties using dot notation or array syntax.

### isEmpty(value: any): boolean
Check if a value is empty (null, undefined, empty string, empty array, empty object).

### delay(ms: number): Promise<void>
Creates a promise that resolves after the specified number of milliseconds.

### randomString(length: number): string
Generates a random string of the specified length using alphanumeric characters.

## License

MIT
58 changes: 58 additions & 0 deletions packages/utils/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@pnstack/utils",
"version": "1.0.0",
"description": "Utility functions for PNStack applications",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/pnstack/template-turbo-ui.git",
"directory": "packages/utils"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
"main": "dist/index.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.js"
}
},
"engines": {
"node": ">=18"
},
"scripts": {
"dev": "NODE_ENV=development BABEL_ENV=development rollup -c --watch",
"build": "rimraf dist && NODE_ENV=production BABEL_ENV=production rollup -c",
"lint": "pnpm check-types && pnpm eslint",
"lint:fix": "pnpm eslint:fix",
"eslint": "eslint . --report-unused-disable-directives --max-warnings 0",
"eslint:fix": "eslint . --fix",
"check-types": "tsc --noEmit true",
"test": "vitest --config ./vitest.config.ts",
"ci": "pnpm lint && pnpm test --watch=false",
"release": "pnpm ci && pnpm build && pnpm publish"
},
"devDependencies": {
"@repo/eslint-config": "workspace:*",
"@repo/prettier-config": "workspace:*",
"@repo/typescript-config": "workspace:*",
"@rollup/plugin-commonjs": "^28.0.2",
"@rollup/plugin-node-resolve": "^16.0.0",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
"@types/node": "^22.10.2",
"rimraf": "^6.0.1",
"rollup": "^4.29.1",
"rollup-plugin-dts": "^6.1.1",
"rollup-plugin-peer-deps-external": "^2.2.4",
"tslib": "^2.8.1",
"typescript": "5.7.2",
"vitest": "^2.1.8"
},
"packageManager": "[email protected]"
}
30 changes: 30 additions & 0 deletions packages/utils/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { defineConfig } from "rollup";
import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import typescript from "@rollup/plugin-typescript";
import terser from "@rollup/plugin-terser";
import peerDepsExternal from "rollup-plugin-peer-deps-external";

export default defineConfig([
{
input: "src/index.ts",
output: [
{
file: "dist/index.js",
format: "esm",
sourcemap: true,
},
],
plugins: [
peerDepsExternal(),
resolve(),
commonjs(),
typescript({
tsconfig: "./tsconfig.json",
declaration: true,
declarationDir: "dist",
}),
terser(),
],
},
]);
41 changes: 41 additions & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Safely access nested object properties
*/
export function get<T>(obj: any, path: string, defaultValue?: T): T | undefined {
const travel = (regexp: RegExp) =>
String.prototype.split
.call(path, regexp)
.filter(Boolean)
.reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj);
const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
return result === undefined || result === obj ? defaultValue : result;
}

/**
* Check if value is empty (null, undefined, empty string, empty array, empty object)
*/
export function isEmpty(value: any): boolean {
if (value === null || value === undefined) return true;
if (typeof value === "string") return value.trim().length === 0;
if (Array.isArray(value)) return value.length === 0;
if (typeof value === "object") return Object.keys(value).length === 0;
return false;
}

/**
* Delay execution for specified milliseconds
*/
export const delay = (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));

/**
* Generate a random string of specified length
*/
export function randomString(length: number): string {
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
26 changes: 26 additions & 0 deletions packages/utils/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": false,
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"inlineSources": false,
"isolatedModules": true,
"moduleResolution": "Bundler",
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveWatchOutput": true,
"skipLibCheck": true,
"strict": true,
"strictNullChecks": true,
"lib": ["ES2015", "DOM"],
"target": "ES2015",
"module": "ESNext",
"outDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
8 changes: 8 additions & 0 deletions packages/utils/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
globals: true,
environment: 'node',
},
});
48 changes: 48 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 941807c

Please sign in to comment.