1
0
mirror of https://github.com/robonen/tools.git synced 2026-03-20 19:04:46 +00:00

131 Commits

Author SHA1 Message Date
renovate[bot]
ac4ee586cc chore(deps): update all non-major dependencies 2026-02-14 01:06:04 +00:00
7dce7ed482 Merge pull request #121 from robonen/tsdown
feat: update pnpm workspace and dependencies, migrate to tsdown for builds
2026-02-14 03:58:55 +07:00
df13f0b827 Merge branch 'master' into tsdown 2026-02-14 03:56:59 +07:00
3da393ed08 feat: update pnpm workspace and dependencies, migrate to tsdown for builds 2026-02-14 03:56:45 +07:00
efadb5fe28 feat: update pnpm workspace and dependencies, migrate to tsdown for builds 2026-02-14 03:49:10 +07:00
renovate[bot]
07e6d3eadc chore(deps): update all non-major dependencies (#119)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-02-12 01:36:35 +00:00
renovate[bot]
6fcc9d5a51 chore(deps): update all non-major dependencies (#116)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-31 01:44:27 +00:00
renovate[bot]
289d0d5af1 chore(deps): update all non-major dependencies (#115)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-17 01:52:33 +00:00
4bade839e7 Merge pull request #107 from robonen/renovate/renovate-42.x
chore(deps): update devdependency renovate to v42
2026-01-13 15:58:01 +03:00
renovate[bot]
c4321a2039 chore(deps): update devdependency renovate to v42 2026-01-13 12:56:13 +00:00
f6b3bfbca6 Merge pull request #109 from robonen/renovate/actions-checkout-6.x
chore(deps): update actions/checkout action to v6
2026-01-13 15:55:02 +03:00
renovate[bot]
7541e6aad4 chore(deps): update actions/checkout action to v6 2026-01-04 01:09:12 +00:00
renovate[bot]
a4d9b4c88a chore(deps): update all non-major dependencies (#114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-04 01:08:54 +00:00
renovate[bot]
3b39f64734 chore(deps): update all non-major dependencies (#113)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-26 01:03:01 +00:00
renovate[bot]
6ab2d5cebf chore(deps): update all non-major dependencies (#112)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-17 01:02:35 +00:00
renovate[bot]
54f1facc4f chore(deps): update all non-major dependencies (#111)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-13 01:05:02 +00:00
renovate[bot]
717c41ef88 chore(deps): update all non-major dependencies (#110)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 01:51:25 +00:00
renovate[bot]
3747f5213e chore(deps): update all non-major dependencies (#108)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-16 01:48:53 +00:00
daf18871a0 Merge pull request #106 from robonen/renovate/node-24.x
chore(deps): update node.js to v24
2025-11-05 19:09:26 +03:00
renovate[bot]
8bf9943e9e chore(deps): update node.js to v24 2025-11-03 06:47:48 +00:00
renovate[bot]
0e67715d9e chore(deps): update all non-major dependencies (#105)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-03 01:29:17 +00:00
renovate[bot]
3e43e4db3d chore(deps): update all non-major dependencies (#103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-25 01:44:03 +00:00
b8308e383c Merge pull request #99 from robonen/renovate/jsdom-27.x
chore(deps): update pnpm.catalog.default jsdom to v27
2025-10-23 09:58:09 +03:00
renovate[bot]
93c878cc35 chore(deps): update pnpm.catalog.default jsdom to v27 2025-10-23 06:56:36 +00:00
7653975fa4 Merge pull request #102 from robonen/renovate/actions-setup-node-6.x
chore(deps): update actions/setup-node action to v6
2025-10-23 09:52:09 +03:00
renovate[bot]
e2cb3f5a75 chore(deps): update actions/setup-node action to v6 2025-10-14 05:25:23 +00:00
renovate[bot]
67fbad8930 chore(deps): update all non-major dependencies (#101)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-06 01:41:58 +00:00
renovate[bot]
e49c49e320 chore(deps): update all non-major dependencies (#100)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-26 01:45:40 +00:00
renovate[bot]
43cdc3b5e6 chore(deps): update all non-major dependencies (#98)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-15 01:40:15 +00:00
a9a6c04176 Merge pull request #97 from robonen/renovate/actions-setup-node-5.x
chore(deps): update actions/setup-node action to v5
2025-09-06 15:37:33 +03:00
a6d3e8971f Merge branch 'master' into renovate/actions-setup-node-5.x 2025-09-06 15:36:20 +03:00
40dfdabd08 Merge pull request #96 from robonen/chore/deps
chore: update deps
2025-09-06 15:36:02 +03:00
renovate[bot]
876a815fd3 chore(deps): update actions/setup-node action to v5 2025-09-06 12:35:00 +00:00
b1b9889ad2 chore: update deps 2025-09-06 19:34:30 +07:00
renovate[bot]
9d2a393372 chore(deps): update all non-major dependencies (#95)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-22 01:07:02 +00:00
renovate[bot]
4071e49ad6 chore(deps): update all non-major dependencies (#92)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-16 01:13:12 +00:00
88bd87f9b0 Merge pull request #93 from robonen/renovate/actions-checkout-5.x
chore(deps): update actions/checkout action to v5
2025-08-15 00:45:05 +03:00
renovate[bot]
ac265c05a8 chore(deps): update actions/checkout action to v5 2025-08-14 21:44:00 +00:00
69e5ebc085 Merge pull request #94 from robonen/feat/vue/unrefElement
feat(web/vue): unrefElement
2025-08-15 00:41:59 +03:00
48a85dbae2 build(web/vue): bump version to 0.0.11 2025-08-15 04:39:37 +07:00
0cfdce7456 docs(web/vue): update examples in unrefElement documentation to include type parameters 2025-08-15 04:38:46 +07:00
e035d1abca docs(web/vue): update documentation for unrefElement function 2025-08-15 04:37:58 +07:00
1851d5c80c feat(web/vue): add unrefElement function and tests for element handling 2025-08-15 04:33:47 +07:00
48626a9fe5 Merge pull request #91 from robonen/refactor/web/vue
refactor(web/vue): reuse injection context composable in injection store
2025-08-07 05:28:14 +07:00
04aa9e4721 build(web/vue): bump version to 0.0.10 2025-08-07 05:26:02 +07:00
d55e3989f3 refactor(web/vue): reuse inject context composable in context state 2025-08-07 05:25:04 +07:00
renovate[bot]
acee7e4167 chore(deps): update all non-major dependencies (#90)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-02 01:50:33 +00:00
renovate[bot]
a633bd8da0 chore(deps): update all non-major dependencies (#88)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-27 01:09:23 +00:00
e194ba3883 Merge pull request #81 from robonen/renovate/renovate-41.x
chore(deps): update devdependency renovate to v41
2025-07-19 02:13:10 +07:00
renovate[bot]
d7c978bf9e chore(deps): update devdependency renovate to v41 2025-07-18 07:53:11 +00:00
renovate[bot]
5674095073 chore(deps): update all non-major dependencies (#84)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-18 01:10:46 +00:00
77bab6055c Merge pull request #87 from robonen/fix/web/vue/missing-export
fix(web/vue): missing useAsyncState export
2025-07-14 02:19:49 +07:00
7fcafae467 chore(web/vue): bump version to 0.0.9 2025-07-14 02:17:46 +07:00
52a5add405 fix(web/vue): add missing export useAsyncState from composables 2025-07-14 02:17:31 +07:00
bd5fdab6a0 Merge pull request #86 from robonen/chore/web/vue/0.0.8
chore(web/vue): bump version to 0.0.8
2025-07-14 01:01:39 +07:00
e8d7cccfe0 chore(web/vue): bump version to 0.0.8 2025-07-14 01:00:25 +07:00
be13ec7079 Merge pull request #85 from robonen/web/vue/useAsyncState
feat(web/vue): add useAsyncState
2025-07-14 00:51:53 +07:00
55438b63f9 test(web/vue): update useAsyncState to allow optional delay parameter and add tests 2025-07-14 00:42:50 +07:00
1e9859da83 feat(web/vue): enhance async state management for useAsyncState with improved error handling and loading states 2025-07-10 05:34:47 +07:00
renovate[bot]
aa8a0f00f3 chore(deps): update all non-major dependencies (#83)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-29 01:29:06 +00:00
renovate[bot]
e1e879ebbb chore(deps): update all non-major dependencies (#82)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-24 01:09:26 +00:00
renovate[bot]
6339b21f56 chore(deps): update all non-major dependencies (#80)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-17 01:11:50 +00:00
renovate[bot]
1d4f5c5512 chore(deps): update all non-major dependencies (#78)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 01:00:27 +00:00
2cc0efd556 Merge pull request #79 from robonen/feat/tsconfig-ts-imports
feat(configs/tsconfig): enable importing TypeScript extensions in tsc…
2025-05-27 16:10:51 +07:00
bef0aea14c build(configs/tsconfig): bump version to 0.0.2 2025-05-27 16:09:56 +07:00
40d1d6962b feat(configs/tsconfig): enable importing TypeScript extensions in tsconfig 2025-05-27 16:07:59 +07:00
renovate[bot]
eb8514fe89 chore(deps): update all non-major dependencies (#73)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-24 01:49:10 +00:00
b6200aa7a3 Merge pull request #77 from robonen/refactor/template
Refactor template
2025-05-20 19:42:49 +07:00
a67322ca66 test: temporary disable type checking in test configuration 2025-05-20 19:26:58 +07:00
8297e47086 Merge branch 'master' into refactor/template 2025-05-20 19:25:22 +07:00
95e1bcd0c4 feat: update vitest configuration and dependencies to version 3.2.0-beta.2 2025-05-20 19:20:38 +07:00
6d68246d16 refactor(core/stdlib): update test descriptions and improve placeholder handling 2025-05-20 19:20:26 +07:00
049b5b351a feat(core/stdlib): implement get function and remove getByPath 2025-05-20 19:20:03 +07:00
890d984aad feat(core/stdlib): add type definitions and tests for collections and union types 2025-05-20 19:19:41 +07:00
9d01b12160 Merge pull request #76 from robonen/fix/renovate
fix(infra/renovate): update renovate path
2025-05-20 14:34:08 +07:00
6f2311afeb fix(infra/renovate): update renovate configuration to extend correct default settings 2025-05-20 14:32:28 +07:00
f7312b1060 Merge pull request #74 from robonen/refactor/dir-struct
Refactor directory structure
2025-05-19 18:08:01 +07:00
3d15f7b3b2 chore: remove CHANGELOG.md file 2025-05-19 18:04:25 +07:00
32bf20899f chore: remove shebang from cli.ts 2025-05-19 17:52:26 +07:00
8355477e0e chore: remove unused cover image 2025-05-19 17:51:39 +07:00
968cf26fd0 refactor: simplify version check logic in publish workflow 2025-05-19 17:49:57 +07:00
78fb4da82a refactor: change separate tools by category 2025-05-19 17:43:42 +07:00
d55737df2f chore: dedupe deps 2025-05-19 04:46:08 +07:00
39ce28a5ef Merge pull request #70 from robonen/renovate/all-minor-patch
chore(deps): update all non-major dependencies
2025-05-19 04:44:01 +07:00
renovate[bot]
3d813d22b9 chore(deps): update all non-major dependencies 2025-05-18 21:43:01 +00:00
4f558270ce Merge pull request #72 from robonen/chore/config
Chore/vitest-config
2025-05-19 04:40:53 +07:00
4d6922e06a fix: update CI and publish workflows to use correct build and test commands 2025-05-19 04:36:39 +07:00
fa726eecc4 chore: add workspace vitest configuration for testing with jsdom and coverage 2025-05-19 04:34:13 +07:00
c5f34efe05 chore: remove obsolete documentation and configuration files 2025-05-19 03:34:50 +07:00
ead9c019cd Merge pull request #71 from robonen/refactor/update-cli
feat(cli): auto resolve latest packages for cli
2025-05-18 00:04:23 +07:00
8ee6970674 chore: update package manager version and remove unused dependencies 2025-05-18 00:03:19 +07:00
27c80d24ef feat(cli): update CLI tool for project creation with package.json and config generation 2025-05-17 23:55:52 +07:00
c596e8aa29 build: bump stdlib 0.0.7 2025-05-11 15:41:48 +07:00
f8b37cacd3 fix(packages/stdlib): fix pubsub types 2025-05-11 15:36:26 +07:00
40d8194134 ci: add private packages checking in publish action 2025-05-11 15:10:46 +07:00
renovate[bot]
11d1ac232e chore(deps): update all non-major dependencies (#69)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-11 01:32:48 +00:00
7c1d801c8e build: fix publish script, bump stdlib 0.0.6 and vue 0.0.7 2025-05-09 22:31:02 +07:00
de391fa80d build: bump stdlib 0.0.5 and vue 0.0.6 2025-05-09 14:22:13 +07:00
8ab58078ba build: revert stdlib and vue versions 2025-05-09 14:11:18 +07:00
88f6cec9b2 ci: add registry-url 2025-05-09 13:38:29 +07:00
09e72d904c build: bump stdlib 0.0.5 and vue 0.0.6 2025-05-09 13:32:45 +07:00
695647470b ci: fix branch for publish workflow 2025-05-09 13:22:32 +07:00
b2beb6a5fc Merge pull request #63 from robonen/feat/sync-mutex
fix(packages/stdlib): add SyncMutex primitive
2025-05-09 13:19:14 +07:00
c7048be9fb chore(packages/vue): rename startTime to renderStartTime in useRenderInfo 2025-05-09 13:18:12 +07:00
4ead7fb18c chore: add npm-publish gh action 2025-05-09 13:12:37 +07:00
3994f349f4 feat(packages/stdlib): add execute method for SyncMutex 2025-05-09 13:12:07 +07:00
8d6f08c332 fix(packages/vue): set render duration ref only after mounted and updated 2025-05-09 13:11:20 +07:00
3a2837c1a1 fix(packages/vue): revert to old version useRenderCount 2025-05-09 13:09:03 +07:00
renovate[bot]
82a0c0f746 chore(deps): update all non-major dependencies (#68)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-08 01:55:42 +00:00
renovate[bot]
e8667d6a0a chore(deps): update devdependency renovate to ^40.1.3 (#67)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-04 01:52:46 +00:00
6ed7d39a11 Merge pull request #65 from robonen/renovate/all-minor-patch
chore(deps): update all non-major dependencies
2025-05-01 07:58:37 +07:00
renovate[bot]
74c170e853 chore(deps): update all non-major dependencies 2025-05-01 00:57:28 +00:00
fa96b9ddee Merge pull request #57 from robonen/renovate/pnpm-10.x
chore(deps): update pnpm to v10
2025-05-01 07:56:47 +07:00
ff4a88b896 Merge pull request #66 from robonen/renovate/renovate-40.x
chore(deps): update devdependency renovate to v40
2025-05-01 07:56:31 +07:00
renovate[bot]
871e0cfad2 chore(deps): update devdependency renovate to v40 2025-04-30 23:32:34 +00:00
renovate[bot]
849d444172 chore(deps): update pnpm to v10 2025-04-28 02:03:30 +00:00
renovate[bot]
cea221ed57 chore(deps): update all non-major dependencies (#64)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-05 01:26:48 +00:00
renovate[bot]
49dacf071f chore(deps): update all non-major dependencies (#61)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-23 01:13:25 +00:00
a07ac35db9 fix(packages/vue): add mutex for useRenderCount to avoid infinite rerender 2025-02-23 00:44:58 +07:00
8c5252986e feat(packages/stdlib): add SyncMutex 2025-02-23 00:44:14 +07:00
fad1284cd3 Merge pull request #62 from robonen/feat/injection-store
feat(packages/vue): useInjectionStore
2025-02-22 23:40:54 +07:00
ca0a63ea38 build(packages/vue): bump v0.0.5 2025-02-22 23:39:50 +07:00
7bfbb8e52a chore: update deps 2025-02-22 23:39:31 +07:00
30b72fb2f0 refactor(packages/vue): use another way to provide state at app level in useContextFactory 2025-02-22 23:35:20 +07:00
5594cef31e feat(packages/vue): add useInjectionStore 2025-02-22 23:30:45 +07:00
caa7c4221a Merge pull request #60 from robonen/chore/drop-apps
chore(apps): drop apps workspace completely
2025-02-09 05:20:32 +07:00
6ae3c939d8 Merge branch 'master' into chore/drop-apps
# Conflicts:
#	apps/vhs/package.json
#	pnpm-workspace.yaml
2025-02-09 05:19:10 +07:00
1bada217e9 chore(apps): drop apps workspace completely 2025-02-09 05:13:18 +07:00
renovate[bot]
c813bd174c chore(deps): update all non-major dependencies (#58)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-07 01:13:10 +00:00
renovate[bot]
a2f49b6286 chore(deps): update pnpm.catalog.default vitest to v3.0.5 [security] (#59)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-05 01:04:57 +00:00
renovate[bot]
987b8d4abd chore(deps): update all non-major dependencies (#56)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-02-02 01:51:20 +00:00
191 changed files with 5496 additions and 5922 deletions

View File

@@ -1,7 +1,9 @@
name: CI name: CI
on: on:
- pull_request pull_request:
branches:
- master
env: env:
NODE_VERSION: 22.x NODE_VERSION: 22.x
@@ -14,14 +16,14 @@ jobs:
contents: read contents: read
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v6
- name: Install pnpm - name: Install pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
with: with:
run_install: false run_install: false
- uses: actions/setup-node@v4 - uses: actions/setup-node@v6
with: with:
node-version: ${{ env.NODE_VERSION }} node-version: ${{ env.NODE_VERSION }}
cache: pnpm cache: pnpm
@@ -30,4 +32,4 @@ jobs:
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Test - name: Test
run: pnpm all:build && pnpm all:test run: pnpm build && pnpm test

78
.github/workflows/publish.yaml vendored Normal file
View File

@@ -0,0 +1,78 @@
name: Publish to NPM
on:
push:
branches:
- master
env:
NODE_VERSION: 22.x
jobs:
check-and-publish:
name: Check version changes and publish
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build & Test
run: pnpm build && pnpm test
- name: Check for version changes and publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
# Find all package.json files (excluding node_modules)
PACKAGE_FILES=$(find . -path "*/package.json" -not -path "*/node_modules/*")
for file in $PACKAGE_FILES; do
PACKAGE_DIR=$(dirname $file)
echo "Checking $PACKAGE_DIR for version changes..."
# Get package details
PACKAGE_NAME=$(node -p "require('$file').name")
CURRENT_VERSION=$(node -p "require('$file').version")
IS_PRIVATE=$(node -p "require('$file').private || false")
# Skip private packages
if [ "$IS_PRIVATE" == "true" ]; then
echo "Skipping private package $PACKAGE_NAME"
continue
fi
# Skip root package
if [ "$PACKAGE_DIR" == "." ]; then
echo "Skipping root package"
continue
fi
# Check if package exists on npm
NPM_VERSION=$(npm view $PACKAGE_NAME version 2>/dev/null || echo "0.0.0")
# Compare versions
if [ "$CURRENT_VERSION" != "$NPM_VERSION" ]; then
echo "Version changed for $PACKAGE_NAME: $NPM_VERSION → $CURRENT_VERSION"
echo "Publishing $PACKAGE_NAME@$CURRENT_VERSION"
cd $PACKAGE_DIR
pnpm publish --access public --no-git-checks
cd -
else
echo "No version change detected for $PACKAGE_NAME"
fi
done

View File

@@ -1,57 +0,0 @@
# Changelog
## v0.0.1
### 🚀 Enhancements
- **repo:** Cli tool, base tscofig ([3fcc42e](https://github.com/robonen/tools/commit/3fcc42e))
- **repo:** Drop node_modules ([7dba5ac](https://github.com/robonen/tools/commit/7dba5ac))
- **repo:** Global gitignore ([00c2736](https://github.com/robonen/tools/commit/00c2736))
- **packages/tsconfig:** Readme ([afa15cd](https://github.com/robonen/tools/commit/afa15cd))
- **docs:** Add auto generated doc based on readme ([3960f86](https://github.com/robonen/tools/commit/3960f86))
- **packages/stdlib:** Create stdlib ([c985b95](https://github.com/robonen/tools/commit/c985b95))
- **packages/stdlib:** Base vite config ([0434725](https://github.com/robonen/tools/commit/0434725))
- **packages/stdlib:** Math/clamp util ([8515bff](https://github.com/robonen/tools/commit/8515bff))
- **packages/stdlib:** MapRange util ([d8a9a62](https://github.com/robonen/tools/commit/d8a9a62))
- **packages/stdlib:** Levenshtein distance util ([0022153](https://github.com/robonen/tools/commit/0022153))
- **packages/stdlib:** Add trigram distance utill ([5045852](https://github.com/robonen/tools/commit/5045852))
### 🩹 Fixes
- **repo:** Workspaces -> workspace ([80b87d7](https://github.com/robonen/tools/commit/80b87d7))
### 💅 Refactors
- **repo:** Cleanup ([bc2ebfc](https://github.com/robonen/tools/commit/bc2ebfc))
- **packages/tsconfig:** Readme remove extra spaces ([565e7d8](https://github.com/robonen/tools/commit/565e7d8))
- **docs:** Drop docs cache and dist ([03f755d](https://github.com/robonen/tools/commit/03f755d))
- **repo:** Add vitepress to gitignore ([cf71b8e](https://github.com/robonen/tools/commit/cf71b8e))
- **repo:** Add pathe lib to cli tool ([d7a2d15](https://github.com/robonen/tools/commit/d7a2d15))
- **packages/tsconfig:** Add description and publishConfig ([37d25bf](https://github.com/robonen/tools/commit/37d25bf))
- **repo:** Change cli generated exports in package.json ([a5d33ea](https://github.com/robonen/tools/commit/a5d33ea))
- **packages/tsconfig:** Disable declaration and source maps ([3f1d16b](https://github.com/robonen/tools/commit/3f1d16b))
- **packages/stdlib:** Add doc, update tests ([5280ace](https://github.com/robonen/tools/commit/5280ace))
- **packages/stdlib:** Add comments for math utils ([65ba312](https://github.com/robonen/tools/commit/65ba312))
- **packages/stdlib:** Levensthein fn replate to module export ([92721b3](https://github.com/robonen/tools/commit/92721b3))
- **packages/stdlib:** Rename arguments to left and right ([7d8f5be](https://github.com/robonen/tools/commit/7d8f5be))
- **packages/stdlib:** Reformat test files ([9031430](https://github.com/robonen/tools/commit/9031430))
- **packages/tsconfig:** Add exclude for .output and coverage folders ([769476d](https://github.com/robonen/tools/commit/769476d))
- **packages/stdlib:** Remove private from package.json ([5dadb50](https://github.com/robonen/tools/commit/5dadb50))
### 🏡 Chore
- **packages/stdlib:** Add bench script, add vscode workspace ([e9b8b0c](https://github.com/robonen/tools/commit/e9b8b0c))
- **release:** V0.0.1 ([725b73d](https://github.com/robonen/tools/commit/725b73d))
- **packages/stdlib:** Set 0.0.1 version ([c65113e](https://github.com/robonen/tools/commit/c65113e))
- **release:** V0.0.1 ([f77716a](https://github.com/robonen/tools/commit/f77716a))
### ✅ Tests
- **packages/stdlib:** Trigram distance tests ([4c10d38](https://github.com/robonen/tools/commit/4c10d38))
### ❤️ Contributors
- Robonen ([@robonen](http://github.com/robonen))

2
apps/vhs/.gitignore vendored
View File

@@ -1,2 +0,0 @@
bin/**
!bin/.gitkeep

View File

@@ -1 +0,0 @@
# @robonen/vhs

View File

View File

@@ -1,5 +0,0 @@
{
"name": "@robonen/vhs",
"version": "0.0.0",
"exports": "./src/index.ts"
}

View File

@@ -1,26 +0,0 @@
{
"name": "@robonen/vhs",
"private": true,
"version": "0.0.1",
"license": "UNLICENSED",
"description": "",
"keywords": [],
"author": "Robonen Andrew <robonenandrew@gmail.com>",
"repository": {
"type": "git",
"url": "git+https://github.com/robonen/tools.git",
"directory": "./apps/vhs"
},
"packageManager": "pnpm@9.15.4",
"engines": {
"bun": ">=1.1.27"
},
"type": "module",
"scripts": {
"start": "bun run src/index.ts"
},
"devDependencies": {
"@robonen/tsconfig": "workspace:*",
"@types/bun": "^1.1.17"
}
}

View File

@@ -1,36 +0,0 @@
import { version } from '../package.json';
import { resolve } from 'path';
import { $, Glob } from 'bun';
async function ffmpegMergeAndTranscodeAvi(files: Set<string>) {
const ffmpeg = resolve('bin/ffmpeg');
const output = resolve('output.mp4');
const input = Array.from(files).toSorted((a, b) => a.localeCompare(b)).join('|');
const shell = $`${ffmpeg} -i "concat:${input}" -stats -c:v libx264 -crf 23 -preset veryfast -c:a aac ${output}`;
for await (const line of shell.lines()) {
console.log(line);
}
}
const path = Bun.argv[2];
if (!path) {
console.error('Please provide a path to a file or directory');
process.exit(1);
}
console.info(`Welcome to VHS v${version} 📼`);
console.info(`Scanning ${path}...`);
const glob = new Glob(resolve(path));
const files = new Set<string>();
for await (const file of glob.scan({ followSymlinks: false })) {
files.add(file);
}
console.info(`Found ${files.size} files`);
console.info(await ffmpegMergeAndTranscodeAvi(files));

View File

@@ -1,16 +1,53 @@
import { mkdir, writeFile } from 'node:fs/promises'; import { mkdir, writeFile } from 'node:fs/promises';
import { defineCommand, runMain } from 'citty'; import { defineCommand, runMain } from 'citty';
import { resolve } from 'pathe'; import { resolve } from 'node:path';
import { splitByCase } from 'scule'; import { splitByCase } from 'scule';
const PACKAGE_MANAGER = 'pnpm@9.11.0'; async function getLatestPackageVersion(packageName: string) {
const NODE_VERSION = '>=20.17.0'; try {
const VITE_VERSION = '^5.4.8'; const response = await fetch(`https://registry.npmjs.org/${packageName}`);
const VITE_DTS_VERSION = '^4.2.2'; const data = await response.json();
const PATHE_VERSION = '^1.1.2'
if (!response.ok) {
console.warn(`Failed to fetch latest version for ${packageName}, using fallback`);
return null;
}
const latestVersion = data['dist-tags']?.latest as string | undefined;
if (!latestVersion)
return null;
return {
version: latestVersion,
versionRange: `^${latestVersion}`,
};
} catch (error) {
console.warn(`Error fetching version for ${packageName}: ${error.message}`);
return null;
}
}
const PACKAGE_MANAGER_DEFAULT = 'pnpm@10.10.0';
const NODE_VERSION = '>=22.15.0';
const VITE_VERSION_DEFAULT = '^5.4.8';
const VITE_DTS_VERSION_DEFAULT = '^4.2.2';
const PATHE_VERSION_DEFAULT = '^1.1.2';
const DEFAULT_DIR = 'packages'; const DEFAULT_DIR = 'packages';
const generatePackageJson = (name: string, path: string, hasVite: boolean) => { const generatePackageJson = async (name: string, path: string, hasVite: boolean) => {
const [
packageManagerVersion,
viteVersion,
viteDtsVersion,
patheVersion,
] = await Promise.all([
getLatestPackageVersion('pnpm').then(v => v?.version || PACKAGE_MANAGER_DEFAULT),
hasVite ? getLatestPackageVersion('vite').then(v => v?.versionRange || VITE_VERSION_DEFAULT) : VITE_VERSION_DEFAULT,
hasVite ? getLatestPackageVersion('vite-plugin-dts').then(v => v?.versionRange || VITE_DTS_VERSION_DEFAULT) : VITE_DTS_VERSION_DEFAULT,
hasVite ? getLatestPackageVersion('pathe').then(v => v?.versionRange || PATHE_VERSION_DEFAULT) : PATHE_VERSION_DEFAULT,
]);
const data = { const data = {
name, name,
private: true, private: true,
@@ -24,20 +61,17 @@ const generatePackageJson = (name: string, path: string, hasVite: boolean) => {
url: 'git+https://github.com/robonen/tools.git', url: 'git+https://github.com/robonen/tools.git',
directory: path, directory: path,
}, },
packageManager: PACKAGE_MANAGER, packageManager: `pnpm@${packageManagerVersion}`,
engines: { engines: {
node: NODE_VERSION, node: NODE_VERSION,
}, },
type: 'module', type: 'module',
files: ['dist'], files: ['dist'],
main: './dist/index.umd.js',
module: './dist/index.js',
types: './dist/index.d.ts',
exports: { exports: {
'.': { '.': {
types: './dist/index.d.ts',
import: './dist/index.js', import: './dist/index.js',
require: './dist/index.umd.js', require: './dist/index.umd.js',
types: './dist/index.d.ts',
}, },
}, },
scripts: { scripts: {
@@ -51,9 +85,9 @@ const generatePackageJson = (name: string, path: string, hasVite: boolean) => {
devDependencies: { devDependencies: {
'@robonen/tsconfig': 'workspace:*', '@robonen/tsconfig': 'workspace:*',
...(hasVite && { ...(hasVite && {
vite: VITE_VERSION, vite: viteVersion,
'vite-plugin-dts': VITE_DTS_VERSION, 'vite-plugin-dts': viteDtsVersion,
pathe: PATHE_VERSION, pathe: patheVersion,
}), }),
}, },
}; };
@@ -132,14 +166,15 @@ const createCommand = defineCommand({
await mkdir(resolvedPath, { recursive: true }); await mkdir(resolvedPath, { recursive: true });
writeFile(`${resolvedPath}/package.json`, generatePackageJson(args.name, path, hasVite)); const packageJson = await generatePackageJson(args.name, path, hasVite);
writeFile(`${resolvedPath}/jsr.json`, generateJsrJson(args.name)); await writeFile(`${resolvedPath}/package.json`, packageJson);
writeFile(`${resolvedPath}/tsconfig.json`, generateTsConfig()); await writeFile(`${resolvedPath}/jsr.json`, generateJsrJson(args.name));
writeFile(`${resolvedPath}/README.md`, generateReadme(args.name)); await writeFile(`${resolvedPath}/tsconfig.json`, generateTsConfig());
await writeFile(`${resolvedPath}/README.md`, generateReadme(args.name));
if (hasVite) { if (hasVite) {
mkdir(`${resolvedPath}/src`, { recursive: true }); await mkdir(`${resolvedPath}/src`, { recursive: true });
writeFile(`${resolvedPath}/vite.config.ts`, generateViteConfig()); await writeFile(`${resolvedPath}/vite.config.ts`, generateViteConfig());
} }
console.log(`Project created successfully`); console.log(`Project created successfully`);

View File

@@ -1,6 +1,6 @@
{ {
"name": "@robonen/tsconfig", "name": "@robonen/tsconfig",
"version": "0.0.1", "version": "0.0.2",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "Base typescript configuration for projects", "description": "Base typescript configuration for projects",
"keywords": [ "keywords": [
@@ -15,9 +15,9 @@
"url": "git+https://github.com/robonen/tools.git", "url": "git+https://github.com/robonen/tools.git",
"directory": "packages/tsconfig" "directory": "packages/tsconfig"
}, },
"packageManager": "pnpm@9.15.4", "packageManager": "pnpm@10.29.3",
"engines": { "engines": {
"node": ">=22.13.0" "node": ">=24.13.1"
}, },
"files": [ "files": [
"**tsconfig.json" "**tsconfig.json"

View File

@@ -13,6 +13,7 @@
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true, "esModuleInterop": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"allowImportingTsExtensions": true,
"allowJs": true, "allowJs": true,
"resolveJsonModule": true, "resolveJsonModule": true,
"moduleDetection": "force", "moduleDetection": "force",

View File

@@ -18,9 +18,9 @@
"url": "git+https://github.com/robonen/tools.git", "url": "git+https://github.com/robonen/tools.git",
"directory": "packages/platform" "directory": "packages/platform"
}, },
"packageManager": "pnpm@9.15.4", "packageManager": "pnpm@10.29.3",
"engines": { "engines": {
"node": ">=22.13.0" "node": ">=24.13.1"
}, },
"type": "module", "type": "module",
"files": [ "files": [
@@ -28,25 +28,23 @@
], ],
"exports": { "exports": {
"./browsers": { "./browsers": {
"import": "./dist/browsers.mjs", "types": "./dist/browsers.d.ts",
"require": "./dist/browsers.cjs", "import": "./dist/browsers.js",
"types": "./dist/browsers.d.ts" "require": "./dist/browsers.cjs"
}, },
"./multi": { "./multi": {
"import": "./dist/multi.mjs", "types": "./dist/multi.d.ts",
"require": "./dist/multi.cjs", "import": "./dist/multi.js",
"types": "./dist/multi.d.ts" "require": "./dist/multi.cjs"
} }
}, },
"scripts": { "scripts": {
"test": "vitest run", "test": "vitest run",
"dev": "vitest dev", "dev": "vitest dev",
"build": "unbuild" "build": "tsdown"
}, },
"devDependencies": { "devDependencies": {
"@robonen/tsconfig": "workspace:*", "@robonen/tsconfig": "workspace:*",
"jsdom": "catalog:", "tsdown": "catalog:"
"unbuild": "catalog:",
"vitest": "catalog:"
} }
} }

View File

@@ -0,0 +1,12 @@
import { defineConfig } from 'tsdown';
export default defineConfig({
entry: {
browsers: 'src/browsers/index.ts',
multi: 'src/multi/index.ts',
},
format: ['esm', 'cjs'],
dts: true,
clean: true,
hash: false,
});

View File

@@ -1,6 +1,6 @@
{ {
"$schema": "https://jsr.io/schema/config-file.v1.json", "$schema": "https://jsr.io/schema/config-file.v1.json",
"name": "@robonen/stdlib", "name": "@robonen/stdlib",
"version": "0.0.4", "version": "0.0.7",
"exports": "./src/index.ts" "exports": "./src/index.ts"
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@robonen/stdlib", "name": "@robonen/stdlib",
"version": "0.0.4", "version": "0.0.7",
"license": "Apache-2.0", "license": "Apache-2.0",
"description": "A collection of tools, utilities, and helpers for TypeScript", "description": "A collection of tools, utilities, and helpers for TypeScript",
"keywords": [ "keywords": [
@@ -18,34 +18,28 @@
"url": "git+https://github.com/robonen/tools.git", "url": "git+https://github.com/robonen/tools.git",
"directory": "packages/stdlib" "directory": "packages/stdlib"
}, },
"packageManager": "pnpm@9.15.4", "packageManager": "pnpm@10.29.3",
"engines": { "engines": {
"node": ">=22.13.0" "node": ">=24.13.1"
}, },
"type": "module", "type": "module",
"files": [ "files": [
"dist" "dist"
], ],
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": { "exports": {
".": { ".": {
"import": "./dist/index.mjs", "types": "./dist/index.d.ts",
"require": "./dist/index.cjs", "import": "./dist/index.js",
"types": "./dist/index.d.ts" "require": "./dist/index.cjs"
} }
}, },
"scripts": { "scripts": {
"test": "vitest run", "test": "vitest run",
"dev": "vitest dev", "dev": "vitest dev",
"build": "unbuild" "build": "tsdown"
}, },
"devDependencies": { "devDependencies": {
"@robonen/tsconfig": "workspace:*", "@robonen/tsconfig": "workspace:*",
"@vitest/coverage-v8": "catalog:", "tsdown": "catalog:"
"pathe": "catalog:",
"unbuild": "catalog:",
"vitest": "catalog:"
} }
} }

View File

@@ -0,0 +1,38 @@
export interface RetryOptions {
times?: number;
delay?: number;
backoff: (options: RetryOptions & { count: number }) => number;
}
/**
* @name retry
* @category Async
* @description Retries a function a specified number of times with a delay between each retry
*
* @param {Promise<unknown>} fn - The function to retry
* @param {RetryOptions} options - The options for the retry
* @returns {Promise<unknown>} - The result of the function
*
* @example
* const result = await retry(() => {
* return fetch('https://jsonplaceholder.typicode.com/todos/1')
* .then(response => response.json())
* });
*
* @example
* const result = await retry(() => {
* return fetch('https://jsonplaceholder.typicode.com/todos/1')
* .then(response => response.json())
* }, { times: 3, delay: 1000 });
*
*/
export async function retry<Return>(
fn: () => Promise<Return>,
options: RetryOptions
) {
const {
times = 3,
} = options;
let count = 0;
}

View File

@@ -13,6 +13,8 @@
* sleep(1000).then(() => { * sleep(1000).then(() => {
* console.log('Hello, World!'); * console.log('Hello, World!');
* }); * });
*
* @since 0.0.3
*/ */
export function sleep(ms: number): Promise<void> { export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms));

View File

@@ -0,0 +1,34 @@
import { type Collection, type Path } from '../../types';
export type ExtractFromObject<O extends Record<PropertyKey, unknown>, K> =
K extends keyof O
? O[K]
: K extends keyof NonNullable<O>
? NonNullable<O>[K]
: never;
export type ExtractFromArray<A extends readonly any[], K> =
any[] extends A
? A extends readonly (infer T)[]
? T | undefined
: undefined
: K extends keyof A
? A[K]
: undefined;
export type ExtractFromCollection<O, K> =
K extends []
? O
: K extends [infer Key, ...infer Rest]
? O extends Record<PropertyKey, unknown>
? ExtractFromCollection<ExtractFromObject<O, Key>, Rest>
: O extends readonly any[]
? ExtractFromCollection<ExtractFromArray<O, Key>, Rest>
: never
: never;
type Get<O, K> = ExtractFromCollection<O, Path<K>>;
export function get<O extends Collection, K extends string>(obj: O, path: K) {
return path.split('.').reduce((acc, key) => (acc as any)?.[key], obj) as Get<O, K> | undefined;
}

View File

@@ -0,0 +1 @@
export * from './get';

View File

@@ -5,6 +5,7 @@ export * from './math';
export * from './objects'; export * from './objects';
export * from './patterns'; export * from './patterns';
export * from './structs'; export * from './structs';
export * from './sync';
export * from './text'; export * from './text';
export * from './types'; export * from './types';
export * from './utils' export * from './utils'

View File

@@ -1,7 +1,8 @@
import type { AnyFunction } from '../../../types'; import type { AnyFunction } from '../../../types';
export type Subscriber = AnyFunction; export type Subscriber = AnyFunction;
export type EventsRecord = Record<string | symbol, Subscriber>;
export type EventHandlerMap = Record<PropertyKey, Subscriber>;
/** /**
* @name PubSub * @name PubSub
@@ -10,9 +11,9 @@ export type EventsRecord = Record<string | symbol, Subscriber>;
* *
* @since 0.0.2 * @since 0.0.2
* *
* @template {EventsRecord} Events * @template Events - Event map where all values are function types
*/ */
export class PubSub<Events extends EventsRecord> { export class PubSub<Events extends EventHandlerMap> {
/** /**
* Events map * Events map
* *

View File

@@ -0,0 +1 @@
export * from './mutex';

View File

@@ -0,0 +1,94 @@
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { SyncMutex } from '.';
describe('SyncMutex', () => {
let mutex: SyncMutex;
beforeEach(() => {
mutex = new SyncMutex();
});
it('unlocked by default', () => {
expect(mutex.isLocked).toBe(false);
});
it('lock the mutex', () => {
mutex.lock();
expect(mutex.isLocked).toBe(true);
});
it('remain locked when locked multiple times', () => {
mutex.lock();
mutex.lock();
expect(mutex.isLocked).toBe(true);
});
it('unlock a locked mutex', () => {
mutex.lock();
mutex.unlock();
expect(mutex.isLocked).toBe(false);
});
it('remain unlocked when unlocked multiple times', () => {
mutex.unlock();
mutex.unlock();
expect(mutex.isLocked).toBe(false);
});
it('reflect the current lock state', () => {
expect(mutex.isLocked).toBe(false);
mutex.lock();
expect(mutex.isLocked).toBe(true);
mutex.unlock();
expect(mutex.isLocked).toBe(false);
});
it('execute a callback when unlocked', async () => {
const callback = vi.fn(() => 'done');
const result = await mutex.execute(callback);
expect(result).toBe('done');
expect(callback).toHaveBeenCalled();
});
it('execute a promise callback when unlocked', async () => {
const callback = vi.fn(() => Promise.resolve('done'));
const result = await mutex.execute(callback);
expect(result).toBe('done');
expect(callback).toHaveBeenCalled();
});
it('execute concurrent callbacks only one at a time', async () => {
const callback = vi.fn(() => Promise.resolve('done'));
const result = await Promise.all([
mutex.execute(callback),
mutex.execute(callback),
mutex.execute(callback),
]);
expect(result).toEqual(['done', undefined, undefined]);
expect(callback).toHaveBeenCalledTimes(1);
});
it('does not execute a callback when locked', async () => {
const callback = vi.fn(() => 'done');
mutex.lock();
const result = await mutex.execute(callback);
expect(result).toBeUndefined();
expect(callback).not.toHaveBeenCalled();
});
it('unlocks after executing a callback', async () => {
const callback = vi.fn(() => 'done');
await mutex.execute(callback);
expect(mutex.isLocked).toBe(false);
});
});

View File

@@ -0,0 +1,47 @@
import type { MaybePromise } from "../../types";
/**
* @name SyncMutex
* @category Utils
* @description A simple synchronous mutex to provide more readable locking and unlocking of code blocks
*
* @example
* const mutex = new SyncMutex();
*
* mutex.lock();
*
* mutex.unlock();
*
* const result = await mutex.execute(() => {
* // do something
* return Promise.resolve('done');
* });
*
* @since 0.0.5
*/
export class SyncMutex {
private state = false;
public get isLocked() {
return this.state;
}
public lock() {
this.state = true;
}
public unlock() {
this.state = false;
}
public async execute<T>(callback: () => T) {
if (this.isLocked)
return;
this.lock();
const result = await callback();
this.unlock();
return result;
}
}

View File

@@ -1,7 +1,7 @@
import { describe, expectTypeOf, it } from "vitest"; import { describe, expectTypeOf, it } from 'vitest';
import type { ClearPlaceholder, ExtractPlaceholders } from "./index"; import type { ClearPlaceholder, ExtractPlaceholders } from './index';
describe('template', () => { describe.skip('template', () => {
describe('ClearPlaceholder', () => { describe('ClearPlaceholder', () => {
it('ignores strings without braces', () => { it('ignores strings without braces', () => {
type actual = ClearPlaceholder<'name'>; type actual = ClearPlaceholder<'name'>;

View File

@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
import { templateObject } from '.'; import { templateObject } from '.';
describe.todo('templateObject', () => { describe.skip('templateObject', () => {
it('replace template placeholders with corresponding values from args', () => { it('replace template placeholders with corresponding values from args', () => {
const template = 'Hello, {names.0}!'; const template = 'Hello, {names.0}!';
const args = { names: ['John'] }; const args = { names: ['John'] };

View File

@@ -0,0 +1,73 @@
import { get } from '../../collections';
import { isFunction, type Path, type PathToType, type Stringable, type Trim, type UnionToIntersection } from '../../types';
/**
* Type of a value that will be used to replace a placeholder in a template.
*/
export type TemplateValue = Stringable | string;
/**
* Type of a fallback value when a template key is not found.
*/
export type TemplateFallback = string | ((key: string) => string);
/**
* Type of a template string with placeholders.
*/
const TEMPLATE_PLACEHOLDER = /\{\s*([^{}]+?)\s*\}/gm;
/**
* Removes the placeholder syntax from a template string.
*
* @example
* type Base = ClearPlaceholder<'{user.name}'>; // 'user.name'
* type Unbalanced = ClearPlaceholder<'{user.name'>; // 'user.name'
* type Spaces = ClearPlaceholder<'{ user.name }'>; // 'user.name'
*/
export type ClearPlaceholder<In extends string> =
In extends `${string}{${infer Template}`
? ClearPlaceholder<Template>
: In extends `${infer Template}}${string}`
? ClearPlaceholder<Template>
: Trim<In>;
/**
* Extracts all placeholders from a template string.
*
* @example
* type Base = ExtractPlaceholders<'Hello {user.name}, {user.addresses.0.street}'>; // 'user.name' | 'user.addresses.0.street'
*/
export type ExtractPlaceholders<In extends string> =
In extends `${infer Before}}${infer After}`
? Before extends `${string}{${infer Placeholder}`
? ClearPlaceholder<Placeholder> | ExtractPlaceholders<After>
: ExtractPlaceholders<After>
: never;
/**
* Generates a type for a template string with placeholders.
*
* @example
* type Base = GenerateTypes<'Hello {user.name}, your address {user.addresses.0.street}'>; // { user: { name: string; addresses: { 0: { street: string; }; }; }; }
* type WithTarget = GenerateTypes<'Hello {user.age}', number>; // { user: { age: number; }; }
*/
export type GenerateTypes<T extends string, Target = string> = UnionToIntersection<PathToType<Path<T>, Target>>;
export function templateObject<
T extends string,
A extends GenerateTypes<ExtractPlaceholders<T>, TemplateValue>
>(template: T, args: A, fallback?: TemplateFallback) {
return template.replace(TEMPLATE_PLACEHOLDER, (_, key) => {
const value = get(args, key)?.toString();
return value !== undefined ? value : (isFunction(fallback) ? fallback(key) : '');
});
}
templateObject('Hello {user.name}, your address {user.addresses.0.city}', {
user: {
name: 'John',
addresses: [
{ city: 'Kolpa' },
],
},
});

Some files were not shown because too many files have changed in this diff Show More