-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
under_moon
committed
Sep 18, 2023
1 parent
99d4ed0
commit d38782e
Showing
19 changed files
with
2,536 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
name: ci | ||
|
||
on: | ||
push: | ||
tags: | ||
- 'v*' | ||
|
||
jobs: | ||
unit-test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: pnpm setup | ||
uses: pnpm/[email protected] | ||
with: | ||
version: 7.33.6 | ||
- name: node setup | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: 18 | ||
cache: 'pnpm' | ||
- run: pnpm install | ||
- run: pnpm build | ||
- run: pnpm test | ||
|
||
release: | ||
needs: unit-test | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: pnpm setup | ||
uses: pnpm/[email protected] | ||
with: | ||
version: 7.33.6 | ||
- name: node setup | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: 18 | ||
registry-url: 'https://registry.npmjs.org' | ||
cache: 'pnpm' | ||
- run: pnpm install | ||
- run: pnpm build | ||
- run: npm publish | ||
env: | ||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
//npm.pkg.github.com/:_authToken=NODE_AUTH_TOKEN |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
dist | ||
coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"$schema": "https://json.schemastore.org/prettierrc", | ||
"semi": false, | ||
"tabWidth": 2, | ||
"singleQuote": true, | ||
"printWidth": 100, | ||
"trailingComma": "none" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"editor.formatOnSave": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# object-shake | ||
|
||
### Use Cases | ||
|
||
#### - `Vanilla` | ||
|
||
```js | ||
import { shake } from '@object-shake/core' | ||
|
||
const target = { | ||
a: { | ||
b: { c: 1, d: 2 }, | ||
e: 3 | ||
}, | ||
f: 4 | ||
} | ||
|
||
const [proxyTarget, shakedTarget] = shake(target) | ||
|
||
proxyTarget.a.b.c | ||
console.log(shakedTarget) // { a: { b: { c: 1 } } } | ||
|
||
proxyTarget.f | ||
console.log(shakedTarget) // { a: { b: { c: 1 } }, f: 4 } | ||
``` | ||
|
||
#### - `Vue3` | ||
|
||
```html | ||
<script setup> | ||
import { ref, onMounted } from 'vue' | ||
import { reactiveShake } from '@object-shake/vue' | ||
const target = ref({ | ||
a: { | ||
b: { c: 1, d: 2 }, | ||
e: 3 | ||
}, | ||
f: 4 | ||
}) | ||
const [proxyTarget, shakedTarget] = shake(target) | ||
onMounted(() => { | ||
console.log(shakedTarget) // { a: { b: { c: 1 } }, f: 4 } | ||
}) | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<span>{{ proxyTarget.a.b.c }}</span> | ||
<span>{{ proxyTarget.f }}</span> | ||
</div> | ||
</template> | ||
``` | ||
|
||
### Perf | ||
|
||
- performance Test in Nuxt3: `shake state` vs `state` -> https://github.com/undermoonn/vue-reactive-shake-perf | ||
|
||
### Roadmap | ||
|
||
#### `@object-shake/vue` | ||
|
||
- [ ] nested ref | ||
- [ ] vue2 support |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"private": true, | ||
"version": "1.0.0-alpha.1", | ||
"type": "module", | ||
"scripts": { | ||
"prepare": "husky install", | ||
"format": "prettier --write --cache \"**/*.[tj]s?(x)\"", | ||
"test": "vitest run --coverage", | ||
"build": "turbo run build", | ||
"clean": "find . \\( -name 'node_modules' -o -name 'dist' \\) -type d -exec rm -rf {} +" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC", | ||
"devDependencies": { | ||
"@vitest/coverage-v8": "^0.34.4", | ||
"husky": "^8.0.3", | ||
"prettier": "^3.0.3", | ||
"turbo": "^1.10.14", | ||
"typescript": "^5.2.2", | ||
"unbuild": "^2.0.0", | ||
"vitest": "^0.34.4" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { defineBuildConfig } from 'unbuild' | ||
|
||
export default defineBuildConfig({ | ||
entries: ['./src/index.ts'], | ||
declaration: true, | ||
rollup: { | ||
esbuild: { | ||
minify: true | ||
} | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"private": false, | ||
"name": "@object-shake/core", | ||
"version": "1.0.0-alpha.1", | ||
"main": "src/index.ts", | ||
"type": "module", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/undermoonn/object-shake" | ||
}, | ||
"scripts": { | ||
"build": "unbuild" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"keywords": [], | ||
"author": "", | ||
"license": "ISC" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { test, expect, describe } from 'vitest' | ||
import { shake } from './index' | ||
|
||
describe('[core] test', () => { | ||
test('base', () => { | ||
const [p, s] = shake({ a: { b: 1 }, c: 2 }) | ||
expect(s).toEqual({}) | ||
p.a.b | ||
expect(s).toEqual({ a: { b: 1 } }) | ||
}) | ||
}) | ||
|
||
describe('[core] options test', () => { | ||
test('default onKeySet', () => { | ||
const [p, s] = shake( | ||
{ a: { b: 1 }, c: 2 }, | ||
{ | ||
walkOptions: { | ||
onKeySet: (keyPath) => keyPath | ||
} | ||
} | ||
) | ||
expect(s).toEqual({}) | ||
p.a.b | ||
expect(s).toEqual({ a: { b: 1 } }) | ||
}) | ||
}) | ||
|
||
describe('[core] key test', () => { | ||
test('symbol key', () => { | ||
const key = Symbol() | ||
const [p, s] = shake({ a: { [key]: 1 }, c: 2 }) | ||
p.a[key] | ||
expect(s).toEqual({}) | ||
}) | ||
|
||
test('symbol key with collectSymbolKey enable', () => { | ||
const key = Symbol() | ||
const [p, s] = shake({ a: { [key]: 1 }, c: 2 }, { walkOptions: { collectSymbolKey: true } }) | ||
expect(s).toEqual({}) | ||
p.a[key] | ||
expect(s).toEqual({ a: { [key]: 1 } }) | ||
}) | ||
}) | ||
|
||
describe('[core] value test', () => { | ||
test('null value', () => { | ||
const [p, s] = shake({ a: null }) | ||
p.a | ||
expect(s).toEqual({ a: null }) | ||
}) | ||
|
||
test('function value', () => { | ||
const a = () => {} | ||
const [p, s] = shake({ a }) | ||
p.a() | ||
expect(s).toEqual({ a }) | ||
}) | ||
|
||
test('undefined value', () => { | ||
const [p, s] = shake({ a: undefined }) | ||
p.a | ||
expect(s).toEqual({ a: undefined }) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
export interface PublicWalkOptions<T extends object> { | ||
onKeySet?: (parentDeepKeyPath: KeyPath) => KeyPath | false | ||
|
||
collectSymbolKey?: boolean | ||
} | ||
|
||
interface PrivateWalkOptions<T extends object> extends PublicWalkOptions<T> { | ||
/** ProxyHandler target */ | ||
target: object | ||
|
||
/** ProxyHandler key */ | ||
key: string | symbol | ||
|
||
/** ProxyHandler receiver */ | ||
receiver: object | ||
|
||
parentDeepKeyPath: KeyPath | ||
|
||
rootReceiver: T | ||
} | ||
|
||
export interface ShakeOptions<T extends object> { | ||
walkOptions?: PublicWalkOptions<T> | ||
} | ||
|
||
type Key = string | symbol | ||
type KeyPath = Key[] | ||
|
||
export function shake<T extends object>(target: T, options?: ShakeOptions<T>): [T, T] { | ||
const shaked: T = Object.create(null) | ||
|
||
const proxy = new Proxy(target, { | ||
get(target, key, receiver) { | ||
return walk({ | ||
target, | ||
key, | ||
receiver, | ||
|
||
parentDeepKeyPath: [], | ||
rootReceiver: shaked, | ||
|
||
...options?.walkOptions | ||
}) | ||
} | ||
}) | ||
|
||
return [proxy, shaked] | ||
} | ||
|
||
function walk<T extends object>( | ||
options: PrivateWalkOptions<T> | ||
): object | string | null | undefined { | ||
const { target, key, receiver, parentDeepKeyPath, rootReceiver, ...otherOptions } = options | ||
|
||
if (typeof key === 'symbol') { | ||
if (options.collectSymbolKey) { | ||
// | ||
} else { | ||
return undefined | ||
} | ||
} | ||
|
||
const currentDeepKeyPath = [...parentDeepKeyPath, key] | ||
const value = Reflect.get(target, key, receiver) | ||
|
||
if (typeof value === 'object' && value !== null) { | ||
return new Proxy(value, { | ||
get(target, key, receiver) { | ||
return walk<T>({ | ||
target, | ||
key, | ||
receiver, | ||
parentDeepKeyPath: currentDeepKeyPath, | ||
rootReceiver, | ||
...otherOptions | ||
}) | ||
} | ||
}) | ||
} | ||
|
||
if (options.onKeySet) { | ||
const filteredKeyPath = options.onKeySet(currentDeepKeyPath) | ||
if (filteredKeyPath) { | ||
deepSet(rootReceiver, filteredKeyPath, value) | ||
} | ||
} else { | ||
deepSet(rootReceiver, currentDeepKeyPath, value) | ||
} | ||
|
||
return value | ||
} | ||
|
||
function deepSet<T extends object>(target: T, keyPath: KeyPath, value: any): T { | ||
let t: any = target | ||
|
||
keyPath.forEach((key, idx) => { | ||
if (idx === keyPath.length - 1) { | ||
Reflect.set(t, key, value) | ||
return | ||
} | ||
if (typeof t[key] === 'undefined') { | ||
Reflect.set(t, key, {}) | ||
} | ||
t = t[key] | ||
}) | ||
|
||
return target | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { defineBuildConfig } from 'unbuild' | ||
|
||
export default defineBuildConfig({ | ||
entries: ['./src/index.ts'], | ||
declaration: true, | ||
rollup: { | ||
esbuild: { | ||
minify: true | ||
} | ||
} | ||
}) |
Oops, something went wrong.