Updated documentation
This commit is contained in:
parent
7a9ab68402
commit
034134a08f
86
.github/workflows/build.yaml
vendored
Normal file
86
.github/workflows/build.yaml
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
name: Build
|
||||
run-name: Build
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build NPM Project
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: node
|
||||
volumes:
|
||||
- '/mnt/swarm/gitea/runner/cache:/cache'
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: ztimson/actions/clone@develop
|
||||
|
||||
- name: Restore node_modules
|
||||
uses: ztimson/actions/cache/restore@develop
|
||||
with:
|
||||
key: node_modules
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm i
|
||||
|
||||
- name: Build Project
|
||||
run: npm run build
|
||||
|
||||
- name: Test
|
||||
run: npm run test:coverage
|
||||
|
||||
- name: Cache node_modules
|
||||
uses: ztimson/actions/cache@develop
|
||||
with:
|
||||
key: node_modules
|
||||
pattern: node_modules
|
||||
|
||||
- name: Cache Artifacts
|
||||
uses: ztimson/actions/cache@develop
|
||||
with:
|
||||
pattern: dist
|
||||
tag:
|
||||
name: Tag Version
|
||||
needs: build
|
||||
if: ${{github.ref_name}} == 'release'
|
||||
runs-on: ubuntu-latest
|
||||
container: node
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: ztimson/actions/clone@develop
|
||||
|
||||
- name: Get Version Number
|
||||
run: echo "VERSION=$(cat package.json | grep version | grep -Eo ':.+' | grep -Eo '[[:alnum:]\.\/\-]+')" >> $GITHUB_ENV
|
||||
|
||||
- name: Tag Version
|
||||
uses: ztimson/actions/tag@develop
|
||||
with:
|
||||
tag: ${{env.VERSION}}
|
||||
|
||||
publish:
|
||||
name: Publish
|
||||
needs: build
|
||||
if: ${{github.ref_name}} == 'release'
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: node
|
||||
volumes:
|
||||
- '/mnt/swarm/gitea/runner/cache:/cache'
|
||||
steps:
|
||||
- name: Clone Repository
|
||||
uses: ztimson/actions/clone@develop
|
||||
|
||||
- name: Restore Artifacts
|
||||
uses: ztimson/actions/cache/restore@develop
|
||||
|
||||
- name: Upload to Registry
|
||||
uses: ztimson/actions/npm/publish@develop
|
||||
|
||||
- name: Upload to NPM
|
||||
uses: ztimson/actions/npm/publish@develop
|
||||
with:
|
||||
owner: ztimson
|
||||
registry: https://registry.npmjs.org/
|
||||
token: ${{secrets.NPM_TOKEN}}
|
@ -1,105 +0,0 @@
|
||||
image: node:16
|
||||
|
||||
npm:
|
||||
stage: build
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- package-lock.json
|
||||
paths:
|
||||
- node_modules
|
||||
policy: pull-push
|
||||
- key: $CI_PIPELINE_ID
|
||||
paths:
|
||||
- dist
|
||||
policy: push
|
||||
script:
|
||||
- npm install
|
||||
- npm run build
|
||||
artifacts:
|
||||
paths:
|
||||
- dist
|
||||
expire_in: 1 week
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
|
||||
audit:
|
||||
stage: test
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- package-lock.json
|
||||
paths:
|
||||
- node_modules
|
||||
policy: pull
|
||||
script:
|
||||
- echo "vulnerabilities_high $(npm audit | grep -oE '[0-9]+ high' | grep -oE '[0-9]+' || echo 0)" > metrics.txt
|
||||
- echo "vulnerabilities_medium $(npm audit | grep -oE '[0-9]+ moderate' | grep -oE '[0-9]+' || echo 0)" >> metrics.txt
|
||||
- echo "vulnerabilities_low $(npm audit | grep -oE '[0-9]+ low' | grep -oE '[0-9]+' || echo 0)" >> metrics.txt
|
||||
artifacts:
|
||||
reports:
|
||||
metrics: metrics.txt
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
|
||||
jest:
|
||||
stage: test
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- package.json
|
||||
paths:
|
||||
- node_modules
|
||||
policy: pull
|
||||
script:
|
||||
- npm run test:coverage
|
||||
coverage: /All\sfiles.*?\s+(\d+.\d+)/
|
||||
artifacts:
|
||||
when: always
|
||||
reports:
|
||||
junit: junit.xml
|
||||
rules:
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
|
||||
registry:
|
||||
stage: deploy
|
||||
cache:
|
||||
- key:
|
||||
files:
|
||||
- package.json
|
||||
paths:
|
||||
- node_modules
|
||||
policy: pull
|
||||
- key: $CI_PIPELINE_ID
|
||||
paths:
|
||||
- dist
|
||||
policy: pull
|
||||
before_script:
|
||||
- VERSION=$(cat package.json | grep version | grep -Eo ':.+' | grep -Eo '[[:alnum:]\.\/\-]+')
|
||||
- if [ "$CI_COMMIT_BRANCH" != "$CI_DEFAULT_BRANCH" ] && [ "$VERSION" != *"-$CI_COMMIT_BRANCH" ]; then VERSION="$VERSION-$(echo "$CI_COMMIT_BRANCH" | sed -E "s/[_/]/-/g")"; npm version --no-git-tag-version $VERSION; fi
|
||||
script:
|
||||
- PACKAGES=$(curl -s -H "PRIVATE-TOKEN:$DEPLOY_TOKEN" https://$CI_SERVER_HOST/api/v4/projects/$CI_PROJECT_ID/packages)
|
||||
- ID=$(node -pe "JSON.parse(process.argv[1]).find(p => p['version'] == process.argv[2])?.id || ''" $PACKAGES $VERSION)
|
||||
- if [ -n "$ID" ]; then curl -s -X DELETE -H "PRIVATE-TOKEN:$DEPLOY_TOKEN" https://$CI_SERVER_HOST/api/v4/projects/$CI_PROJECT_ID/packages/$ID; fi
|
||||
- printf "@transmute:registry=https://$CI_SERVER_HOST/api/v4/projects/$CI_PROJECT_ID/packages/npm/\n//$CI_SERVER_HOST/api/v4/projects/$CI_PROJECT_ID/packages/npm/:_authToken=$DEPLOY_TOKEN" > .npmrc
|
||||
- npm publish
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||
- if: $CI_COMMIT_BRANCH
|
||||
when: manual
|
||||
allow_failure: true
|
||||
|
||||
tag:
|
||||
stage: deploy
|
||||
image:
|
||||
name: alpine/git
|
||||
entrypoint: [""]
|
||||
cache: []
|
||||
before_script:
|
||||
- git remote set-url origin "https://ReleaseBot:$DEPLOY_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git"
|
||||
script:
|
||||
- VERSION=$(cat package.json | grep version | grep -Eo ':.+' | grep -Eo '[[:alnum:]\.\/\-]+')
|
||||
- git tag -f $VERSION $CI_COMMIT_SHA
|
||||
- git push -f origin $VERSION
|
||||
rules:
|
||||
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
7
LICENSE
Normal file
7
LICENSE
Normal file
@ -0,0 +1,7 @@
|
||||
Copyright (c) 2023 Zakary Timson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
148
README.md
148
README.md
@ -1,10 +1,61 @@
|
||||
# WebStorage Decorators
|
||||
A Javascript library that adds property decorators to sync a class property with the local or session storage. Useful
|
||||
for persisting themes or local settings over reloads or maintaining filters/search options in the current user session.
|
||||
<!-- Header -->
|
||||
<div id="top" align="center">
|
||||
<br />
|
||||
|
||||
<!-- Logo -->
|
||||
<img src="https://git.zakscode.com/repo-avatars/60b47463c877db0d03d41f265a24df35882f246e95df786de38a19fbb617d310" alt="Logo" width="200" height="200">
|
||||
|
||||
<!-- Title -->
|
||||
### webstorage-decorators
|
||||
|
||||
<!-- Description -->
|
||||
TypeScript: Sync variables with localStorage
|
||||
|
||||
<!-- Repo badges -->
|
||||
[![Version](https://img.shields.io/badge/dynamic/json.svg?label=Version&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/webstorage-decorators/tags&query=$[0].name)](https://git.zakscode.com/ztimson/webstorage-decorators/tags)
|
||||
[![Pull Requests](https://img.shields.io/badge/dynamic/json.svg?label=Pull%20Requests&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/webstorage-decorators&query=open_pr_counter)](https://git.zakscode.com/ztimson/webstorage-decorators/pulls)
|
||||
[![Issues](https://img.shields.io/badge/dynamic/json.svg?label=Issues&style=for-the-badge&url=https://git.zakscode.com/api/v1/repos/ztimson/webstorage-decorators&query=open_issues_count)](https://git.zakscode.com/ztimson/webstorage-decorators/issues)
|
||||
|
||||
<!-- Links -->
|
||||
|
||||
---
|
||||
<div>
|
||||
<a href="https://git.zakscode.com/ztimson/webstorage-decorators/releases" target="_blank">Release Notes</a>
|
||||
• <a href="https://git.zakscode.com/ztimson/webstorage-decorators/issues/new?template=.github%2fissue_template%2fbug.md" target="_blank">Report a Bug</a>
|
||||
• <a href="https://git.zakscode.com/ztimson/webstorage-decorators/issues/new?template=.github%2fissue_template%2fenhancement.md" target="_blank">Request a Feature</a>
|
||||
</div>
|
||||
|
||||
---
|
||||
</div>
|
||||
|
||||
## Table of Contents
|
||||
- [WebStorage-Decorators](#top)
|
||||
- [About](#about)
|
||||
- [Examples](#examples)
|
||||
- [Built With](#built-with)
|
||||
- [Setup](#setup)
|
||||
- [Production](#production)
|
||||
- [Development](#development)
|
||||
- [Documentation](#documentation)
|
||||
- [Decorators](#decorators)
|
||||
- [WebStorageOptions](#webstorageoptions)
|
||||
- [License](#license)
|
||||
|
||||
## About
|
||||
|
||||
**Deprecated:** Please use the replacement library [var-persist](https://git.zakscode.com/ztimson/var-persist).
|
||||
|
||||
WebStorage-Decorators is a library that adds property decorators to sync a class property with the local or session storage. It is useful for persisting state through reloads without making any changes to existing code.
|
||||
|
||||
This library has some caveats that [var-persist](https://git.zakscode.com/ztimson/var-persist) rectifies:
|
||||
- Only supports decorators
|
||||
- Impure functions can make changes to data which do not get synced
|
||||
- [Proto]types and functions are lost
|
||||
|
||||
**Disclaimer:** JavaScript's decorators are currently undergoing changes to the API overseen by [TC39](https://tc39.es) and currently have no support for property decorators. [Experimental decorators](https://www.typescriptlang.org/tsconfig#experimentalDecorators) must be enabled to work properly.
|
||||
|
||||
### Examples
|
||||
|
||||
## Quick Setup
|
||||
1. Install with: `npm install --save webstorage-decorators`
|
||||
2. Add the decorator to your property and use as normal!
|
||||
```typescript
|
||||
import {LocalStorage, SessionStorage} from 'webstorage-decorators';
|
||||
|
||||
@ -22,6 +73,54 @@ export class MyCustomClass {
|
||||
}
|
||||
```
|
||||
|
||||
### Built With
|
||||
[![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://typescriptlang.org/)
|
||||
|
||||
## Setup
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 id="production" style="display: inline">
|
||||
Production
|
||||
</h3>
|
||||
</summary>
|
||||
|
||||
#### Prerequisites
|
||||
- [Node.js](https://nodejs.org/en/download)
|
||||
|
||||
#### Instructions
|
||||
1. Install persist: `npm i webstorage-decorators`
|
||||
2. Enable decorators inside `tsconfig.json`:
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
3. Import & use, see [examples above](#examples)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>
|
||||
<h3 id="development" style="display: inline">
|
||||
Development
|
||||
</h3>
|
||||
</summary>
|
||||
|
||||
#### Prerequisites
|
||||
- [Node.js](https://nodejs.org/en/download)
|
||||
|
||||
#### Instructions
|
||||
1. Install the dependencies: `npm i`
|
||||
2. Build library & docs: `npm build`
|
||||
3. Run unit tests: `npm test`
|
||||
|
||||
</details>
|
||||
|
||||
## Documentation
|
||||
|
||||
### Decorators
|
||||
@ -38,39 +137,8 @@ export class MyCustomClass {
|
||||
| default | Default value, same as decorator's first argument |
|
||||
| key | Key to reference value inside local/session storage (Defaults to the property name) |
|
||||
|
||||
## Caveats
|
||||
## License
|
||||
|
||||
### Custom Functions
|
||||
You can technically store anything inside local/session storage however everything is serialized using javascript's JSON,
|
||||
so anything extra (prototypes, functions, etc) will be lost. However if you provide a default value, it will be copied &
|
||||
the data injected, giving you a workaround to accessing static properties (Does not work with arrays).
|
||||
Copyright © 2023 Zakary Timson | Available under MIT Licensing
|
||||
|
||||
```typescript
|
||||
class Person {
|
||||
constructor(public first: string, public last: string) { }
|
||||
fullName() { return `${this.last}, ${this.first}`; }
|
||||
}
|
||||
|
||||
LocalStorage.setItem('example', '{"first": "John", "last": "Smith"}');
|
||||
@LocalStorage(null) example!: Person;
|
||||
console.log(example.fullName()) // ERROR: fullName function doesn't exist
|
||||
|
||||
LocalStorage.setItem('example2', '{"first": "John", "last": "Smith"}');
|
||||
@LocalStorage(new Person(null, null)) example2!: Person;
|
||||
console.log(example2.fullName()) // Works because we have a default object to copy type from
|
||||
```
|
||||
|
||||
### Impure Functions
|
||||
Impure functions don't use the Object's setter preventing the storage from being updated. To prevent this use a pure
|
||||
function or save it manually by reading the variable. (Reading triggers change detection & save if there are differences)
|
||||
```typescript
|
||||
@LocalStorage([1, 2]) example: number[];
|
||||
example.push(3) // Impure & won't update storage
|
||||
console.log(localStorage.getItem('example')) // Output: [1, 2];
|
||||
example; // Trigger save
|
||||
console.log(localStorage.getItem('example')) // Output: [1, 2, 3];
|
||||
|
||||
// OR
|
||||
|
||||
example = example.concat([3]); // Pure function requires you to use the setter triggering automatic saving
|
||||
```
|
||||
See the [license](./LICENSE) for more information.
|
||||
|
@ -10,7 +10,7 @@ module.exports = {
|
||||
".+\\.(ts)$": "ts-jest"
|
||||
},
|
||||
collectCoverageFrom: [
|
||||
'src/**/utils/**/*.ts',
|
||||
'!src/**/utils/**/*.d.ts'
|
||||
'src/**/*.ts',
|
||||
'!src/**/*.d.ts'
|
||||
],
|
||||
};
|
||||
|
3789
package-lock.json
generated
Normal file
3789
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
65
package.json
65
package.json
@ -1,33 +1,36 @@
|
||||
{
|
||||
"name": "webstorage-decorators",
|
||||
"version": "4.3.0",
|
||||
"description": "Decorators to sync class properties to Local/Session storage",
|
||||
"repository": "https://github.com/ztimson/WebstorageDecorators",
|
||||
"author": "Zak Timson",
|
||||
"license": "ISC",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest --verbose",
|
||||
"test:coverage": "npx jest --verbose --coverage",
|
||||
"watch": "npm run build && tsc --watch"
|
||||
},
|
||||
"keywords": [
|
||||
"Decorators",
|
||||
"LocalStorage",
|
||||
"SessionStorage",
|
||||
"WebStorage"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.2.3",
|
||||
"jest": "^29.3.1",
|
||||
"jest-junit": "^15.0.0",
|
||||
"ts-jest": "^29.0.3",
|
||||
"typescript": "^4.9.3"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
"name": "webstorage-decorators",
|
||||
"version": "4.3.1",
|
||||
"description": "Decorators to sync class properties to Local/Session storage",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.zakscode.com/ztimson/webstorage-decorators"
|
||||
},
|
||||
"author": "Zak Timson",
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"test": "jest --verbose",
|
||||
"test:coverage": "npx jest --verbose --coverage",
|
||||
"watch": "npm run build && tsc --watch"
|
||||
},
|
||||
"keywords": [
|
||||
"Decorators",
|
||||
"LocalStorage",
|
||||
"SessionStorage",
|
||||
"WebStorage"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.11",
|
||||
"jest": "^29.7.0",
|
||||
"jest-junit": "^16.0.0",
|
||||
"ts-jest": "^29.1.1",
|
||||
"typescript": "^5.0.4"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export function LocalStorage(defaultValue?: any, opts: WebStorageOptions = {}) {
|
||||
* @param defaultValue Default value to return if property does no exist inside sessionStorage.
|
||||
* @param opts Any additional options
|
||||
*/
|
||||
export function SessionStorage(defaultValue?, opts: WebStorageOptions = {}) {
|
||||
export function SessionStorage(defaultValue?: any, opts: WebStorageOptions = {}) {
|
||||
opts.default = defaultValue;
|
||||
return decoratorBuilder(sessionStorage, opts);
|
||||
}
|
||||
@ -85,7 +85,7 @@ function decoratorBuilder(storage: Storage, opts: WebStorageOptions) {
|
||||
let field = fromStorage(storage, opts);
|
||||
Object.defineProperty(target, key, {
|
||||
get: function() {
|
||||
if(field != fromStorage(storage, {key: opts.key})) target[key] = field;
|
||||
if(field != fromStorage(storage, {key: opts.key})) (<any>target)[key] = field;
|
||||
return field;
|
||||
},
|
||||
set: function(value?) {
|
||||
|
@ -1,7 +1,27 @@
|
||||
import {LocalStorage, SessionStorage} from "../src";
|
||||
|
||||
const CUSTOM_KEY = '_MY_KEY'
|
||||
// Mocks ===============================================================================================================
|
||||
class StorageMock implements Storage {
|
||||
private store: {[key: string]: string} = {}
|
||||
|
||||
get length() { return Object.keys(this.store).length; }
|
||||
|
||||
clear() { this.store = {}; }
|
||||
getItem(key: string) { return this.store[key]; }
|
||||
setItem(key: string, value: string) { this.store[key] = value; }
|
||||
removeItem(key: string) { delete this.store[key]; }
|
||||
key(index: number) { return Object.keys(this.store)[index]; }
|
||||
}
|
||||
|
||||
(<any>global).localStorage = new StorageMock();
|
||||
(<any>global).sessionStorage = new StorageMock()
|
||||
var localStorage: StorageMock;
|
||||
localStorage = (<any>global).localStorage;
|
||||
var sessionStorage: StorageMock;
|
||||
sessionStorage = (<any>global).sessionStorage;
|
||||
|
||||
// Test Data ===========================================================================================================
|
||||
const CUSTOM_KEY = '_MY_KEY'
|
||||
class TestType {
|
||||
constructor(public first: string, public last: string) { }
|
||||
fullName() { return `${this.last}, ${this.first}`; }
|
||||
@ -18,6 +38,7 @@ class TestStorage {
|
||||
@SessionStorage(new TestType('John', 'Smith')) objectSessionStorage!: TestType;
|
||||
}
|
||||
|
||||
// Tests ===============================================================================================================
|
||||
describe('WebStorage Decorators', () => {
|
||||
let testComponent: TestStorage;
|
||||
beforeEach(() => {
|
||||
|
@ -2,7 +2,11 @@
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"lib": ["ESNext"],
|
||||
"experimentalDecorators": true,
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM"
|
||||
],
|
||||
"module": "commonjs",
|
||||
"outDir": "./dist",
|
||||
"strict": true,
|
||||
|
Loading…
Reference in New Issue
Block a user