feat: add utils package
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,7 @@ packages/encryption/dist
|
||||
packages/files/dist
|
||||
packages/models/dist
|
||||
packages/services/dist
|
||||
packages/utils/dist
|
||||
|
||||
**/.pnp.*
|
||||
**/.yarn/*
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
.yarn/cache/@types-dompurify-npm-2.3.3-502805169c-427e2dc60d.zip
vendored
Normal file
BIN
.yarn/cache/@types-dompurify-npm-2.3.3-502805169c-427e2dc60d.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@types-jsdom-npm-16.2.14-bfbb37071c-12bb926fa7.zip
vendored
Normal file
BIN
.yarn/cache/@types-jsdom-npm-16.2.14-bfbb37071c-12bb926fa7.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@types-parse5-npm-6.0.3-a0bee0f9b4-ddb59ee414.zip
vendored
Normal file
BIN
.yarn/cache/@types-parse5-npm-6.0.3-a0bee0f9b4-ddb59ee414.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/@types-tough-cookie-npm-4.0.2-9e61f877e6-e055556ffd.zip
vendored
Normal file
BIN
.yarn/cache/@types-tough-cookie-npm-4.0.2-9e61f877e6-e055556ffd.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/cssom-npm-0.5.0-44ab2704f2-823471aa30.zip
vendored
Normal file
BIN
.yarn/cache/cssom-npm-0.5.0-44ab2704f2-823471aa30.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/data-urls-npm-3.0.2-c8b2050319-033fc3dd0f.zip
vendored
Normal file
BIN
.yarn/cache/data-urls-npm-3.0.2-c8b2050319-033fc3dd0f.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/domexception-npm-4.0.0-5093673f9b-ddbc1268ed.zip
vendored
Normal file
BIN
.yarn/cache/domexception-npm-4.0.0-5093673f9b-ddbc1268ed.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/entities-npm-4.3.1-3a76d89ee3-e8f6d2bac2.zip
vendored
Normal file
BIN
.yarn/cache/entities-npm-4.3.1-3a76d89ee3-e8f6d2bac2.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/html-encoding-sniffer-npm-3.0.0-daac3dfe41-8d806aa004.zip
vendored
Normal file
BIN
.yarn/cache/html-encoding-sniffer-npm-3.0.0-daac3dfe41-8d806aa004.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/jsdom-npm-20.0.0-9c1ad43ab8-f69b40679d.zip
vendored
Normal file
BIN
.yarn/cache/jsdom-npm-20.0.0-9c1ad43ab8-f69b40679d.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/parse5-npm-7.0.0-3158a72394-7da5d61cc1.zip
vendored
Normal file
BIN
.yarn/cache/parse5-npm-7.0.0-3158a72394-7da5d61cc1.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/saxes-npm-6.0.0-31558949f5-d3fa3e2aaf.zip
vendored
Normal file
BIN
.yarn/cache/saxes-npm-6.0.0-31558949f5-d3fa3e2aaf.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/w3c-xmlserializer-npm-3.0.0-3419fc8f05-0af8589942.zip
vendored
Normal file
BIN
.yarn/cache/w3c-xmlserializer-npm-3.0.0-3419fc8f05-0af8589942.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/whatwg-encoding-npm-2.0.0-d7451f51b4-7087810c41.zip
vendored
Normal file
BIN
.yarn/cache/whatwg-encoding-npm-2.0.0-d7451f51b4-7087810c41.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/whatwg-mimetype-npm-3.0.0-5b617710c1-ce08bbb36b.zip
vendored
Normal file
BIN
.yarn/cache/whatwg-mimetype-npm-3.0.0-5b617710c1-ce08bbb36b.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/xml-name-validator-npm-4.0.0-0857c21729-af100b79c2.zip
vendored
Normal file
BIN
.yarn/cache/xml-name-validator-npm-4.0.0-0857c21729-af100b79c2.zip
vendored
Normal file
Binary file not shown.
@@ -87,7 +87,7 @@
|
||||
"@reduxjs/toolkit": "1.8.0",
|
||||
"@standardnotes/editor-kit": "2.2.5",
|
||||
"@standardnotes/stylekit": "5.23.0",
|
||||
"@standardnotes/utils": "1.6.2",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"@testing-library/dom": "8.11.3",
|
||||
"@testing-library/jest-dom": "5.16.2",
|
||||
"@testing-library/react": "12.1.4",
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"@standardnotes/responses": "^1.6.39",
|
||||
"@standardnotes/services": "workspace:*",
|
||||
"@standardnotes/sncrypto-common": "^1.9.0",
|
||||
"@standardnotes/utils": "^1.6.12",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/services": "workspace:*",
|
||||
"@standardnotes/utils": "^1.6.12",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"@types/wicg-file-system-access": "^2020.9.5",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
"@standardnotes/responses": "^1.6.39",
|
||||
"@standardnotes/services": "workspace:*",
|
||||
"@standardnotes/sncrypto-common": "^1.9.0",
|
||||
"@standardnotes/utils": "^1.6.12",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/features": "workspace:*",
|
||||
"@standardnotes/responses": "^1.6.39",
|
||||
"@standardnotes/utils": "^1.6.12",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"lodash": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"@standardnotes/models": "workspace:*",
|
||||
"@standardnotes/responses": "^1.6.39",
|
||||
"@standardnotes/utils": "^1.6.12",
|
||||
"@standardnotes/utils": "workspace:*",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
2
packages/utils/.eslintignore
Normal file
2
packages/utils/.eslintignore
Normal file
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
||||
6
packages/utils/.eslintrc
Normal file
6
packages/utils/.eslintrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../.eslintrc",
|
||||
"parserOptions": {
|
||||
"project": "./linter.tsconfig.json"
|
||||
}
|
||||
}
|
||||
156
packages/utils/CHANGELOG.md
Normal file
156
packages/utils/CHANGELOG.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.6.13](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.12...@standardnotes/utils@1.6.13) (2022-07-04)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add jsdom types to utils package ([72b257c](https://github.com/standardnotes/snjs/commit/72b257cf878306905781e61ef4b32d6d96ab6885))
|
||||
* add missing jsdom to utils package ([7ccce33](https://github.com/standardnotes/snjs/commit/7ccce3329d1f03bcdfad88f6b908bf7e407631a0))
|
||||
* add missing reflect-metadata package to all packages ([ce3a5bb](https://github.com/standardnotes/snjs/commit/ce3a5bbf3f1d2276ac4abc3eec3c6a44c8c3ba9b))
|
||||
|
||||
## [1.6.12](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.11...@standardnotes/utils@1.6.12) (2022-06-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.11](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.10...@standardnotes/utils@1.6.11) (2022-06-15)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.10](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.9...@standardnotes/utils@1.6.10) (2022-05-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.9](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.8...@standardnotes/utils@1.6.9) (2022-05-17)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.8](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.7...@standardnotes/utils@1.6.8) (2022-05-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.7](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.6...@standardnotes/utils@1.6.7) (2022-05-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.6](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.5...@standardnotes/utils@1.6.6) (2022-05-06)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.5](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.3...@standardnotes/utils@1.6.5) (2022-05-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.4](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.3...@standardnotes/utils@1.6.4) (2022-05-04)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.3](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.2...@standardnotes/utils@1.6.3) (2022-04-28)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.2](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.1...@standardnotes/utils@1.6.2) (2022-04-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.6.1](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.6.0...@standardnotes/utils@1.6.1) (2022-04-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
# [1.6.0](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.5.0...@standardnotes/utils@1.6.0) (2022-04-15)
|
||||
|
||||
### Features
|
||||
|
||||
* introduce sync resolved payloads to ensure deltas always return up to date dirty state ([#694](https://github.com/standardnotes/snjs/issues/694)) ([e5278ba](https://github.com/standardnotes/snjs/commit/e5278ba0b2afa987c37f009a2101fb91949d44c6))
|
||||
|
||||
# [1.5.0](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.8...@standardnotes/utils@1.5.0) (2022-04-15)
|
||||
|
||||
### Features
|
||||
|
||||
* no merge payloads in payload manager ([#693](https://github.com/standardnotes/snjs/issues/693)) ([68a577c](https://github.com/standardnotes/snjs/commit/68a577cb887fd2d5556dc9ddec461f6ae665fcb6))
|
||||
|
||||
## [1.4.8](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.7...@standardnotes/utils@1.4.8) (2022-04-11)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.4.7](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.6...@standardnotes/utils@1.4.7) (2022-04-01)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.4.6](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.5...@standardnotes/utils@1.4.6) (2022-03-31)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.4.5](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.4...@standardnotes/utils@1.4.5) (2022-03-31)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.4.4](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.3...@standardnotes/utils@1.4.4) (2022-03-30)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.4.3](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.2...@standardnotes/utils@1.4.3) (2022-03-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.4.2](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.1...@standardnotes/utils@1.4.2) (2022-03-21)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.4.1](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.4.0...@standardnotes/utils@1.4.1) (2022-03-18)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
# [1.4.0](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.3.0...@standardnotes/utils@1.4.0) (2022-03-16)
|
||||
|
||||
### Features
|
||||
|
||||
* delete file functionality ([#657](https://github.com/standardnotes/snjs/issues/657)) ([edec4f7](https://github.com/standardnotes/snjs/commit/edec4f7a65ef557ed5f47be4dddcf2b659ee28b4))
|
||||
|
||||
## [1.3.1](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.3.0...@standardnotes/utils@1.3.1) (2022-03-16)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
# [1.3.0](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.2.3...@standardnotes/utils@1.3.0) (2022-03-14)
|
||||
|
||||
### Features
|
||||
|
||||
* move vault into applications package ([#653](https://github.com/standardnotes/snjs/issues/653)) ([3d320eb](https://github.com/standardnotes/snjs/commit/3d320eb51ac74729ab8864f1c4c4f24d8fb794d5))
|
||||
|
||||
## [1.2.3](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.2.1...@standardnotes/utils@1.2.3) (2022-02-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add pseudo change to get lerna to trigger ([41e6817](https://github.com/standardnotes/snjs/commit/41e6817bbf726b0932cdf16f58622328b9e42803))
|
||||
|
||||
## [1.2.2](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.2.1...@standardnotes/utils@1.2.2) (2022-02-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add pseudo change to get lerna to trigger ([41e6817](https://github.com/standardnotes/snjs/commit/41e6817bbf726b0932cdf16f58622328b9e42803))
|
||||
|
||||
## [1.2.1](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.2.0...@standardnotes/utils@1.2.1) (2022-02-27)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
# [1.2.0](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.1.2...@standardnotes/utils@1.2.0) (2022-02-25)
|
||||
|
||||
### Features
|
||||
|
||||
* extract core functionalities to separate packages ([#610](https://github.com/standardnotes/snjs/issues/610)) ([801547a](https://github.com/standardnotes/snjs/commit/801547a71614ad51a92fb249eaa184ed46a44aac))
|
||||
|
||||
## [1.1.2](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.1.1...@standardnotes/utils@1.1.2) (2022-02-24)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
## [1.1.1](https://github.com/standardnotes/snjs/compare/@standardnotes/utils@1.1.0...@standardnotes/utils@1.1.1) (2022-02-22)
|
||||
|
||||
**Note:** Version bump only for package @standardnotes/utils
|
||||
|
||||
# 1.1.0 (2022-02-22)
|
||||
|
||||
### Features
|
||||
|
||||
* extract SNJS utils as a separate package ([#604](https://github.com/standardnotes/snjs/issues/604)) ([b28195c](https://github.com/standardnotes/snjs/commit/b28195c20be788eec8dabc44c5aff518f074cdd9))
|
||||
19
packages/utils/jest.config.js
Normal file
19
packages/utils/jest.config.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const base = require('../../node_modules/@standardnotes/config/src/jest.json');
|
||||
|
||||
module.exports = {
|
||||
...base,
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: 'tsconfig.json',
|
||||
},
|
||||
},
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 4,
|
||||
functions: 4,
|
||||
lines: 24,
|
||||
statements: 25
|
||||
}
|
||||
}
|
||||
};
|
||||
4
packages/utils/linter.tsconfig.json
Normal file
4
packages/utils/linter.tsconfig.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
45
packages/utils/package.json
Normal file
45
packages/utils/package.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@standardnotes/utils",
|
||||
"version": "1.7.0",
|
||||
"engines": {
|
||||
"node": ">=16.0.0 <17.0.0"
|
||||
},
|
||||
"description": "Common utilities for Standard Notes projects",
|
||||
"main": "dist/index.js",
|
||||
"author": "Standard Notes",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"scripts": {
|
||||
"clean": "rm -fr dist",
|
||||
"prestart": "yarn clean",
|
||||
"start": "tsc -p tsconfig.json --watch",
|
||||
"prebuild": "yarn clean",
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"lint": "eslint . --ext .ts",
|
||||
"test:unit": "jest spec"
|
||||
},
|
||||
"dependencies": {
|
||||
"@standardnotes/common": "^1.23.1",
|
||||
"dompurify": "^2.3.6",
|
||||
"lodash": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dompurify": "^2.3.3",
|
||||
"@types/jest": "^27.4.1",
|
||||
"@types/jsdom": "^16.2.14",
|
||||
"@types/lodash": "^4.14.179",
|
||||
"@types/node": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.30.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"jest": "^27.5.1",
|
||||
"jsdom": "^20.0.0",
|
||||
"ts-jest": "^27.1.3"
|
||||
}
|
||||
}
|
||||
15
packages/utils/src/Domain/Deferred/Deferred.ts
Normal file
15
packages/utils/src/Domain/Deferred/Deferred.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export const Deferred = <T>() => {
|
||||
let resolve!: (value: T | PromiseLike<T>) => void
|
||||
let reject!: () => void
|
||||
|
||||
const promise = new Promise<T>((res, rej) => {
|
||||
resolve = res
|
||||
reject = rej
|
||||
})
|
||||
|
||||
return {
|
||||
resolve,
|
||||
reject,
|
||||
promise,
|
||||
}
|
||||
}
|
||||
61
packages/utils/src/Domain/Utils/Utils.spec.ts
Normal file
61
packages/utils/src/Domain/Utils/Utils.spec.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as DOMPurifyLib from 'dompurify'
|
||||
import { JSDOM } from 'jsdom'
|
||||
import { sortByKey, withoutLastElement } from './Utils'
|
||||
|
||||
const window = new JSDOM('').window
|
||||
const DOMPurify = DOMPurifyLib(window as never)
|
||||
|
||||
describe('Utils', () => {
|
||||
it('sanitizeHtmlString', () => {
|
||||
const dirty = '<svg><animate onbegin=alert(1) attributeName=x dur=1s>'
|
||||
const cleaned = DOMPurify.sanitize(dirty)
|
||||
expect(cleaned).toEqual('<svg></svg>')
|
||||
})
|
||||
|
||||
it('without last works', () => {
|
||||
expect(withoutLastElement([])).toEqual([])
|
||||
expect(withoutLastElement(['a'])).toEqual([])
|
||||
expect(withoutLastElement(['a', 'b'])).toEqual(['a'])
|
||||
expect(withoutLastElement(['a', 'b', 'c'])).toEqual(['a', 'b'])
|
||||
})
|
||||
|
||||
const sortByKey_INPUT = [
|
||||
{ id: 'aza', age: 0, missing: 7 },
|
||||
{ id: 'aaa', age: 12, missing: 8 },
|
||||
{ id: 'ace', age: 12, missing: 0 },
|
||||
{ id: 'zzz', age: -9 },
|
||||
]
|
||||
|
||||
it('sortByKey sort by key', () => {
|
||||
const input = sortByKey_INPUT
|
||||
|
||||
expect(sortByKey(input, 'id')).toEqual([
|
||||
{ id: 'aaa', age: 12, missing: 8 },
|
||||
{ id: 'ace', age: 12, missing: 0 },
|
||||
{ id: 'aza', age: 0, missing: 7 },
|
||||
{ id: 'zzz', age: -9 },
|
||||
])
|
||||
|
||||
expect(sortByKey(input, 'age')).toEqual([
|
||||
{ id: 'zzz', age: -9 },
|
||||
{ id: 'aza', age: 0, missing: 7 },
|
||||
{ id: 'aaa', age: 12, missing: 8 },
|
||||
{ id: 'ace', age: 12, missing: 0 },
|
||||
])
|
||||
|
||||
expect(sortByKey(input, 'missing')).toEqual([
|
||||
{ id: 'ace', age: 12, missing: 0 },
|
||||
{ id: 'aza', age: 0, missing: 7 },
|
||||
{ id: 'aaa', age: 12, missing: 8 },
|
||||
{ id: 'zzz', age: -9 },
|
||||
])
|
||||
})
|
||||
|
||||
it('sortByKey does not mutate the input & creates a new array', () => {
|
||||
const input = sortByKey_INPUT
|
||||
const initial = [...input]
|
||||
|
||||
expect(sortByKey(input, 'id')).not.toBe(input)
|
||||
expect(initial).toEqual(input)
|
||||
})
|
||||
})
|
||||
681
packages/utils/src/Domain/Utils/Utils.ts
Normal file
681
packages/utils/src/Domain/Utils/Utils.ts
Normal file
@@ -0,0 +1,681 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import * as DOMPurify from 'dompurify'
|
||||
import { find, isArray, mergeWith, remove, uniq, uniqWith } from 'lodash'
|
||||
import { AnyRecord } from '@standardnotes/common'
|
||||
|
||||
const collator = typeof Intl !== 'undefined' ? new Intl.Collator('en', { numeric: true }) : undefined
|
||||
|
||||
export function getGlobalScope(): Window | unknown | null {
|
||||
return typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : null
|
||||
}
|
||||
|
||||
export function dictToArray<T>(dict: Record<any, T>): T[] {
|
||||
return Object.values(dict)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we are in a web browser
|
||||
*/
|
||||
export function isWebEnvironment(): boolean {
|
||||
return getGlobalScope() !== null
|
||||
}
|
||||
|
||||
interface IEDocument {
|
||||
documentMode?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns true if WebCrypto is available
|
||||
*/
|
||||
export function isWebCryptoAvailable(): boolean {
|
||||
return (
|
||||
(isWebEnvironment() && !isReactNativeEnvironment() && !(document && (document as IEDocument).documentMode)) ||
|
||||
(/Edge/.test(navigator.userAgent) && window.crypto && !!window.crypto.subtle)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we are in React Native app
|
||||
*/
|
||||
export function isReactNativeEnvironment(): boolean {
|
||||
return typeof navigator !== 'undefined' && navigator.product === 'ReactNative'
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches array of objects for first object where object[key] === value
|
||||
* @returns Matching object or null if not found
|
||||
*/
|
||||
export function findInArray<T, K extends keyof T>(array: T[], key: K, value: T[K]): T | undefined {
|
||||
return array.find((item: T) => item[key] === value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches array of objects for first object where object[key] === value
|
||||
* @returns Matching object or null if not found
|
||||
*/
|
||||
export function searchArray<T>(array: T[], predicate: Partial<T>): T | undefined {
|
||||
return find(array, predicate) as T
|
||||
}
|
||||
|
||||
export function sureSearchArray<T>(array: T[], predicate: Partial<T>): T {
|
||||
return searchArray(array, predicate) as T
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns Whether the value is a function or object
|
||||
*/
|
||||
export function isObject(value: unknown): value is object {
|
||||
if (value === null) {
|
||||
return false
|
||||
}
|
||||
return typeof value === 'function' || typeof value === 'object'
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns Whether the value is a function
|
||||
*/
|
||||
export function isFunction(value: unknown): boolean {
|
||||
if (value === null) {
|
||||
return false
|
||||
}
|
||||
return typeof value === 'function'
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns True if the object is null or undefined, otherwise false
|
||||
*/
|
||||
export function isNullOrUndefined(value: unknown): value is null | undefined {
|
||||
return value === null || value === undefined
|
||||
}
|
||||
|
||||
export function isNotUndefined<T>(val: T | undefined | null): val is T {
|
||||
return val != undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns True if the string is empty or undefined
|
||||
*/
|
||||
export function isEmpty(string: string): boolean {
|
||||
return !string || string.length === 0
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns Whether the value is a string
|
||||
*/
|
||||
export function isString(value: unknown): value is string {
|
||||
return typeof value === 'string' || value instanceof String
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns The greater of the two dates
|
||||
*/
|
||||
export function greaterOfTwoDates(dateA: Date, dateB: Date): Date {
|
||||
if (dateA > dateB) {
|
||||
return dateA
|
||||
} else {
|
||||
return dateB
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array containing only unique values by combining the two input arrays.
|
||||
* Elements are unique based on the values of `equalityKeys`.
|
||||
* @param equalityKeys - Keys to determine element equality
|
||||
* @returns Array containing unique values
|
||||
*/
|
||||
export function uniqCombineObjArrays<T>(arrayA: T[], arrayB: T[], equalityKeys: (keyof T)[]): T[] {
|
||||
return uniqWith(arrayA.concat(arrayB), (a: T, b: T) => {
|
||||
for (const key of equalityKeys) {
|
||||
if (a[key] !== b[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array containing only unique values
|
||||
* @returns Array containing unique values
|
||||
*/
|
||||
export function uniqueArray<T>(array: T[]): T[] {
|
||||
return uniq(array)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array containing only unique values
|
||||
* @returns Array containing unique values
|
||||
*/
|
||||
export function uniqueArrayByKey<T>(array: T[], key: keyof T): T[] {
|
||||
return uniqWith(array, (a: T, b: T) => {
|
||||
return a[key] === b[key]
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element in the array.
|
||||
* @returns The last element in the array
|
||||
*/
|
||||
export function lastElement<T>(array: T[]): T | undefined {
|
||||
return array[array.length - 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all items from otherArray into inArray, in-place.
|
||||
* Does not return a value.
|
||||
*/
|
||||
export function extendArray<T, K extends T>(inArray: T[], otherArray: K[]): void {
|
||||
for (const value of otherArray) {
|
||||
inArray.push(value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all items appearing in toSubtract from inArray, in-place
|
||||
* @param toSubtract - The list of items to remove from inArray
|
||||
*/
|
||||
export function subtractFromArray<T>(inArray: T[], toSubtract: T[]): void {
|
||||
for (const value of toSubtract) {
|
||||
removeFromArray(inArray, value)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the first matching element of an array by strict equality.
|
||||
* If no matchin element is found, the array is left unchanged.
|
||||
*/
|
||||
export function removeFromArray<T>(array: T[], value: T): void {
|
||||
const valueIndex = array.indexOf(value)
|
||||
if (valueIndex === -1) {
|
||||
return
|
||||
}
|
||||
array.splice(valueIndex, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the element to the array if the array does not already include the value.
|
||||
* The array is searched via array.indexOf
|
||||
* @returns true if value was added
|
||||
*/
|
||||
export function addIfUnique<T>(array: T[], value: T): boolean {
|
||||
if (!array.includes(value)) {
|
||||
array.push(value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an object from the array in-place by searching for an object where all the
|
||||
* key/values in predicate match with the candidate element.
|
||||
*/
|
||||
export function filterFromArray<T>(
|
||||
array: T[],
|
||||
predicate: Partial<Record<keyof T, any>> | ((object: T) => boolean),
|
||||
): void {
|
||||
remove(array, predicate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array by removing all elements in subtract from array
|
||||
*/
|
||||
export function arrayByDifference<T>(array: T[], subtract: T[]): T[] {
|
||||
return array.filter((x) => !subtract.includes(x)).concat(subtract.filter((x) => !array.includes(x)))
|
||||
}
|
||||
|
||||
export function compareValues<T>(left: T, right: T) {
|
||||
if ((left && !right) || (!left && right)) {
|
||||
return false
|
||||
}
|
||||
if (left instanceof Date && right instanceof Date) {
|
||||
return left.getTime() === right.getTime()
|
||||
} else if (left instanceof String && right instanceof String) {
|
||||
return left === right
|
||||
} else {
|
||||
return topLevelCompare(left, right)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the value from the array at the given index, in-place.
|
||||
*/
|
||||
export function removeFromIndex(array: any[], index: number) {
|
||||
array.splice(index, 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the value from the array at the given index, in-place.
|
||||
*/
|
||||
export function addAtIndex<T>(array: T[], element: T, index: number) {
|
||||
array.splice(index, 0, element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array by removeing the value from the array at the given index
|
||||
*/
|
||||
export function arrayByRemovingFromIndex<T>(array: T[], index: number) {
|
||||
const copy = array.slice()
|
||||
removeFromIndex(copy, index)
|
||||
return copy
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array where each element is the value of a top-level
|
||||
* object key.
|
||||
* Example: objectToValueArray({a: 1, b: 2}) returns [1, 2]
|
||||
*/
|
||||
export function objectToValueArray(object: AnyRecord) {
|
||||
const values = []
|
||||
for (const key of Object.keys(object)) {
|
||||
values.push(object[key])
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key-sorted copy of the object.
|
||||
* For example, sortedCopy({b: '1', a: '2'}) returns {a: '2', b: '1'}
|
||||
*/
|
||||
export function sortedCopy(object: any) {
|
||||
const keys = Object.keys(object).sort()
|
||||
const result: any = {}
|
||||
for (const key of keys) {
|
||||
result[key] = object[key]
|
||||
}
|
||||
return Copy(result)
|
||||
}
|
||||
|
||||
export const sortByKey = <T>(input: T[], key: keyof T): T[] => {
|
||||
const compare = (a: T, b: T): number => {
|
||||
const valueA = a[key]
|
||||
const valueB = b[key]
|
||||
|
||||
if (valueA < valueB) {
|
||||
return -1
|
||||
}
|
||||
if (valueA > valueB) {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
const newArray = [...input]
|
||||
newArray.sort(compare)
|
||||
|
||||
return newArray
|
||||
}
|
||||
|
||||
/** Returns a new object by omitting any keys which have an undefined or null value */
|
||||
export function omitUndefinedCopy(object: any) {
|
||||
const result: any = {}
|
||||
for (const key of Object.keys(object)) {
|
||||
if (!isNullOrUndefined(object[key])) {
|
||||
result[key] = object[key]
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new array by sorting an array of elements based on a date property,
|
||||
* as indicated by the input key value.
|
||||
*/
|
||||
export function dateSorted<T>(elements: T[], key: keyof T, ascending = true) {
|
||||
return elements.sort((a, b) => {
|
||||
const aTimestamp = (a[key] as unknown as Date).getTime()
|
||||
const bTimestamp = (b[key] as unknown as Date).getTime()
|
||||
const vector = ascending ? 1 : -1
|
||||
if (aTimestamp < bTimestamp) {
|
||||
return -1 * vector
|
||||
} else if (aTimestamp > bTimestamp) {
|
||||
return 1 * vector
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** Compares for equality by comparing top-level keys value equality (===) */
|
||||
export function topLevelCompare<T>(left: T, right: T) {
|
||||
if (!left && !right) {
|
||||
return true
|
||||
}
|
||||
if (!left || !right) {
|
||||
return false
|
||||
}
|
||||
const leftKeys = Object.keys(left)
|
||||
const rightKeys = Object.keys(right)
|
||||
if (leftKeys.length !== rightKeys.length) {
|
||||
return false
|
||||
}
|
||||
for (const key of leftKeys) {
|
||||
if ((left as any)[key] !== (right as any)[key]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object by attempting to JSON.parse any top-level object keys.
|
||||
*/
|
||||
export function jsonParseEmbeddedKeys(object: AnyRecord) {
|
||||
const result: AnyRecord = {}
|
||||
for (const key of Object.keys(object)) {
|
||||
let value
|
||||
try {
|
||||
value = JSON.parse(object[key] as string)
|
||||
} catch (error) {
|
||||
value = object[key]
|
||||
}
|
||||
result[key] = value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export const withoutLastElement = <T>(array: T[]): T[] => {
|
||||
return array.slice(0, -1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes keys of the input object.
|
||||
*/
|
||||
export function omitInPlace<T>(object: T, keys: Array<keyof T>) {
|
||||
if (!object) {
|
||||
return
|
||||
}
|
||||
for (const key of keys) {
|
||||
delete object[key]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object by omitting `keys` from `object`
|
||||
*/
|
||||
export function omitByCopy<T>(object: T, keys: Array<keyof T>) {
|
||||
if (isNullOrUndefined(object)) {
|
||||
return undefined
|
||||
}
|
||||
const newObject = Object.assign({}, object)
|
||||
/**
|
||||
* Lodash's omit, which was previously used, seems to cause unexpected behavior
|
||||
* when payload is an ES6 item class. So we instead manually omit each key.
|
||||
*/
|
||||
for (const key of keys) {
|
||||
delete newObject[key]
|
||||
}
|
||||
return newObject
|
||||
}
|
||||
|
||||
/**
|
||||
* Similiar to Node's path.join, this function combines an array of paths into
|
||||
* one resolved path.
|
||||
*/
|
||||
export function joinPaths(...args: string[]) {
|
||||
return args
|
||||
.map((part, i) => {
|
||||
if (i === 0) {
|
||||
return part.trim().replace(/[/]*$/g, '')
|
||||
} else {
|
||||
return part.trim().replace(/(^[/]*|[/]*$)/g, '')
|
||||
}
|
||||
})
|
||||
.filter((x) => x.length)
|
||||
.join('/')
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of the input object by JSON stringifying the object then JSON parsing
|
||||
* the string (if the input is an object). If input is date, a Date copy will be created,
|
||||
* and if input is a primitive value, it will be returned as-is.
|
||||
*/
|
||||
export function Copy(object: any) {
|
||||
if (object instanceof Date) {
|
||||
return new Date(object)
|
||||
} else if (isObject(object)) {
|
||||
return JSON.parse(JSON.stringify(object))
|
||||
} else {
|
||||
return object
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the second object parameter into the first object, in-place.
|
||||
* @returns The now modified first object parameter passed into the function.
|
||||
*/
|
||||
export function deepMerge(a: AnyRecord, b: AnyRecord) {
|
||||
/**
|
||||
* lodash.merge will not merge a full array with an empty one.
|
||||
* deepMerge will replace arrays wholesale
|
||||
*/
|
||||
if (!a || !b) {
|
||||
throw 'Attempting to deepMerge with null values'
|
||||
}
|
||||
const customizer = (aValue: any, bValue: any) => {
|
||||
if (isArray(aValue)) {
|
||||
return bValue
|
||||
}
|
||||
}
|
||||
mergeWith(a, b, customizer)
|
||||
return a
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new object by selecting certain keys from input object.
|
||||
*/
|
||||
export function pickByCopy<T>(object: T, keys: Array<keyof T>) {
|
||||
const result = {} as T
|
||||
for (const key of keys) {
|
||||
result[key] = object[key]
|
||||
}
|
||||
return Copy(result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively makes an object immutable via Object.freeze
|
||||
*/
|
||||
export function deepFreeze(object: any) {
|
||||
const propNames = Object.getOwnPropertyNames(object)
|
||||
for (const name of propNames) {
|
||||
const value = object[name]
|
||||
if (value && typeof value === 'object' && !Object.isFrozen(value)) {
|
||||
object[name] = deepFreeze(value)
|
||||
} else {
|
||||
object[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
return Object.freeze(object)
|
||||
}
|
||||
|
||||
export function isValidUrl(url: string): boolean {
|
||||
try {
|
||||
new URL(url)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an object has a getter defined for a given property
|
||||
*/
|
||||
export function hasGetter(object: any, property: string) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(object), property)
|
||||
return descriptor && !isNullOrUndefined(descriptor.get)
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a hex string into a desired number of bits
|
||||
* @returns A hexadecimal string truncated to the number of desired bits
|
||||
*/
|
||||
export function truncateHexString(string: string, desiredBits: number) {
|
||||
const BITS_PER_HEX_CHAR = 4
|
||||
const desiredCharLength = desiredBits / BITS_PER_HEX_CHAR
|
||||
return string.substring(0, desiredCharLength)
|
||||
}
|
||||
|
||||
/**
|
||||
* When awaited, this function allows code execution to pause for a set time.
|
||||
* Should be used primarily for testing.
|
||||
*/
|
||||
export async function sleep(milliseconds: number, warn = true): Promise<void> {
|
||||
if (warn) {
|
||||
console.warn(`Sleeping for ${milliseconds}ms`)
|
||||
}
|
||||
return new Promise<void>((resolve) => {
|
||||
setTimeout(function () {
|
||||
resolve()
|
||||
}, milliseconds)
|
||||
})
|
||||
}
|
||||
|
||||
export function assertUnreachable(uncheckedCase: never): never {
|
||||
throw Error('Unchecked case ' + uncheckedCase)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean representing whether two dates are on the same day
|
||||
*/
|
||||
export function isSameDay(dateA: Date, dateB: Date) {
|
||||
return (
|
||||
dateA.getFullYear() === dateB.getFullYear() &&
|
||||
dateA.getMonth() === dateB.getMonth() &&
|
||||
dateA.getDate() === dateB.getDate()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts an array of objects in natural order
|
||||
* @param items - The array of objects to sort
|
||||
* @param property - The objects' property to sort by
|
||||
* @param direction - The sorting direction, either ascending (default) or descending
|
||||
* @returns Array of objects sorted in natural order
|
||||
*/
|
||||
export function naturalSort<T extends AnyRecord>(
|
||||
items: T[],
|
||||
property: keyof T,
|
||||
direction: 'asc' | 'desc' = 'asc',
|
||||
): T[] {
|
||||
switch (direction) {
|
||||
case 'asc':
|
||||
return [...items].sort(
|
||||
collator
|
||||
? (a, b) => collator.compare(a[property] as string, b[property] as string)
|
||||
: (a, b) => (a[property] as string).localeCompare(b[property] as string, 'en', { numeric: true }),
|
||||
)
|
||||
case 'desc':
|
||||
return [...items].sort(
|
||||
collator
|
||||
? (a, b) => collator.compare(b[property] as string, a[property] as string)
|
||||
: (a, b) => (b[property] as string).localeCompare(a[property] as string, 'en', { numeric: true }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function arraysEqual<T>(left: T[], right: T[]): boolean {
|
||||
if (left.length !== right.length) {
|
||||
return false
|
||||
}
|
||||
return left.every((item) => right.includes(item)) && right.every((item) => left.includes(item))
|
||||
}
|
||||
|
||||
const MicrosecondsInAMillisecond = 1_000
|
||||
const MillisecondsInASecond = 1_000
|
||||
|
||||
enum TimestampDigits {
|
||||
Seconds = 10,
|
||||
Milliseconds = 13,
|
||||
Microseconds = 16,
|
||||
}
|
||||
|
||||
export function convertTimestampToMilliseconds(timestamp: number): number {
|
||||
const digits = String(timestamp).length
|
||||
switch (digits) {
|
||||
case TimestampDigits.Seconds:
|
||||
return timestamp * MillisecondsInASecond
|
||||
case TimestampDigits.Milliseconds:
|
||||
return timestamp
|
||||
case TimestampDigits.Microseconds:
|
||||
return Math.floor(timestamp / MicrosecondsInAMillisecond)
|
||||
|
||||
default:
|
||||
throw `Unhandled timestamp precision: ${timestamp}`
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizeHtmlString(html: string): string {
|
||||
return DOMPurify.sanitize(html)
|
||||
}
|
||||
|
||||
let sharedDateFormatter: unknown
|
||||
export function dateToLocalizedString(date: Date): string {
|
||||
if (typeof Intl !== 'undefined' && Intl.DateTimeFormat && typeof navigator !== 'undefined') {
|
||||
if (!sharedDateFormatter) {
|
||||
const locale = navigator.languages && navigator.languages.length ? navigator.languages[0] : navigator.language
|
||||
sharedDateFormatter = new Intl.DateTimeFormat(locale, {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: '2-digit',
|
||||
weekday: 'long',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
}
|
||||
return (sharedDateFormatter as Intl.DateTimeFormat).format(date)
|
||||
} else {
|
||||
// IE < 11, Safari <= 9.0.
|
||||
// In English, this generates the string most similar to
|
||||
// the toLocaleDateString() result above.
|
||||
return date.toDateString() + ' ' + date.toLocaleTimeString()
|
||||
}
|
||||
}
|
||||
|
||||
export function nonSecureRandomIdentifier(): string {
|
||||
return `${Math.random() * 100}`.replace('.', '')
|
||||
}
|
||||
|
||||
export function splitString(string: string, parts: number): string[] {
|
||||
const outputLength = string.length
|
||||
const partLength = outputLength / parts
|
||||
const partitions = []
|
||||
for (let i = 0; i < parts; i++) {
|
||||
const partition = string.slice(partLength * i, partLength * (i + 1))
|
||||
partitions.push(partition)
|
||||
}
|
||||
return partitions
|
||||
}
|
||||
|
||||
export function firstHalfOfString(string: string): string {
|
||||
return string.substring(0, string.length / 2)
|
||||
}
|
||||
|
||||
export function secondHalfOfString(string: string): string {
|
||||
return string.substring(string.length / 2, string.length)
|
||||
}
|
||||
|
||||
export function log(namespace: string, ...args: any[]): void {
|
||||
const date = new Date()
|
||||
const timeString = `${date.toLocaleTimeString().replace(' PM', '').replace(' AM', '')}.${date.getMilliseconds()}`
|
||||
customLog(
|
||||
`%c${namespace}%c${timeString}`,
|
||||
'color: black; font-weight: bold; margin-right: 4px',
|
||||
'color: gray',
|
||||
...args,
|
||||
)
|
||||
}
|
||||
|
||||
function customLog(..._args: any[]) {
|
||||
// eslint-disable-next-line no-console, prefer-rest-params
|
||||
Function.prototype.apply.call(console.log, console, arguments)
|
||||
}
|
||||
|
||||
export function assert(value: unknown): asserts value {
|
||||
if (value === undefined) {
|
||||
throw new Error('Assertion failed; value must be defined')
|
||||
}
|
||||
}
|
||||
|
||||
export function useBoolean(value: boolean | undefined, defaultValue: boolean): boolean {
|
||||
return value != undefined ? value : defaultValue
|
||||
}
|
||||
5
packages/utils/src/Domain/Uuid/Utils.ts
Normal file
5
packages/utils/src/Domain/Uuid/Utils.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export function Uuids(items: { uuid: string }[]): string[] {
|
||||
return items.map((item) => {
|
||||
return item.uuid
|
||||
})
|
||||
}
|
||||
21
packages/utils/src/Domain/Uuid/UuidGenerator.ts
Normal file
21
packages/utils/src/Domain/Uuid/UuidGenerator.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* An abstract class with no instance methods. Used globally to generate uuids by any
|
||||
* consumer. Application must call SetGenerator before use.
|
||||
*/
|
||||
export class UuidGenerator {
|
||||
private static syncUuidFunc: () => string
|
||||
|
||||
/**
|
||||
* @param {function} syncImpl - A syncronous function that returns a UUID.
|
||||
*/
|
||||
static SetGenerator(syncImpl: () => string): void {
|
||||
this.syncUuidFunc = syncImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a UUID string asyncronously.
|
||||
*/
|
||||
public static GenerateUuid(): string {
|
||||
return this.syncUuidFunc()
|
||||
}
|
||||
}
|
||||
95
packages/utils/src/Domain/Uuid/UuidMap.ts
Normal file
95
packages/utils/src/Domain/Uuid/UuidMap.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { Uuid } from '@standardnotes/common'
|
||||
import { addIfUnique, removeFromArray } from '../Utils/Utils'
|
||||
|
||||
/**
|
||||
* Maps a UUID to an array of UUIDS to establish either direct or inverse
|
||||
* relationships between UUID strings (represantative of items or payloads).
|
||||
*/
|
||||
export class UuidMap {
|
||||
/** uuid to uuids that we have a relationship with */
|
||||
private directMap: Partial<Record<Uuid, Uuid[]>> = {}
|
||||
/** uuid to uuids that have a relationship with us */
|
||||
private inverseMap: Partial<Record<Uuid, Uuid[]>> = {}
|
||||
|
||||
public makeCopy(): UuidMap {
|
||||
const copy = new UuidMap()
|
||||
copy.directMap = Object.assign({}, this.directMap)
|
||||
copy.inverseMap = Object.assign({}, this.inverseMap)
|
||||
return copy
|
||||
}
|
||||
|
||||
public getDirectRelationships(uuid: Uuid): Uuid[] {
|
||||
return this.directMap[uuid] || []
|
||||
}
|
||||
|
||||
public getInverseRelationships(uuid: Uuid): Uuid[] {
|
||||
return this.inverseMap[uuid] || []
|
||||
}
|
||||
|
||||
public establishRelationship(uuidA: Uuid, uuidB: Uuid): void {
|
||||
this.establishDirectRelationship(uuidA, uuidB)
|
||||
this.establishInverseRelationship(uuidA, uuidB)
|
||||
}
|
||||
|
||||
public deestablishRelationship(uuidA: Uuid, uuidB: Uuid): void {
|
||||
this.deestablishDirectRelationship(uuidA, uuidB)
|
||||
this.deestablishInverseRelationship(uuidA, uuidB)
|
||||
}
|
||||
|
||||
public setAllRelationships(uuid: Uuid, relationships: Uuid[]): void {
|
||||
const previousDirect = this.directMap[uuid] || []
|
||||
this.directMap[uuid] = relationships
|
||||
|
||||
/** Remove all previous values in case relationships have changed
|
||||
* The updated references will be added afterwards.
|
||||
*/
|
||||
for (const previousRelationship of previousDirect) {
|
||||
this.deestablishInverseRelationship(uuid, previousRelationship)
|
||||
}
|
||||
|
||||
/** Now map current relationships */
|
||||
for (const newRelationship of relationships) {
|
||||
this.establishInverseRelationship(uuid, newRelationship)
|
||||
}
|
||||
}
|
||||
|
||||
public removeFromMap(uuid: Uuid): void {
|
||||
/** Items that we reference */
|
||||
const directReferences = this.directMap[uuid] || []
|
||||
for (const directReference of directReferences) {
|
||||
removeFromArray(this.inverseMap[directReference] || [], uuid)
|
||||
}
|
||||
delete this.directMap[uuid]
|
||||
|
||||
/** Items that are referencing us */
|
||||
const inverseReferences = this.inverseMap[uuid] || []
|
||||
for (const inverseReference of inverseReferences) {
|
||||
removeFromArray(this.directMap[inverseReference] || [], uuid)
|
||||
}
|
||||
delete this.inverseMap[uuid]
|
||||
}
|
||||
|
||||
private establishDirectRelationship(uuidA: Uuid, uuidB: Uuid): void {
|
||||
const index = this.directMap[uuidA] || []
|
||||
addIfUnique(index, uuidB)
|
||||
this.directMap[uuidA] = index
|
||||
}
|
||||
|
||||
private establishInverseRelationship(uuidA: Uuid, uuidB: Uuid): void {
|
||||
const inverseIndex = this.inverseMap[uuidB] || []
|
||||
addIfUnique(inverseIndex, uuidA)
|
||||
this.inverseMap[uuidB] = inverseIndex
|
||||
}
|
||||
|
||||
private deestablishDirectRelationship(uuidA: Uuid, uuidB: Uuid): void {
|
||||
const index = this.directMap[uuidA] || []
|
||||
removeFromArray(index, uuidB)
|
||||
this.directMap[uuidA] = index
|
||||
}
|
||||
|
||||
private deestablishInverseRelationship(uuidA: Uuid, uuidB: Uuid): void {
|
||||
const inverseIndex = this.inverseMap[uuidB] || []
|
||||
removeFromArray(inverseIndex, uuidA)
|
||||
this.inverseMap[uuidB] = inverseIndex
|
||||
}
|
||||
}
|
||||
5
packages/utils/src/Domain/index.ts
Normal file
5
packages/utils/src/Domain/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './Utils/Utils'
|
||||
export * from './Uuid/UuidGenerator'
|
||||
export * from './Uuid/UuidMap'
|
||||
export * from './Uuid/Utils'
|
||||
export * from './Deferred/Deferred'
|
||||
1
packages/utils/src/index.ts
Normal file
1
packages/utils/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './Domain'
|
||||
13
packages/utils/tsconfig.json
Normal file
13
packages/utils/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../node_modules/@standardnotes/config/src/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"skipLibCheck": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"references": [],
|
||||
"exclude": ["**/*.spec.ts", "dist", "node_modules"]
|
||||
}
|
||||
226
yarn.lock
226
yarn.lock
@@ -6130,7 +6130,7 @@ __metadata:
|
||||
"@reduxjs/toolkit": 1.8.0
|
||||
"@standardnotes/editor-kit": 2.2.5
|
||||
"@standardnotes/stylekit": 5.23.0
|
||||
"@standardnotes/utils": 1.6.2
|
||||
"@standardnotes/utils": "workspace:*"
|
||||
"@testing-library/dom": 8.11.3
|
||||
"@testing-library/jest-dom": 5.16.2
|
||||
"@testing-library/react": 12.1.4
|
||||
@@ -6326,7 +6326,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/common@npm:^1.19.6, @standardnotes/common@npm:^1.23.1":
|
||||
"@standardnotes/common@npm:^1.23.1":
|
||||
version: 1.23.1
|
||||
resolution: "@standardnotes/common@npm:1.23.1"
|
||||
checksum: f498f4c469f7b9cdfc08b7648077832a2a214d844f012d02d73c2c418fab221af3302570cc6b1957b5ed481b55237f95bc24fc5c231162bfcdf8730333d38405
|
||||
@@ -6519,7 +6519,7 @@ __metadata:
|
||||
"@standardnotes/responses": ^1.6.39
|
||||
"@standardnotes/services": "workspace:*"
|
||||
"@standardnotes/sncrypto-common": ^1.9.0
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
"@standardnotes/utils": "workspace:*"
|
||||
"@types/jest": ^27.4.1
|
||||
"@types/node": ^18.0.0
|
||||
"@typescript-eslint/eslint-plugin": "*"
|
||||
@@ -6573,7 +6573,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.23.1
|
||||
"@standardnotes/services": "workspace:*"
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
"@standardnotes/utils": "workspace:*"
|
||||
"@types/jest": ^27.4.1
|
||||
"@types/wicg-file-system-access": ^2020.9.5
|
||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||
@@ -6596,7 +6596,7 @@ __metadata:
|
||||
"@standardnotes/responses": ^1.6.39
|
||||
"@standardnotes/services": "workspace:*"
|
||||
"@standardnotes/sncrypto-common": ^1.9.0
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
"@standardnotes/utils": "workspace:*"
|
||||
"@types/jest": ^27.4.1
|
||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||
eslint-plugin-prettier: ^4.2.1
|
||||
@@ -6982,7 +6982,7 @@ __metadata:
|
||||
"@standardnotes/common": ^1.23.1
|
||||
"@standardnotes/features": "workspace:*"
|
||||
"@standardnotes/responses": ^1.6.39
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
"@standardnotes/utils": "workspace:*"
|
||||
"@types/jest": ^27.4.1
|
||||
"@types/lodash": ^4.14.182
|
||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||
@@ -7088,7 +7088,7 @@ __metadata:
|
||||
"@standardnotes/common": ^1.23.1
|
||||
"@standardnotes/models": "workspace:*"
|
||||
"@standardnotes/responses": ^1.6.39
|
||||
"@standardnotes/utils": ^1.6.12
|
||||
"@standardnotes/utils": "workspace:*"
|
||||
"@types/jest": ^27.4.1
|
||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||
"@typescript-eslint/parser": ^5.12.1
|
||||
@@ -7298,27 +7298,26 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/utils@npm:1.6.2":
|
||||
version: 1.6.2
|
||||
resolution: "@standardnotes/utils@npm:1.6.2"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.19.6
|
||||
dompurify: ^2.3.6
|
||||
lodash: ^4.17.21
|
||||
checksum: e7d90879921d3991527dc1fd2f87cf16706008d06d20b690e41a7a3ee1ab37289fa4ab354a58b3d2ae58609bb8b56f1afe90544b7911be5b04ca4117aa4b982d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@standardnotes/utils@npm:^1.6.12":
|
||||
version: 1.6.12
|
||||
resolution: "@standardnotes/utils@npm:1.6.12"
|
||||
"@standardnotes/utils@^1.6.12, @standardnotes/utils@workspace:*, @standardnotes/utils@workspace:packages/utils":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@standardnotes/utils@workspace:packages/utils"
|
||||
dependencies:
|
||||
"@standardnotes/common": ^1.23.1
|
||||
"@types/dompurify": ^2.3.3
|
||||
"@types/jest": ^27.4.1
|
||||
"@types/jsdom": ^16.2.14
|
||||
"@types/lodash": ^4.14.179
|
||||
"@types/node": ^18.0.0
|
||||
"@typescript-eslint/eslint-plugin": ^5.30.0
|
||||
dompurify: ^2.3.6
|
||||
eslint-plugin-prettier: ^4.2.1
|
||||
jest: ^27.5.1
|
||||
jsdom: ^20.0.0
|
||||
lodash: ^4.17.21
|
||||
checksum: e177b1fa518ca2c0bcc5602d2a83d37946461bc4c3d8daa329d7290d61dec9bcfd5b9c1593582672598b0696d994f7ce42b9ca16f82a485fd45cb221411bd4e8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
reflect-metadata: ^0.1.13
|
||||
ts-jest: ^27.1.3
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@standardnotes/web-server@workspace:packages/web-server":
|
||||
version: 0.0.0-use.local
|
||||
@@ -7994,6 +7993,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/dompurify@npm:^2.3.3":
|
||||
version: 2.3.3
|
||||
resolution: "@types/dompurify@npm:2.3.3"
|
||||
dependencies:
|
||||
"@types/trusted-types": "*"
|
||||
checksum: 427e2dc60d94d13d7860a293b926b376727cb2f545a3334a3f2e7de695a2bb23058dd15108e49e0651378229b443ee8ae0028034b6f2df9a9008c04fb7ad6f8f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/eslint-scope@npm:^3.7.3":
|
||||
version: 3.7.4
|
||||
resolution: "@types/eslint-scope@npm:3.7.4"
|
||||
@@ -8239,6 +8247,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/jsdom@npm:^16.2.14":
|
||||
version: 16.2.14
|
||||
resolution: "@types/jsdom@npm:16.2.14"
|
||||
dependencies:
|
||||
"@types/node": "*"
|
||||
"@types/parse5": "*"
|
||||
"@types/tough-cookie": "*"
|
||||
checksum: 12bb926fa74ea07c0ba0bfd5bf185ac0fd771b28666a5e8784b9af4bb96bb0c51fc5f494eff7da1d3cd804e4757f640a23c344c1cd5d188f95ab0ab51770d88b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/json-buffer@npm:~3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "@types/json-buffer@npm:3.0.0"
|
||||
@@ -8411,6 +8430,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/parse5@npm:*":
|
||||
version: 6.0.3
|
||||
resolution: "@types/parse5@npm:6.0.3"
|
||||
checksum: ddb59ee4144af5dfcc508a8dcf32f37879d11e12559561e65788756b95b33e6f03ea027d88e1f5408f9b7bfb656bf630ace31a2169edf44151daaf8dd58df1b7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/parse5@npm:^5.0.0":
|
||||
version: 5.0.3
|
||||
resolution: "@types/parse5@npm:5.0.3"
|
||||
@@ -8933,7 +8959,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/trusted-types@npm:^2.0.2":
|
||||
"@types/tough-cookie@npm:*":
|
||||
version: 4.0.2
|
||||
resolution: "@types/tough-cookie@npm:4.0.2"
|
||||
checksum: e055556ffdaa39ad85ede0af192c93f93f986f4bd9e9426efdc2948e3e2632db3a4a584d4937dbf6d7620527419bc99e6182d3daf2b08685e710f2eda5291905
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/trusted-types@npm:*, @types/trusted-types@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "@types/trusted-types@npm:2.0.2"
|
||||
checksum: 3371eef5f1c50e1c3c07a127c1207b262ba65b83dd167a1c460fc1b135a3fb0c97b9f508efebd383f239cc5dd5b7169093686a692a501fde9c3f7208657d9b0d
|
||||
@@ -9616,7 +9649,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"abab@npm:^2.0.3, abab@npm:^2.0.5":
|
||||
"abab@npm:^2.0.3, abab@npm:^2.0.5, abab@npm:^2.0.6":
|
||||
version: 2.0.6
|
||||
resolution: "abab@npm:2.0.6"
|
||||
checksum: 6ffc1af4ff315066c62600123990d87551ceb0aafa01e6539da77b0f5987ac7019466780bf480f1787576d4385e3690c81ccc37cfda12819bf510b8ab47e5a3e
|
||||
@@ -14827,6 +14860,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cssom@npm:^0.5.0":
|
||||
version: 0.5.0
|
||||
resolution: "cssom@npm:0.5.0"
|
||||
checksum: 823471aa30091c59e0a305927c30e7768939b6af70405808f8d2ce1ca778cddcb24722717392438329d1691f9a87cb0183b64b8d779b56a961546d54854fde01
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cssom@npm:~0.3.6":
|
||||
version: 0.3.8
|
||||
resolution: "cssom@npm:0.3.8"
|
||||
@@ -15578,6 +15618,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"data-urls@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "data-urls@npm:3.0.2"
|
||||
dependencies:
|
||||
abab: ^2.0.6
|
||||
whatwg-mimetype: ^3.0.0
|
||||
whatwg-url: ^11.0.0
|
||||
checksum: 033fc3dd0fba6d24bc9a024ddcf9923691dd24f90a3d26f6545d6a2f71ec6956f93462f2cdf2183cc46f10dc01ed3bcb36731a8208456eb1a08147e571fe2a76
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"date-time@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "date-time@npm:3.1.0"
|
||||
@@ -15655,7 +15706,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decimal.js@npm:^10.2.1":
|
||||
"decimal.js@npm:^10.2.1, decimal.js@npm:^10.3.1":
|
||||
version: 10.3.1
|
||||
resolution: "decimal.js@npm:10.3.1"
|
||||
checksum: 0351ac9f05fe050f23227aa6a4573bee2d58fa7378fcf28d969a8c789525032effb488a90320fd3fe86a66e17b4bc507d811b15eada5b7f0e7ec5d2af4c24a59
|
||||
@@ -16412,6 +16463,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"domexception@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "domexception@npm:4.0.0"
|
||||
dependencies:
|
||||
webidl-conversions: ^7.0.0
|
||||
checksum: ddbc1268edf33a8ba02ccc596735ede80375ee0cf124b30d2f05df5b464ba78ef4f49889b6391df4a04954e63d42d5631c7fcf8b1c4f12bc531252977a5f13d5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"domhandler@npm:^2.3.0":
|
||||
version: 2.4.2
|
||||
resolution: "domhandler@npm:2.4.2"
|
||||
@@ -16942,6 +17002,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"entities@npm:^4.3.0":
|
||||
version: 4.3.1
|
||||
resolution: "entities@npm:4.3.1"
|
||||
checksum: e8f6d2bac238494b2355e90551893882d2675142be7e7bdfcb15248ed0652a630678ba0e3a8dc750693e736cb6011f504c27dabeb4cd3330560092e88b105090
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"entities@npm:~2.0.0":
|
||||
version: 2.0.3
|
||||
resolution: "entities@npm:2.0.3"
|
||||
@@ -20599,6 +20666,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html-encoding-sniffer@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "html-encoding-sniffer@npm:3.0.0"
|
||||
dependencies:
|
||||
whatwg-encoding: ^2.0.0
|
||||
checksum: 8d806aa00487e279e5ccb573366a951a9f68f65c90298eac9c3a2b440a7ffe46615aff2995a2f61c6746c639234e6179a97e18ca5ccbbf93d3725ef2099a4502
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html-entities@npm:^1.3.1":
|
||||
version: 1.4.0
|
||||
resolution: "html-entities@npm:1.4.0"
|
||||
@@ -20893,7 +20969,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"https-proxy-agent@npm:^5.0.0":
|
||||
"https-proxy-agent@npm:^5.0.0, https-proxy-agent@npm:^5.0.1":
|
||||
version: 5.0.1
|
||||
resolution: "https-proxy-agent@npm:5.0.1"
|
||||
dependencies:
|
||||
@@ -20985,7 +21061,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iconv-lite@npm:0.6, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3":
|
||||
"iconv-lite@npm:0.6, iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3":
|
||||
version: 0.6.3
|
||||
resolution: "iconv-lite@npm:0.6.3"
|
||||
dependencies:
|
||||
@@ -23637,6 +23713,46 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jsdom@npm:^20.0.0":
|
||||
version: 20.0.0
|
||||
resolution: "jsdom@npm:20.0.0"
|
||||
dependencies:
|
||||
abab: ^2.0.6
|
||||
acorn: ^8.7.1
|
||||
acorn-globals: ^6.0.0
|
||||
cssom: ^0.5.0
|
||||
cssstyle: ^2.3.0
|
||||
data-urls: ^3.0.2
|
||||
decimal.js: ^10.3.1
|
||||
domexception: ^4.0.0
|
||||
escodegen: ^2.0.0
|
||||
form-data: ^4.0.0
|
||||
html-encoding-sniffer: ^3.0.0
|
||||
http-proxy-agent: ^5.0.0
|
||||
https-proxy-agent: ^5.0.1
|
||||
is-potential-custom-element-name: ^1.0.1
|
||||
nwsapi: ^2.2.0
|
||||
parse5: ^7.0.0
|
||||
saxes: ^6.0.0
|
||||
symbol-tree: ^3.2.4
|
||||
tough-cookie: ^4.0.0
|
||||
w3c-hr-time: ^1.0.2
|
||||
w3c-xmlserializer: ^3.0.0
|
||||
webidl-conversions: ^7.0.0
|
||||
whatwg-encoding: ^2.0.0
|
||||
whatwg-mimetype: ^3.0.0
|
||||
whatwg-url: ^11.0.0
|
||||
ws: ^8.8.0
|
||||
xml-name-validator: ^4.0.0
|
||||
peerDependencies:
|
||||
canvas: ^2.5.0
|
||||
peerDependenciesMeta:
|
||||
canvas:
|
||||
optional: true
|
||||
checksum: f69b40679d8cfaee2353615445aaff08b823c53dc7778ede6592d02ed12b3e9fb4e8db2b6d033551b67e08424a3adb2b79d231caa7dcda2d16019c20c705c11f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"jsesc@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "jsesc@npm:1.3.0"
|
||||
@@ -28618,6 +28734,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse5@npm:^7.0.0":
|
||||
version: 7.0.0
|
||||
resolution: "parse5@npm:7.0.0"
|
||||
dependencies:
|
||||
entities: ^4.3.0
|
||||
checksum: 7da5d61cc18eb36ffa71fc861e65cbfd1f23d96483a6631254e627be667dbc9c93ac0b0e6cb17a13a2e4033dab19bfb2f76f38e5936cfb57240ed49036a83fcc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parseurl@npm:~1.3.2, parseurl@npm:~1.3.3":
|
||||
version: 1.3.3
|
||||
resolution: "parseurl@npm:1.3.3"
|
||||
@@ -34002,6 +34127,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"saxes@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "saxes@npm:6.0.0"
|
||||
dependencies:
|
||||
xmlchars: ^2.2.0
|
||||
checksum: d3fa3e2aaf6c65ed52ee993aff1891fc47d5e47d515164b5449cbf5da2cbdc396137e55590472e64c5c436c14ae64a8a03c29b9e7389fc6f14035cf4e982ef3b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"scheduler@npm:^0.17.0":
|
||||
version: 0.17.0
|
||||
resolution: "scheduler@npm:0.17.0"
|
||||
@@ -38319,6 +38453,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"w3c-xmlserializer@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "w3c-xmlserializer@npm:3.0.0"
|
||||
dependencies:
|
||||
xml-name-validator: ^4.0.0
|
||||
checksum: 0af8589942eeb11c9fe29eb31a1a09f3d5dd136aea53a9848dfbabff79ac0dd26fe13eb54d330d5555fe27bb50b28dca0715e09f9cc2bfa7670ccc8b7f919ca2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wait-on@npm:^5.2.1":
|
||||
version: 5.3.0
|
||||
resolution: "wait-on@npm:5.3.0"
|
||||
@@ -38900,6 +39043,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-encoding@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "whatwg-encoding@npm:2.0.0"
|
||||
dependencies:
|
||||
iconv-lite: 0.6.3
|
||||
checksum: 7087810c410aa9b689cbd6af8773341a53cdc1f3aae2a882c163bd5522ec8ca4cdfc269aef417a5792f411807d5d77d50df4c24e3abb00bb60192858a40cc675
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-fetch@npm:^3.0.0, whatwg-fetch@npm:^3.6.2":
|
||||
version: 3.6.2
|
||||
resolution: "whatwg-fetch@npm:3.6.2"
|
||||
@@ -38914,6 +39066,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-mimetype@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "whatwg-mimetype@npm:3.0.0"
|
||||
checksum: ce08bbb36b6aaf64f3a84da89707e3e6a31e5ab1c1a2379fd68df79ba712a4ab090904f0b50e6693b0dafc8e6343a6157e40bf18fdffd26e513cf95ee2a59824
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"whatwg-url-without-unicode@npm:8.0.0-3":
|
||||
version: 8.0.0-3
|
||||
resolution: "whatwg-url-without-unicode@npm:8.0.0-3"
|
||||
@@ -39458,7 +39617,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ws@npm:^8.4.2":
|
||||
"ws@npm:^8.4.2, ws@npm:^8.8.0":
|
||||
version: 8.8.0
|
||||
resolution: "ws@npm:8.8.0"
|
||||
peerDependencies:
|
||||
@@ -39522,6 +39681,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xml-name-validator@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "xml-name-validator@npm:4.0.0"
|
||||
checksum: af100b79c29804f05fa35aa3683e29a321db9b9685d5e5febda3fa1e40f13f85abc40f45a6b2bf7bee33f68a1dc5e8eaef4cec100a304a9db565e6061d4cb5ad
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"xmlbuilder@npm:>=11.0.1":
|
||||
version: 15.1.1
|
||||
resolution: "xmlbuilder@npm:15.1.1"
|
||||
|
||||
Reference in New Issue
Block a user