mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-04 18:29:23 +02:00
refactor(struct): tweak type plugin system
This commit is contained in:
parent
b601f7a7f2
commit
9f3d480523
22 changed files with 862 additions and 530 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -24,6 +24,7 @@
|
||||||
"hhmm",
|
"hhmm",
|
||||||
"hisi",
|
"hisi",
|
||||||
"jmuxer",
|
"jmuxer",
|
||||||
|
"keyof",
|
||||||
"killforward",
|
"killforward",
|
||||||
"laggy",
|
"laggy",
|
||||||
"lapo",
|
"lapo",
|
||||||
|
@ -46,8 +47,10 @@
|
||||||
"tcpip",
|
"tcpip",
|
||||||
"tinyh",
|
"tinyh",
|
||||||
"tsbuildinfo",
|
"tsbuildinfo",
|
||||||
|
"typeof",
|
||||||
"uifabric",
|
"uifabric",
|
||||||
"webadb",
|
"webadb",
|
||||||
|
"webpackbar",
|
||||||
"websockify",
|
"websockify",
|
||||||
"webusb",
|
"webusb",
|
||||||
"wifi",
|
"wifi",
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@yume-chan/adb-backend-web",
|
"name": "@yume-chan/adb-backend-web",
|
||||||
|
"private": true,
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "Backend for `@yume-chan/adb` using Web technologies.",
|
"description": "Backend for `@yume-chan/adb` using Web technologies.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@yume-chan/adb",
|
"name": "@yume-chan/adb",
|
||||||
|
"private": true,
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "TypeScript implementation of Android Debug Bridge (ADB) protocol.",
|
"description": "TypeScript implementation of Android Debug Bridge (ADB) protocol.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
@ -34,7 +35,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@yume-chan/async-operation-manager": "2.1.3",
|
"@yume-chan/async-operation-manager": "2.1.3",
|
||||||
"@yume-chan/event": "^0.0.1",
|
"@yume-chan/event": "^0.0.1",
|
||||||
"@yume-chan/struct": "^0.0.1",
|
"@yume-chan/struct": "^0.0.2",
|
||||||
"tslib": "2.0.3"
|
"tslib": "2.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
173
packages/demo/package-lock.json
generated
173
packages/demo/package-lock.json
generated
|
@ -861,6 +861,15 @@
|
||||||
"integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
|
"integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ansi-escapes": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"type-fest": "^0.11.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ansi-html": {
|
"ansi-html": {
|
||||||
"version": "0.0.7",
|
"version": "0.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
|
||||||
|
@ -1232,6 +1241,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ci-info": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"class-utils": {
|
"class-utils": {
|
||||||
"version": "0.3.6",
|
"version": "0.3.6",
|
||||||
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
|
||||||
|
@ -1407,6 +1422,12 @@
|
||||||
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
|
"integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"consola": {
|
||||||
|
"version": "2.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz",
|
||||||
|
"integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"content-disposition": {
|
"content-disposition": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
|
||||||
|
@ -2249,6 +2270,15 @@
|
||||||
"websocket-driver": ">=0.5.1"
|
"websocket-driver": ">=0.5.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"figures": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"escape-string-regexp": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"file-loader": {
|
"file-loader": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
|
||||||
|
@ -4348,6 +4378,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pretty-time": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
@ -5232,6 +5268,15 @@
|
||||||
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
|
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"std-env": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/std-env/-/std-env-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-IjYQUinA3lg5re/YMlwlfhqNRTzMZMqE+pezevdcTaHceqx8ngEi1alX9nNCk9Sc81fy1fLDeQoaCzeiW1yBOQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ci-info": "^1.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"streamsaver": {
|
"streamsaver": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/streamsaver/-/streamsaver-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/streamsaver/-/streamsaver-2.0.5.tgz",
|
||||||
|
@ -5402,6 +5447,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"text-table": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"thunky": {
|
"thunky": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
|
||||||
|
@ -5516,6 +5567,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
|
||||||
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
|
"integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
|
||||||
},
|
},
|
||||||
|
"type-fest": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"type-is": {
|
"type-is": {
|
||||||
"version": "1.6.18",
|
"version": "1.6.18",
|
||||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
|
@ -6454,6 +6511,122 @@
|
||||||
"source-map": "~0.6.1"
|
"source-map": "~0.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"webpackbar": {
|
||||||
|
"version": "5.0.0-3",
|
||||||
|
"resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.0-3.tgz",
|
||||||
|
"integrity": "sha512-viW6KCYjMb0NPoDrw2jAmLXU2dEOhRrtku28KmOfeE1vxbfwCYuTbTaMhnkrCZLFAFyY9Q49Z/jzYO80Dw5b8g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-escapes": "^4.3.1",
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"consola": "^2.15.0",
|
||||||
|
"figures": "^3.2.0",
|
||||||
|
"pretty-time": "^1.1.0",
|
||||||
|
"std-env": "^2.2.1",
|
||||||
|
"text-table": "^0.2.0",
|
||||||
|
"wrap-ansi": "^7.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wrap-ansi": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"websocket-driver": {
|
"websocket-driver": {
|
||||||
"version": "0.6.5",
|
"version": "0.6.5",
|
||||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
|
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "demo",
|
"name": "demo",
|
||||||
"version": "0.0.1",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"version": "0.0.1",
|
||||||
"description": "Demo of `@yume-chan/adb` and `@yume-chan/adb-backend-web`.",
|
"description": "Demo of `@yume-chan/adb` and `@yume-chan/adb-backend-web`.",
|
||||||
"author": "Simon Chan <cnsimonchan@live.com>",
|
"author": "Simon Chan <cnsimonchan@live.com>",
|
||||||
"homepage": "https://github.com/yume-chan/ya-webadb#readme",
|
"homepage": "https://github.com/yume-chan/ya-webadb#readme",
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
"webpack-bundle-analyzer": "4.3.0",
|
"webpack-bundle-analyzer": "4.3.0",
|
||||||
"webpack-cli": "4.2.0",
|
"webpack-cli": "4.2.0",
|
||||||
"webpack-dev-server": "3.11.0",
|
"webpack-dev-server": "3.11.0",
|
||||||
|
"webpackbar": "5.0.0-3",
|
||||||
"worker-loader": "3.0.7"
|
"worker-loader": "3.0.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -47,7 +48,7 @@
|
||||||
"@yume-chan/adb-backend-web": "^0.0.1",
|
"@yume-chan/adb-backend-web": "^0.0.1",
|
||||||
"@yume-chan/async-operation-manager": "2.1.3",
|
"@yume-chan/async-operation-manager": "2.1.3",
|
||||||
"@yume-chan/event": "^0.0.1",
|
"@yume-chan/event": "^0.0.1",
|
||||||
"@yume-chan/struct": "^0.0.1",
|
"@yume-chan/struct": "^0.0.2",
|
||||||
"jmuxer": "2.0.0",
|
"jmuxer": "2.0.0",
|
||||||
"path-browserify": "1.0.1",
|
"path-browserify": "1.0.1",
|
||||||
"react": "17.0.1",
|
"react": "17.0.1",
|
||||||
|
|
|
@ -12,6 +12,18 @@ import { createTinyH264Decoder, TinyH264Decoder } from './tinyh264';
|
||||||
|
|
||||||
const DeviceServerPath = '/data/local/tmp/scrcpy-server.jar';
|
const DeviceServerPath = '/data/local/tmp/scrcpy-server.jar';
|
||||||
|
|
||||||
|
function clamp(value: number, min: number, max: number): number {
|
||||||
|
if (value < min) {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > max) {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
export const Scrcpy = withDisplayName('Scrcpy')(({
|
export const Scrcpy = withDisplayName('Scrcpy')(({
|
||||||
device
|
device
|
||||||
}: RouteProps): JSX.Element | null => {
|
}: RouteProps): JSX.Element | null => {
|
||||||
|
@ -283,14 +295,11 @@ export const Scrcpy = withDisplayName('Scrcpy')(({
|
||||||
action: AndroidMotionEventAction,
|
action: AndroidMotionEventAction,
|
||||||
e: React.PointerEvent<HTMLCanvasElement>
|
e: React.PointerEvent<HTMLCanvasElement>
|
||||||
) => {
|
) => {
|
||||||
e.preventDefault();
|
const view = canvasRef.current!.getBoundingClientRect();
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
const view = e.currentTarget.getBoundingClientRect();
|
|
||||||
const pointerViewX = e.clientX - view.x;
|
const pointerViewX = e.clientX - view.x;
|
||||||
const pointerViewY = e.clientY - view.y;
|
const pointerViewY = e.clientY - view.y;
|
||||||
const pointerScreenX = pointerViewX / view.width * width;
|
const pointerScreenX = clamp(pointerViewX / view.width, 0, 1) * width;
|
||||||
const pointerScreenY = pointerViewY / view.height * height;
|
const pointerScreenY = clamp(pointerViewY / view.height, 0, 1) * height;
|
||||||
|
|
||||||
scrcpyClientRef.current?.injectTouch({
|
scrcpyClientRef.current?.injectTouch({
|
||||||
action,
|
action,
|
||||||
|
@ -307,6 +316,7 @@ export const Scrcpy = withDisplayName('Scrcpy')(({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
canvasRef.current!.focus();
|
canvasRef.current!.focus();
|
||||||
|
e.currentTarget.setPointerCapture(e.pointerId);
|
||||||
injectTouch(AndroidMotionEventAction.Down, e);
|
injectTouch(AndroidMotionEventAction.Down, e);
|
||||||
}, [injectTouch]);
|
}, [injectTouch]);
|
||||||
|
|
||||||
|
@ -321,6 +331,7 @@ export const Scrcpy = withDisplayName('Scrcpy')(({
|
||||||
if (e.button !== 0) {
|
if (e.button !== 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
e.currentTarget.releasePointerCapture(e.pointerId);
|
||||||
injectTouch(AndroidMotionEventAction.Up, e);
|
injectTouch(AndroidMotionEventAction.Up, e);
|
||||||
}, [injectTouch]);
|
}, [injectTouch]);
|
||||||
|
|
||||||
|
@ -406,6 +417,7 @@ export const Scrcpy = withDisplayName('Scrcpy')(({
|
||||||
onPointerDown={handlePointerDown}
|
onPointerDown={handlePointerDown}
|
||||||
onPointerMove={handlePointerMove}
|
onPointerMove={handlePointerMove}
|
||||||
onPointerUp={handlePointerUp}
|
onPointerUp={handlePointerUp}
|
||||||
|
onPointerCancel={handlePointerUp}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
/>
|
/>
|
||||||
</DeviceView>
|
</DeviceView>
|
||||||
|
|
|
@ -6,9 +6,10 @@ var html_webpack_plugin_1 = tslib_1.__importDefault(require("html-webpack-plugin
|
||||||
var mini_css_extract_plugin_1 = tslib_1.__importDefault(require("mini-css-extract-plugin"));
|
var mini_css_extract_plugin_1 = tslib_1.__importDefault(require("mini-css-extract-plugin"));
|
||||||
var path_1 = tslib_1.__importDefault(require("path"));
|
var path_1 = tslib_1.__importDefault(require("path"));
|
||||||
var webpack_bundle_analyzer_1 = require("webpack-bundle-analyzer");
|
var webpack_bundle_analyzer_1 = require("webpack-bundle-analyzer");
|
||||||
|
var webpackbar_1 = tslib_1.__importDefault(require("webpackbar"));
|
||||||
var context = path_1.default.resolve(process.cwd());
|
var context = path_1.default.resolve(process.cwd());
|
||||||
var plugins = [
|
var plugins = [
|
||||||
new clean_webpack_plugin_1.CleanWebpackPlugin(),
|
new webpackbar_1.default({}),
|
||||||
new mini_css_extract_plugin_1.default({
|
new mini_css_extract_plugin_1.default({
|
||||||
filename: '[name].[contenthash].css',
|
filename: '[name].[contenthash].css',
|
||||||
}),
|
}),
|
||||||
|
@ -29,34 +30,40 @@ var plugins = [
|
||||||
if (process.env.ANALYZE) {
|
if (process.env.ANALYZE) {
|
||||||
plugins.push(new webpack_bundle_analyzer_1.BundleAnalyzerPlugin());
|
plugins.push(new webpack_bundle_analyzer_1.BundleAnalyzerPlugin());
|
||||||
}
|
}
|
||||||
var config = function (env, argv) { return ({
|
var config = function (env, argv) {
|
||||||
mode: 'development',
|
if (argv.mode !== 'production') {
|
||||||
devtool: argv.mode === 'production' ? 'source-map' : 'eval-source-map',
|
plugins.unshift(new clean_webpack_plugin_1.CleanWebpackPlugin());
|
||||||
context: context,
|
}
|
||||||
target: 'web',
|
return {
|
||||||
entry: {
|
mode: 'development',
|
||||||
index: './src/index.tsx',
|
devtool: argv.mode === 'production' ? 'source-map' : 'eval-source-map',
|
||||||
},
|
context: context,
|
||||||
output: {
|
target: 'web',
|
||||||
path: path_1.default.resolve(context, 'lib'),
|
entry: {
|
||||||
filename: '[name].[contenthash].js',
|
index: './src/index.tsx',
|
||||||
},
|
},
|
||||||
resolve: {
|
output: {
|
||||||
extensions: ['.ts', '.tsx', '.js'],
|
path: path_1.default.resolve(context, 'lib'),
|
||||||
fallback: { "path": require.resolve("path-browserify") },
|
filename: '[name].[contenthash].js',
|
||||||
},
|
},
|
||||||
plugins: plugins,
|
resolve: {
|
||||||
module: {
|
extensions: ['.ts', '.tsx', '.js'],
|
||||||
rules: [
|
// @ts-expect-error typing is not up to date
|
||||||
{ test: /\.js$/, enforce: 'pre', use: ['source-map-loader'], },
|
fallback: { "path": require.resolve("path-browserify") },
|
||||||
{ test: /\.css$/i, use: [mini_css_extract_plugin_1.default.loader, 'css-loader'] },
|
},
|
||||||
{ test: /\.asset$/, use: { loader: "file-loader" } },
|
plugins: plugins,
|
||||||
{ test: /\.tsx?$/i, loader: 'ts-loader', options: { projectReferences: true } },
|
module: {
|
||||||
],
|
rules: [
|
||||||
},
|
{ test: /\.js$/, enforce: 'pre', use: ['source-map-loader'], },
|
||||||
devServer: {
|
{ test: /\.css$/i, use: [mini_css_extract_plugin_1.default.loader, 'css-loader'] },
|
||||||
contentBase: path_1.default.resolve(context, 'lib'),
|
{ test: /\.asset$/, use: { loader: "file-loader" } },
|
||||||
port: 9000,
|
{ test: /\.tsx?$/i, loader: 'ts-loader', options: { projectReferences: true } },
|
||||||
},
|
],
|
||||||
}); };
|
},
|
||||||
|
devServer: {
|
||||||
|
contentBase: path_1.default.resolve(context, 'lib'),
|
||||||
|
port: 9000,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@yume-chan/event",
|
"name": "@yume-chan/event",
|
||||||
|
"private": true,
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "Event/EventEmitter",
|
"description": "Event/EventEmitter",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|
|
@ -4,30 +4,42 @@ C-style structure serializer and deserializer.
|
||||||
|
|
||||||
Fully compatible with TypeScript.
|
Fully compatible with TypeScript.
|
||||||
|
|
||||||
- [Compatibility](#compatibility)
|
|
||||||
- [Quick Start](#quick-start)
|
- [Quick Start](#quick-start)
|
||||||
|
- [Compatibility](#compatibility)
|
||||||
- [API](#api)
|
- [API](#api)
|
||||||
- [`placeholder` method](#placeholder-method)
|
- [`placeholder` method](#placeholder-method)
|
||||||
- [`Struct` constructor](#struct-constructor)
|
- [`Struct` constructor](#struct-constructor)
|
||||||
- [`Struct#uint8`/`uint16`/`uint32`/`int32` methods](#structuint8uint16uint32int32-methods)
|
- [`Struct#fields` method](#structfields-method)
|
||||||
- [`Struct#uint64`/`int64` method](#structuint64int64-method)
|
- [`Struct#uint8`/`uint16`/`int32`/`uint32` methods](#structuint8uint16int32uint32-methods)
|
||||||
|
- [`Struct#int64`/`uint64` methods](#structint64uint64-methods)
|
||||||
- [`extra` function](#extra-function)
|
- [`extra` function](#extra-function)
|
||||||
- [`afterParsed` method](#afterparsed-method)
|
- [`postDeserialize` method](#postdeserialize-method)
|
||||||
- [`deserialize` method](#deserialize-method)
|
- [`deserialize` method](#deserialize-method)
|
||||||
- [`serialize` method](#serialize-method)
|
- [`serialize` method](#serialize-method)
|
||||||
- [Extend types](#extend-types)
|
- [Custom types](#custom-types)
|
||||||
- [Backing Field](#backing-field)
|
- [`Struct#field` method](#structfield-method)
|
||||||
- [`FieldDescriptorBase` interface](#fielddescriptorbase-interface)
|
- [FieldDefinition](#fielddefinition)
|
||||||
- [`field` method](#field-method)
|
- [`FieldDefinition#getSize` method](#fielddefinitiongetsize-method)
|
||||||
- [`FieldTypeDefinition` interface](#fieldtypedefinition-interface)
|
- [`FieldDefinition#deserialize` method](#fielddefinitiondeserialize-method)
|
||||||
- [`deserialize` method](#deserialize-method-1)
|
- [`FieldDefinition#createValue` method](#fielddefinitioncreatevalue-method)
|
||||||
- [`getSize` method](#getsize-method)
|
- [FieldRuntimeValue](#fieldruntimevalue)
|
||||||
- [`getDynamicSize` method](#getdynamicsize-method)
|
|
||||||
- [`initialize` method](#initialize-method)
|
## Quick Start
|
||||||
- [`serialize` method](#serialize-method-1)
|
|
||||||
- [Array type](#array-type)
|
```ts
|
||||||
- [`registerFieldTypeDefinition` method](#registerfieldtypedefinition-method)
|
import Struct from '@yume-chan/struct';
|
||||||
- [Data flow](#data-flow)
|
|
||||||
|
const MyStruct =
|
||||||
|
new Struct({ littleEndian: true })
|
||||||
|
.int32('foo')
|
||||||
|
.int32('bar');
|
||||||
|
|
||||||
|
const value = await MyStruct.deserialize(someStream);
|
||||||
|
// TypeScript can infer type of the result object.
|
||||||
|
const { foo, bar } = value;
|
||||||
|
|
||||||
|
const buffer = MyStruct.serialize({ foo, bar });
|
||||||
|
```
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
|
@ -47,7 +59,7 @@ Basic usage requires [`Promise`][MDN_Promise], [`ArrayBuffer`][MDN_ArrayBuffer],
|
||||||
| **Safari** | 8 | |
|
| **Safari** | 8 | |
|
||||||
| **Node.js** | 0.12 | |
|
| **Node.js** | 0.12 | |
|
||||||
|
|
||||||
Usage of `uint64` requires [`BigInt`][MDN_BigInt] (**can't** be polyfilled), [`DataView#getBigUint64`][MDN_DataView_getBigUint64] and [`DataView#setBigUint64`][MDN_DataView_setBigUint64] (can be polyfilled).
|
Usage of `int64`/`uint64` requires [`BigInt`][MDN_BigInt] (**can't** be polyfilled), [`DataView#getBigUint64`][MDN_DataView_getBigUint64] and [`DataView#setBigUint64`][MDN_DataView_setBigUint64] (can be polyfilled).
|
||||||
|
|
||||||
[MDN_BigInt]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
|
[MDN_BigInt]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
|
||||||
[MDN_DataView_getBigUint64]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getBigUint64
|
[MDN_DataView_getBigUint64]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getBigUint64
|
||||||
|
@ -62,21 +74,6 @@ Usage of `uint64` requires [`BigInt`][MDN_BigInt] (**can't** be polyfilled), [`D
|
||||||
| **Safari** | 14 | Requires polyfills for `DataView#getBigUint64`/`DataView#setBigUint64` |
|
| **Safari** | 14 | Requires polyfills for `DataView#getBigUint64`/`DataView#setBigUint64` |
|
||||||
| **Node.js** | 10.4.0 | |
|
| **Node.js** | 10.4.0 | |
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import Struct from '@yume-chan/struct';
|
|
||||||
|
|
||||||
const MyStruct =
|
|
||||||
new Struct({ littleEndian: true })
|
|
||||||
.int32('foo')
|
|
||||||
.int32('bar');
|
|
||||||
|
|
||||||
const value = MyStruct.deserialize(someStream);
|
|
||||||
// TypeScript can infer type of the result object.
|
|
||||||
const { foo, bar } = value;
|
|
||||||
```
|
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
### `placeholder` method
|
### `placeholder` method
|
||||||
|
@ -89,20 +86,18 @@ export function placeholder<T>(): T {
|
||||||
|
|
||||||
Return a (fake) value of the given type.
|
Return a (fake) value of the given type.
|
||||||
|
|
||||||
Because TypeScript only supports supply all or none type arguments, this library allows all type parameters to be inferred from arguments.
|
Because TypeScript only supports supply all or none type arguments, this method allows all type parameters to be inferred from arguments.
|
||||||
|
|
||||||
This method can be used where an argument is only used to infer a type parameter.
|
|
||||||
|
|
||||||
**While all following APIs heavily rely on generic, DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
**While all following APIs heavily rely on generic, DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
||||||
|
|
||||||
### `Struct` constructor
|
### `Struct` constructor
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
export default class Struct<
|
class Struct<
|
||||||
TResult extends object = {},
|
TValue extends object = {},
|
||||||
TInit extends object = {},
|
TInit extends object = {},
|
||||||
TExtra extends object = {},
|
TExtra extends object = {},
|
||||||
TAfterParsed = undefined,
|
TPostDeserialized = undefined
|
||||||
> {
|
> {
|
||||||
public constructor(options: Partial<StructOptions> = StructDefaultOptions);
|
public constructor(options: Partial<StructOptions> = StructDefaultOptions);
|
||||||
}
|
}
|
||||||
|
@ -112,10 +107,10 @@ Creates a new structure definition.
|
||||||
|
|
||||||
**Generic Parameters**
|
**Generic Parameters**
|
||||||
|
|
||||||
1. `TResult`: Type of the result object.
|
1. `TValue`: Type of the Struct instance.
|
||||||
2. `TInit`: Type requirement to create such a structure. (Because some fields may implies other fields)
|
2. `TInit`: Type requirement to create such a structure. (May not be same as `TValue` because some fields can implies others)
|
||||||
3. `TExtra`: Type of extra fields.
|
3. `TExtra`: Type of extra fields.
|
||||||
4. `TAfterParsed`: State of the `afterParsed` function.
|
4. `TPostDeserialized`: State of the `postDeserialize` function.
|
||||||
|
|
||||||
**DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
**DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
||||||
|
|
||||||
|
@ -124,52 +119,90 @@ These are considered "internal state" of the `Struct` and will be taken care of
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
1. `options`:
|
1. `options`:
|
||||||
* `littleEndian:boolean = false`: Whether all multi-byte fields are [little-endian encoded][Wikipeida_Endianess].
|
* `littleEndian:boolean = false`: Whether all multi-byte fields in this struct are [little-endian encoded][Wikipeida_Endianess].
|
||||||
|
|
||||||
[Wikipeida_Endianess]: https://en.wikipedia.org/wiki/Endianness
|
[Wikipeida_Endianess]: https://en.wikipedia.org/wiki/Endianness
|
||||||
|
|
||||||
### `Struct#uint8`/`uint16`/`uint32`/`int32` methods
|
### `Struct#fields` method
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
public int32<
|
fields<
|
||||||
TName extends string,
|
TOther extends Struct<any, any, any, any>
|
||||||
TTypeScriptType = number
|
|
||||||
>(
|
>(
|
||||||
name: TName,
|
struct: TOther
|
||||||
options: FieldDescriptorBaseOptions = {},
|
|
||||||
_typescriptType?: TTypeScriptType,
|
|
||||||
): Struct<
|
): Struct<
|
||||||
TResult & Record<TName, TTypeScriptType>,
|
TValue & TOther['valueType'],
|
||||||
TInit & Record<TName, TTypeScriptType>,
|
TInit & TOther['initType'],
|
||||||
TExtra,
|
TExtra & TOther['extraType'],
|
||||||
TAfterParsed,
|
TPostDeserialized
|
||||||
>;
|
|
||||||
|
|
||||||
public uint32<
|
|
||||||
TName extends string,
|
|
||||||
TTypeScriptType = number
|
|
||||||
>(
|
|
||||||
name: TName,
|
|
||||||
options: {} = {},
|
|
||||||
_typescriptType?: TTypeScriptType,
|
|
||||||
): Struct<
|
|
||||||
TResult & Record<TName, TTypeScriptType>,
|
|
||||||
TInit & Record<TName, TTypeScriptType>,
|
|
||||||
TExtra,
|
|
||||||
TAfterParsed,
|
|
||||||
>;
|
>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Return a new `Struct` instance with an `int32`/`uint32` field appended to the end.
|
Merges (flats) another `Struct`'s fields and extra fields into this one.
|
||||||
|
|
||||||
The original `Struct` instance will not be changed.
|
**Examples**
|
||||||
|
|
||||||
TypeScript will also append a `name: TTypeScriptType` field into the result object and the init object.
|
1. Extending another `Struct`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const MyStructV1 =
|
||||||
|
new Struct()
|
||||||
|
.int32('field1');
|
||||||
|
|
||||||
|
const MyStructV2 =
|
||||||
|
new Struct()
|
||||||
|
.fields(MyStructV1)
|
||||||
|
.int32('field2');
|
||||||
|
|
||||||
|
const structV2 = await MyStructV2.deserialize(context);
|
||||||
|
structV2.field1; // number
|
||||||
|
structV2.field2; // number
|
||||||
|
// Same result, but serialize/deserialize order is reversed
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Also possible in any order
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const MyStructV1 =
|
||||||
|
new Struct()
|
||||||
|
.int32('field1');
|
||||||
|
|
||||||
|
const MyStructV2 =
|
||||||
|
new Struct()
|
||||||
|
.int32('field2')
|
||||||
|
.fields(MyStructV1);
|
||||||
|
|
||||||
|
const structV2 = await MyStructV2.deserialize(context);
|
||||||
|
structV2.field1; // number
|
||||||
|
structV2.field2; // number
|
||||||
|
// Fields are flatten
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Struct#uint8`/`uint16`/`int32`/`uint32` methods
|
||||||
|
|
||||||
|
```ts
|
||||||
|
int32<
|
||||||
|
TName extends PropertyKey,
|
||||||
|
TTypeScriptType = number
|
||||||
|
>(
|
||||||
|
name: TName,
|
||||||
|
_typescriptType?: TTypeScriptType
|
||||||
|
): Struct<
|
||||||
|
Evaluate<TValue & Record<TName, TTypeScriptType>>,
|
||||||
|
Evaluate<TInit & Record<TName, TTypeScriptType>>,
|
||||||
|
TExtra,
|
||||||
|
TPostDeserialized
|
||||||
|
>;
|
||||||
|
```
|
||||||
|
|
||||||
|
(All method signatures are same)
|
||||||
|
|
||||||
|
Appends an `uint8`/`uint16`/`int32`/`uint32` field to the `Struct`
|
||||||
|
|
||||||
**Generic Parameters**
|
**Generic Parameters**
|
||||||
|
|
||||||
1. `TName`: Literal type of the field's name.
|
1. `TName`: Literal type of the field's name.
|
||||||
2. `TTypeScriptType = number`: Type of the field in the result object.
|
2. `TTypeScriptType = number`: Type of the field in the result object. For example you can declare it as a number literal type, or some enum type.
|
||||||
|
|
||||||
**DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
**DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
||||||
|
|
||||||
|
@ -178,7 +211,6 @@ TypeScript will infer them from arguments. See examples below.
|
||||||
**Parameters**
|
**Parameters**
|
||||||
|
|
||||||
1. `name`: (Required) Field name. Should be a string literal to make types work.
|
1. `name`: (Required) Field name. Should be a string literal to make types work.
|
||||||
1. `options`: currently unused.
|
|
||||||
2. `_typescriptType`: Set field's type. See examples below.
|
2. `_typescriptType`: Set field's type. See examples below.
|
||||||
|
|
||||||
**Note**
|
**Note**
|
||||||
|
@ -226,67 +258,62 @@ But obviously, it's a bad idea.
|
||||||
struct.create({ foo: MyEnum.a, bar: MyEnum.b }); // ok
|
struct.create({ foo: MyEnum.a, bar: MyEnum.b }); // ok
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Create a new struct by extending existing one
|
### `Struct#int64`/`uint64` methods
|
||||||
|
|
||||||
```ts
|
|
||||||
const struct1 = new Struct()
|
|
||||||
.int32('foo');
|
|
||||||
|
|
||||||
const struct2 = struct1
|
|
||||||
.int32('bar');
|
|
||||||
|
|
||||||
assert(struct2 !== struct1);
|
|
||||||
// `struct1` will not be changed
|
|
||||||
```
|
|
||||||
|
|
||||||
### `Struct#uint64`/`int64` method
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
public uint64<
|
int64<
|
||||||
TName extends string,
|
TName extends PropertyKey,
|
||||||
TTypeScriptType = bigint
|
TTypeScriptType = bigint
|
||||||
>(
|
>(
|
||||||
name: TName,
|
name: TName,
|
||||||
options: FieldDescriptorBaseOptions = {},
|
_typescriptType?: TTypeScriptType
|
||||||
_typescriptType?: TTypeScriptType,
|
|
||||||
): Struct<
|
): Struct<
|
||||||
TResult & Record<TName, TTypeScriptType>,
|
Evaluate<TValue & Record<TName, TTypeScriptType>>,
|
||||||
TInit & Record<TName, TTypeScriptType>,
|
Evaluate<TInit & Record<TName, TTypeScriptType>>,
|
||||||
TExtra,
|
TExtra,
|
||||||
TAfterParsed,
|
TPostDeserialized
|
||||||
>;
|
>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Return a new `Struct` instance with an `uint64` field appended to the end.
|
Appends an `int64`/`uint64` field to the `Struct`.
|
||||||
|
|
||||||
The original `Struct` instance will not be changed.
|
Requires native `BigInt` support of runtime. See [compatibility](#compatibility).
|
||||||
|
|
||||||
TypeScript will also append a `name: TTypeScriptType` field into the result object and the init object.
|
|
||||||
|
|
||||||
Require native `BigInt` support in runtime. See [compatibility](#compatibility).
|
|
||||||
|
|
||||||
### `extra` function
|
### `extra` function
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
public extra<TValue extends object>(
|
extra<
|
||||||
value: TValue & ThisType<WithBackingField<Overwrite<Overwrite<TExtra, TValue>, TResult>>>
|
T extends Record<
|
||||||
|
Exclude<
|
||||||
|
keyof T,
|
||||||
|
Exclude<
|
||||||
|
keyof T,
|
||||||
|
keyof TValue
|
||||||
|
>
|
||||||
|
>,
|
||||||
|
never
|
||||||
|
>
|
||||||
|
>(
|
||||||
|
value: T & ThisType<Overwrite<Overwrite<TExtra, T>, TValue>>
|
||||||
): Struct<
|
): Struct<
|
||||||
TResult,
|
TValue,
|
||||||
TInit,
|
TInit,
|
||||||
Overwrite<TExtra, TValue>,
|
Overwrite<TExtra, T>,
|
||||||
TAfterParsed
|
TPostDeserialized
|
||||||
>;
|
>;
|
||||||
```
|
```
|
||||||
|
|
||||||
Return a new `Struct` instance adding some extra fields.
|
Adds some extra fields into every Struct instance.
|
||||||
|
|
||||||
The original `Struct` instance will not be changed.
|
Extra fields will not affect serialize or deserialize process.
|
||||||
|
|
||||||
TypeScript will also append all extra fields into the result object (if not already exited).
|
Multiple calls to `extra` will merge all values together.
|
||||||
|
|
||||||
|
See examples below.
|
||||||
|
|
||||||
**Generic Parameters**
|
**Generic Parameters**
|
||||||
|
|
||||||
1. `TValue`: Type of the extra fields.
|
1. `T`: Type of the extra fields. The scary looking generic constraint is used to forbid overwriting any already existed fields.
|
||||||
|
|
||||||
**DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
**DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
||||||
|
|
||||||
|
@ -299,8 +326,6 @@ TypeScript will infer them from arguments. See examples below.
|
||||||
**Note**
|
**Note**
|
||||||
|
|
||||||
1. If the current `Struct` already has some extra fields, it will be merged with `value`, with `value` taking precedence.
|
1. If the current `Struct` already has some extra fields, it will be merged with `value`, with `value` taking precedence.
|
||||||
2. Extra fields will not be serialized.
|
|
||||||
3. Extra fields will be ignored if it has the same name with some defined fields.
|
|
||||||
|
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
|
@ -343,31 +368,30 @@ TypeScript will infer them from arguments. See examples below.
|
||||||
value.logBar();
|
value.logBar();
|
||||||
```
|
```
|
||||||
|
|
||||||
### `afterParsed` method
|
### `postDeserialize` method
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
public afterParsed(
|
postDeserialize(callback: StructPostDeserialized<TValue, never>): Struct<TValue, TInit, TExtra, never>;
|
||||||
callback?: StructAfterParsed<TResult, void>
|
postDeserialize(callback?: StructPostDeserialized<TValue, void>): Struct<TValue, TInit, TExtra, undefined>;
|
||||||
): Struct<TResult, TInit, TExtra, undefined>;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Return a new `Struct` instance, registering (or replacing) a custom callback to be run after deserialized.
|
Registers (or replaces) a custom callback to be run after deserialized.
|
||||||
|
|
||||||
The original `Struct` instance will not be changed.
|
A callback returning `never` (always throw an error) will also change the return type of `deserialize` to `never`.
|
||||||
|
|
||||||
|
A callback returning `void` means it modify the result object in-place (or doesn't modify it at all), so `deserialize` will still return the result object.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
public afterParsed<TAfterParsed>(
|
postDeserialize<TPostSerialize>(callback?: StructPostDeserialized<TValue, TPostSerialize>): Struct<TValue, TInit, TExtra, TPostSerialize>;
|
||||||
callback?: StructAfterParsed<TResult, TAfterParsed>
|
|
||||||
): Struct<TResult, TInit, TExtra, TAfterParsed>;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Return a new `Struct` instance, registering (or replacing) a custom callback to be run after deserialized, and replacing the result object with the returned value.
|
Registers (or replaces) a custom callback to be run after deserialized.
|
||||||
|
|
||||||
The original `Struct` instance will not be changed.
|
A callback returning anything other than `undefined` will `deserialize` to return that object instead.
|
||||||
|
|
||||||
**Generic Parameters**
|
**Generic Parameters**
|
||||||
|
|
||||||
1. `TAfterParsed`: Type of the new result object.
|
1. `TPostSerialize`: Type of the new result object.
|
||||||
|
|
||||||
**DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
**DO NOT PASS ANY GENERIC ARGUMENTS MANUALLY!**
|
||||||
|
|
||||||
|
@ -389,7 +413,7 @@ TypeScript will infer them from arguments. See examples below.
|
||||||
const struct = new Struct()
|
const struct = new Struct()
|
||||||
.int32('messageLength')
|
.int32('messageLength')
|
||||||
.string('message', { lengthField: 'messageLength' })
|
.string('message', { lengthField: 'messageLength' })
|
||||||
.afterParsed(value => {
|
.postDeserialize(value => {
|
||||||
throw new Error(value.message);
|
throw new Error(value.message);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
@ -400,28 +424,12 @@ TypeScript will infer them from arguments. See examples below.
|
||||||
// I think this one doesn't need any code example
|
// I think this one doesn't need any code example
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Clear a previously set `afterParsed` callback
|
3. Replace result object
|
||||||
|
|
||||||
```ts
|
|
||||||
// Most used with extending structures
|
|
||||||
|
|
||||||
const struct1 = new Struct()
|
|
||||||
.int32('foo')
|
|
||||||
.afterParsed(value => {
|
|
||||||
// do something
|
|
||||||
});
|
|
||||||
|
|
||||||
const struct2 = struct1
|
|
||||||
.afterParsed() // don't inherit `struct1`'s `afterParsed`
|
|
||||||
.int32('bar');
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Replace result object
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
const struct1 = new Struct()
|
const struct1 = new Struct()
|
||||||
.int32('foo')
|
.int32('foo')
|
||||||
.afterParsed(value => {
|
.postDeserialize(value => {
|
||||||
return {
|
return {
|
||||||
bar: value.foo,
|
bar: value.foo,
|
||||||
};
|
};
|
||||||
|
@ -434,14 +442,12 @@ TypeScript will infer them from arguments. See examples below.
|
||||||
### `deserialize` method
|
### `deserialize` method
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
public async deserialize(
|
deserialize(context: StructDeserializationContext): Promise<TPostDeserialized extends undefined ? Overwrite<TExtra, TValue> : TPostDeserialized>;
|
||||||
context: StructDeserializationContext
|
|
||||||
): Promise<TAfterParsed extends undefined ? Overwrite<TExtra, TResult> : TAfterParsed>;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Deserialize one structure from the `context`.
|
Deserialize a Struct instance from `context`.
|
||||||
|
|
||||||
As you can see, if your `afterParsed` callback returns a value, that value will be returned by `deserialize`. Or the result object will be returned.
|
As you can see, if your `postDeserialize` callback returns something, that value will be returned by `deserialize`.
|
||||||
|
|
||||||
### `serialize` method
|
### `serialize` method
|
||||||
|
|
||||||
|
@ -449,214 +455,97 @@ As you can see, if your `afterParsed` callback returns a value, that value will
|
||||||
public serialize(init: TInit, context: StructSerializationContext): ArrayBuffer;
|
public serialize(init: TInit, context: StructSerializationContext): ArrayBuffer;
|
||||||
```
|
```
|
||||||
|
|
||||||
Serialize a value as the structure.
|
Serialize a Struct instance into an `ArrayBuffer`.
|
||||||
|
|
||||||
## Extend types
|
## Custom types
|
||||||
|
|
||||||
The library also supports adding custom types.
|
It also supports adding custom types.
|
||||||
|
|
||||||
There are two concepts around the type plugin system.
|
### `Struct#field` method
|
||||||
|
|
||||||
### Backing Field
|
|
||||||
|
|
||||||
The result object has a hidden backing field, containing implementation details of each field.
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { getBackingField, setBackingField } from '@yume-chan/struct';
|
field<
|
||||||
|
TName extends PropertyKey,
|
||||||
const value = getBackingField<number>(resultObject, 'foo');
|
TDefinition extends FieldDefinition<any, any, any>
|
||||||
setBackingField(resultObject, 'foo', value);
|
>(
|
||||||
|
name: TName,
|
||||||
|
definition: TDefinition
|
||||||
|
): Struct<
|
||||||
|
Evaluate<TValue & Record<TFieldName, TDefinition['valueType']>>,
|
||||||
|
Evaluate<Omit<TInit, TDefinition['removeFields']> & Record<TFieldName, TDefinition['valueType']>>,
|
||||||
|
TExtra,
|
||||||
|
TPostDeserialized
|
||||||
|
>;
|
||||||
```
|
```
|
||||||
|
|
||||||
It's possible to access other fields' data if you know the type. But it's not recommended to modify them.
|
Appends a `FieldDefinition` to the `Struct.
|
||||||
|
|
||||||
### `FieldDescriptorBase` interface
|
All above built-in methods are all alias to this method.
|
||||||
|
|
||||||
This interface describes one field, and will be stored in `Struct` class.
|
### FieldDefinition
|
||||||
|
|
||||||
**Generic Parameters**
|
|
||||||
|
|
||||||
* `TName extends string = string`: Name of the field. Although `FieldDescriptorBase` doesn't need it to be generic, derived types will need it. So marking this way helps TypeScript infer the type.
|
|
||||||
* `TResultObject = {}`: Type that will be merged into the result object (`TResult`). Any key that has `never` type will be removed.
|
|
||||||
* `TInitObject = {}`: Type that will be merged into the init object (`TInit`). Any key that has `never` type will be removed. Normally you only need to add the current field into `TInit`, but sometimes one field will imply other fields, so you may want to also remove those implied fields from `TInit`.
|
|
||||||
* `TOptions extends FieldDescriptorBaseOptions = FieldDescriptorBaseOptions`: Type of the `options`. currently `FieldDescriptorBaseOptions` is empty but maybe something will happen later.
|
|
||||||
|
|
||||||
When declaring your own field descriptor, you need to extend `FieldDescriptorBase`, and correctly pass all generic arguments.
|
|
||||||
|
|
||||||
**Fields**
|
|
||||||
|
|
||||||
* `type: string`: The unique identifier of the type.
|
|
||||||
* `name: TName`: Field name in the result object.
|
|
||||||
* `options: TOptions`: You can store your options here.
|
|
||||||
* `resultObject?: TResultObject`: Make it possible for TypeScript to infer `TResultObject`. DO NOT TOUCH.
|
|
||||||
* `initObject?: TInitObject`: Make it possible for TypeScript to infer `TInitObject`. DO NOT TOUCH.
|
|
||||||
|
|
||||||
When declaring your own field descriptor, you can also add more fields to hold your data.
|
|
||||||
|
|
||||||
### `field` method
|
|
||||||
|
|
||||||
`Struct` class also has a `field` method to add a custom field descriptor.
|
|
||||||
|
|
||||||
Due to the limitation of TypeScript, you can't extend `Struct` class while keeping the fluent style API working.
|
|
||||||
|
|
||||||
So for type safety you should provide a function to generate your own field descriptor, then let the user call the `field` method.
|
|
||||||
|
|
||||||
### `FieldTypeDefinition` interface
|
|
||||||
|
|
||||||
This interface defines how to serialize and deserialize a type. You need to implement this interface for your type and register it.
|
|
||||||
|
|
||||||
**Generic Parameters**
|
|
||||||
|
|
||||||
* `TDescriptor extends FieldDescriptorBase = FieldDescriptorBase`: Type of the field descriptor. Just pass in your own field descriptor type.
|
|
||||||
|
|
||||||
**Fields**
|
|
||||||
|
|
||||||
* `type: string`: The unique identifier of the type. Make sure it's same as in `FieldDescriptor`.
|
|
||||||
|
|
||||||
#### `deserialize` method
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
deserialize(options: {
|
abstract class FieldDefinition<TOptions = void, TValueType = unknown, TRemoveFields = never> {
|
||||||
context: StructDeserializationContext;
|
readonly options: TOptions;
|
||||||
field: TDescriptor;
|
|
||||||
object: any;
|
|
||||||
options: StructOptions;
|
|
||||||
}): Promise<void>;
|
|
||||||
```
|
|
||||||
|
|
||||||
Defines how to deserialize the field.
|
constructor(options: TOptions);
|
||||||
|
|
||||||
You should `read` data from the `context` according to your `field` descriptor, and set appropriate values onto `object` ("appropriate" means "same as `TDescriptor`'s `TResultObject`").
|
|
||||||
|
|
||||||
If you also defined `initialize` method, the result data shape of `object` should be same as the result of `initialize`.
|
|
||||||
|
|
||||||
#### `getSize` method
|
|
||||||
|
|
||||||
```ts
|
|
||||||
getSize(options: {
|
|
||||||
field: TDescriptor;
|
|
||||||
options: StructOptions;
|
|
||||||
}): number;
|
|
||||||
```
|
|
||||||
|
|
||||||
Get the size (in bytes) of the field.
|
|
||||||
|
|
||||||
If the size is (partially or fully) dynamic, returns the minimal size.
|
|
||||||
|
|
||||||
It's just a hint for how much data should be ready before parsing, not that important.
|
|
||||||
|
|
||||||
#### `getDynamicSize` method
|
|
||||||
|
|
||||||
```ts
|
|
||||||
getDynamicSize?(options: {
|
|
||||||
context: StructSerializationContext,
|
|
||||||
field: TDescriptor,
|
|
||||||
object: any,
|
|
||||||
options: StructOptions,
|
|
||||||
}): number;
|
|
||||||
```
|
|
||||||
|
|
||||||
Similar to `getSize`, but also has access to `object` and `context` so the actual size can be calculated.
|
|
||||||
|
|
||||||
This method will be called just before `serialize`, so you can also prepare your field to be serialized in it.
|
|
||||||
|
|
||||||
You can also modify `object` to store your lazily evaluated values so next serialization can reuse them. But make sure you have also defined a setter in `initialize` method to invalidate the cache.
|
|
||||||
|
|
||||||
#### `initialize` method
|
|
||||||
|
|
||||||
```ts
|
|
||||||
initialize?(options: {
|
|
||||||
context: StructSerializationContext;
|
|
||||||
field: TDescriptor;
|
|
||||||
init: any;
|
|
||||||
object: any;
|
|
||||||
options: StructOptions;
|
|
||||||
}): void;
|
|
||||||
```
|
|
||||||
|
|
||||||
When creating or serializing an object, you can fine tune how to map fields from `init` object onto the result `object`.
|
|
||||||
|
|
||||||
You can modify the `object` as your wish, but a common practice is storing actual data on the backing field and define getter/setter on `object` to access them. Because fields may be overwritten by `extra` fields, where data on the backing field is still useful.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
initialize({ field, init, object }) {
|
|
||||||
object[BackingField][field.name] = {
|
|
||||||
value: init[field.name],
|
|
||||||
...extraData,
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.defineProperty(object, field.name, {
|
|
||||||
configurable: true,
|
|
||||||
enumerable: true,
|
|
||||||
get() { return object[BackingField][field.name].value; }
|
|
||||||
set(value) {
|
|
||||||
object[BackingField][field.name].value = value;
|
|
||||||
// set some other data
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If omitted, value from `init` will be set into the backing field and a pair of simple getter/setter will be defined on `object`.
|
A `FieldDefinition` defines its type, size, etc.
|
||||||
|
|
||||||
Some possible usages:
|
It's an `abstract` class, means it lacks some method implementations, so it shouldn't be constructed.
|
||||||
|
|
||||||
1. Do some calculations and then set it onto `object`.
|
To create a custom type, one should create its own derived classes of `FieldDefinition` and `FieldRuntimeValue`.
|
||||||
2. Define getter/setter onto `object` to intercept read/write.
|
|
||||||
3. Maybe one field implies others, so you can define multiple fields onto `object` for a single `field`.
|
|
||||||
|
|
||||||
#### `serialize` method
|
The custom `FieldDefinition` then can be passed to `Struct#field` method to append such a custom type field.
|
||||||
|
|
||||||
|
### `FieldDefinition#getSize` method
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
serialize(options: {
|
abstract getSize(): number;
|
||||||
context: StructSerializationContext;
|
|
||||||
dataView: DataView;
|
|
||||||
field: TDescriptor;
|
|
||||||
object: any;
|
|
||||||
offset: number;
|
|
||||||
options: StructOptions;
|
|
||||||
}): void;
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Defines how to serialize the field.
|
Returns the size (or minimal size if it's dynamic) of this field.
|
||||||
|
|
||||||
You should serialize your `field`'s value on `object`, and write it to `dataView` at `offset`.
|
Actual size should been returned from `FieldRuntimeValue#getSize`
|
||||||
|
|
||||||
You must not write more data than `getSize`/`getDynamicSize` returned. Or an Error will be thrown.
|
### `FieldDefinition#deserialize` method
|
||||||
|
|
||||||
### Array type
|
```ts
|
||||||
|
abstract deserialize(
|
||||||
|
options: Readonly<StructOptions>,
|
||||||
|
context: StructDeserializationContext,
|
||||||
|
object: any,
|
||||||
|
): ValueOrPromise<FieldRuntimeValue<FieldDefinition<TOptions, TValueType, TRemoveInitFields>>>;
|
||||||
|
```
|
||||||
|
|
||||||
Instead of true "Array", the current array types (`arraybuffer` and `string`) are more like buffers.
|
Defines how to deserialize a value from `context`. Can also return a `Promise`.
|
||||||
|
|
||||||
### `registerFieldTypeDefinition` method
|
Usually implementations should be:
|
||||||
|
|
||||||
This library exports the `registerFieldTypeDefinition` method to register your custom type definitions.
|
1. Some how parse the value from `context`
|
||||||
|
2. Pass the value into `FieldDefinition#createValue`
|
||||||
|
|
||||||
Pass the `undefined as unknown as YourTypeDescriptor` as the first argument to make TypeScript infers the type.
|
Sometimes, some metadata is present when deserializing, but need to be calculated when serializing, for example a UTF-8 encoded string may have different length between itself (character count) and serialized form (byte length). So `deserialize` and save those metadata on the `FieldRuntimeValue` instance.
|
||||||
|
|
||||||
### Data flow
|
### `FieldDefinition#createValue` method
|
||||||
|
|
||||||
Here are lists of methods calling order to help you understand how this library works.
|
```ts
|
||||||
|
abstract createValue(
|
||||||
|
options: Readonly<StructOptions>,
|
||||||
|
context: StructSerializationContext,
|
||||||
|
object: any,
|
||||||
|
value: TValueType,
|
||||||
|
): FieldRuntimeValue<FieldDefinition<TOptions, TValueType, TRemoveInitFields>>;
|
||||||
|
```
|
||||||
|
|
||||||
| Method | Description |
|
Similar to `deserialize`, creates a `FieldRuntimeValue` for this instance.
|
||||||
| ----------------------------- | -------------------------- |
|
|
||||||
| `Struct#field` | Add a field descriptor |
|
|
||||||
| `FieldTypeDefinition#getSize` | Add up struct's total size |
|
|
||||||
|
|
||||||
| Method | Description |
|
The difference is `createValue` will be called when a init value was provided to create a Struct instance.
|
||||||
| --------------------------------- | ------------------------------------ |
|
|
||||||
| `Struct#deserialize` | Start deserializing from a `context` |
|
|
||||||
| `FieldTypeDefinition#deserialize` | Deserialize each field |
|
|
||||||
|
|
||||||
| Method | Description |
|
### FieldRuntimeValue
|
||||||
| -------------------------------- | ---------------------------------------------------- |
|
|
||||||
| `Struct#create` | Validate and create a value of the current structure |
|
|
||||||
| `FieldTypeDefinition#initialize` | Initialize each field |
|
|
||||||
|
|
||||||
| Method | Description |
|
One `FieldDefinition` instance represents one field declaration, and one `FieldRuntimeValue` instance represents one value.
|
||||||
| ------------------------------------ | ---------------------------------------------------- |
|
|
||||||
| `Struct#serialize` | Serialize a value into a buffer |
|
It defines how to get, set, and serialize a value.
|
||||||
| `Struct#create` | Validate and create a value of the current structure |
|
|
||||||
| `FieldTypeDefinition#initialize` | Initialize each field |
|
|
||||||
| `FieldTypeDefinition#getDynamicSize` | Get actual sizes of each field |
|
|
||||||
| `FieldTypeDefinition#serialize` | Write each field into the allocated buffer |
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ export interface StructDeserializationContext extends StructSerializationContext
|
||||||
|
|
||||||
export interface StructOptions {
|
export interface StructOptions {
|
||||||
/**
|
/**
|
||||||
* Whether multi-byte fields in this struct are in little endian
|
* Whether all multi-byte fields in this struct are little-endian encoded.
|
||||||
*
|
*
|
||||||
* Default to `false`
|
* Default to `false`
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import type { StructOptions, StructSerializationContext } from './context';
|
import type { StructDeserializationContext, StructOptions, StructSerializationContext } from './context';
|
||||||
import type { FieldRuntimeValue } from './runtime-value';
|
import type { FieldRuntimeValue } from './runtime-value';
|
||||||
|
|
||||||
|
type ValueOrPromise<T> = T | Promise<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A field definition is a bridge between its type and its runtime value.
|
* A field definition is a bridge between its type and its runtime value.
|
||||||
*
|
*
|
||||||
|
@ -14,44 +16,54 @@ import type { FieldRuntimeValue } from './runtime-value';
|
||||||
*
|
*
|
||||||
* @template TOptions TypeScript type of this definition's `options`.
|
* @template TOptions TypeScript type of this definition's `options`.
|
||||||
* @template TValueType TypeScript type of this field.
|
* @template TValueType TypeScript type of this field.
|
||||||
* @template TRemoveFields Optional remove keys from current `Struct`. Should be a union of string literal types.
|
* @template TRemoveInitFields Optional remove some field from the `TInit` type. Should be a union of string literal types.
|
||||||
*/
|
*/
|
||||||
export abstract class FieldDefinition<
|
export abstract class FieldDefinition<
|
||||||
TOptions = void,
|
TOptions = void,
|
||||||
TValueType = unknown,
|
TValueType = unknown,
|
||||||
TRemoveFields = never,
|
TRemoveInitFields = never,
|
||||||
> {
|
> {
|
||||||
public readonly options: TOptions;
|
public readonly options: TOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When `T` is a type initiated `FieldDefinition`,
|
* When `T` is a type initiated `FieldDefinition`,
|
||||||
* use `T['valueType']` to retrieve its `TValueType` type parameter
|
* use `T['valueType']` to retrieve its `TValueType` type parameter.
|
||||||
*/
|
*/
|
||||||
public readonly valueType!: TValueType;
|
public readonly valueType!: TValueType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When `T` is a type initiated `FieldDefinition`,
|
* When `T` is a type initiated `FieldDefinition`,
|
||||||
* use `T['removeFields']` to retrieve its `TRemoveFields` type parameter .
|
* use `T['removeInitFields']` to retrieve its `TRemoveInitFields` type parameter.
|
||||||
*/
|
*/
|
||||||
public readonly removeFields!: TRemoveFields;
|
public readonly removeInitFields!: TRemoveInitFields;
|
||||||
|
|
||||||
public constructor(options: TOptions) {
|
public constructor(options: TOptions) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When implemented in derived classes, returns the static size (or smallest size) of this field.
|
* When implemented in derived classes, returns the size (or minimal size if it's dynamic) of this field.
|
||||||
*
|
*
|
||||||
* Actual size can be retrieved from `FieldRuntimeValue#getSize`
|
* Actual size can be retrieved from `FieldRuntimeValue#getSize`
|
||||||
*/
|
*/
|
||||||
public abstract getSize(): number;
|
public abstract getSize(): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When implemented in derived classes, creates a `FieldRuntimeValue` for the current field definition.
|
* When implemented in derived classes, creates a `FieldRuntimeValue` by parsing the `context`.
|
||||||
|
*/
|
||||||
|
public abstract deserialize(
|
||||||
|
options: Readonly<StructOptions>,
|
||||||
|
context: StructDeserializationContext,
|
||||||
|
object: any,
|
||||||
|
): ValueOrPromise<FieldRuntimeValue<FieldDefinition<TOptions, TValueType, TRemoveInitFields>>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When implemented in derived classes, creates a `FieldRuntimeValue` from a given `value`.
|
||||||
*/
|
*/
|
||||||
public abstract createValue(
|
public abstract createValue(
|
||||||
options: Readonly<StructOptions>,
|
options: Readonly<StructOptions>,
|
||||||
context: StructSerializationContext,
|
context: StructSerializationContext,
|
||||||
object: any
|
object: any,
|
||||||
): FieldRuntimeValue;
|
value: TValueType,
|
||||||
|
): FieldRuntimeValue<FieldDefinition<TOptions, TValueType, TRemoveInitFields>>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { StructDeserializationContext, StructOptions, StructSerializationContext } from './context';
|
import type { StructOptions, StructSerializationContext } from './context';
|
||||||
import type { FieldDefinition } from './definition';
|
import type { FieldDefinition } from './definition';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,23 +22,22 @@ export abstract class FieldRuntimeValue<
|
||||||
/** Gets the associated `Struct` instance */
|
/** Gets the associated `Struct` instance */
|
||||||
public readonly object: any;
|
public readonly object: any;
|
||||||
|
|
||||||
|
protected value: TDefinition['valueType'];
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
definition: TDefinition,
|
definition: TDefinition,
|
||||||
options: Readonly<StructOptions>,
|
options: Readonly<StructOptions>,
|
||||||
context: StructSerializationContext,
|
context: StructSerializationContext,
|
||||||
object: any,
|
object: any,
|
||||||
|
value: TDefinition['valueType'],
|
||||||
) {
|
) {
|
||||||
this.definition = definition;
|
this.definition = definition;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.object = object;
|
this.object = object;
|
||||||
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** When implemented in derived classes, deserialize this field from the specified `context` */
|
|
||||||
public abstract deserialize(
|
|
||||||
context: StructDeserializationContext
|
|
||||||
): void | Promise<void>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the actual size of this field. By default, the return value of its `definition.getSize()`
|
* Gets the actual size of this field. By default, the return value of its `definition.getSize()`
|
||||||
*
|
*
|
||||||
|
@ -51,12 +50,16 @@ export abstract class FieldRuntimeValue<
|
||||||
/**
|
/**
|
||||||
* When implemented in derived classes, returns the current value of this field
|
* When implemented in derived classes, returns the current value of this field
|
||||||
*/
|
*/
|
||||||
public abstract get(): unknown;
|
public get(): TDefinition['valueType'] {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When implemented in derived classes, update the current value of this field
|
* When implemented in derived classes, update the current value of this field
|
||||||
*/
|
*/
|
||||||
public abstract set(value: unknown): void;
|
public set(value: TDefinition['valueType']): void {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When implemented in derived classes, serializes this field into `dataView` at `offset`
|
* When implemented in derived classes, serializes this field into `dataView` at `offset`
|
||||||
|
|
|
@ -31,7 +31,7 @@ type AddFieldDescriptor<
|
||||||
Evaluate<TValue & Record<TFieldName, TDefinition['valueType']>>,
|
Evaluate<TValue & Record<TFieldName, TDefinition['valueType']>>,
|
||||||
// There is no `Evaluate` here, because otherwise the type of a `Struct` with many fields
|
// There is no `Evaluate` here, because otherwise the type of a `Struct` with many fields
|
||||||
// can become too complex for TypeScript to compute
|
// can become too complex for TypeScript to compute
|
||||||
Evaluate<Omit<TInit, TDefinition['removeFields']> & Record<TFieldName, TDefinition['valueType']>>,
|
Evaluate<Omit<TInit, TDefinition['removeInitFields']> & Record<TFieldName, TDefinition['valueType']>>,
|
||||||
TExtra,
|
TExtra,
|
||||||
TPostDeserialized
|
TPostDeserialized
|
||||||
>>;
|
>>;
|
||||||
|
@ -171,7 +171,7 @@ export default class Struct<
|
||||||
|
|
||||||
private _size = 0;
|
private _size = 0;
|
||||||
/**
|
/**
|
||||||
* Get the static size (exclude fields that can change size at runtime)
|
* Gets the static size (exclude fields that can change size at runtime)
|
||||||
*/
|
*/
|
||||||
public get size() { return this._size; }
|
public get size() { return this._size; }
|
||||||
|
|
||||||
|
@ -185,6 +185,9 @@ export default class Struct<
|
||||||
this.options = { ...StructDefaultOptions, ...options };
|
this.options = { ...StructDefaultOptions, ...options };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a `FieldDefinition` to the `Struct
|
||||||
|
*/
|
||||||
public field<
|
public field<
|
||||||
TName extends PropertyKey,
|
TName extends PropertyKey,
|
||||||
TDefinition extends FieldDefinition<any, any, any>
|
TDefinition extends FieldDefinition<any, any, any>
|
||||||
|
@ -208,6 +211,9 @@ export default class Struct<
|
||||||
return this as any;
|
return this as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges (flats) another `Struct`'s fields and extra fields into this one.
|
||||||
|
*/
|
||||||
public fields<TOther extends Struct<any, any, any, any>>(
|
public fields<TOther extends Struct<any, any, any, any>>(
|
||||||
struct: TOther
|
struct: TOther
|
||||||
): Struct<
|
): Struct<
|
||||||
|
@ -239,6 +245,9 @@ export default class Struct<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends an `uint8` field to the `Struct`
|
||||||
|
*/
|
||||||
public uint8<
|
public uint8<
|
||||||
TName extends PropertyKey,
|
TName extends PropertyKey,
|
||||||
TTypeScriptType = (typeof NumberFieldType)['Uint8']['valueType']
|
TTypeScriptType = (typeof NumberFieldType)['Uint8']['valueType']
|
||||||
|
@ -253,6 +262,9 @@ export default class Struct<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends an `uint16` field to the `Struct`
|
||||||
|
*/
|
||||||
public uint16<
|
public uint16<
|
||||||
TName extends PropertyKey,
|
TName extends PropertyKey,
|
||||||
TTypeScriptType = (typeof NumberFieldType)['Uint16']['valueType']
|
TTypeScriptType = (typeof NumberFieldType)['Uint16']['valueType']
|
||||||
|
@ -267,6 +279,9 @@ export default class Struct<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends an `int32` field to the `Struct`
|
||||||
|
*/
|
||||||
public int32<
|
public int32<
|
||||||
TName extends PropertyKey,
|
TName extends PropertyKey,
|
||||||
TTypeScriptType = (typeof NumberFieldType)['Int32']['valueType']
|
TTypeScriptType = (typeof NumberFieldType)['Int32']['valueType']
|
||||||
|
@ -281,6 +296,9 @@ export default class Struct<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends an `uint32` field to the `Struct`
|
||||||
|
*/
|
||||||
public uint32<
|
public uint32<
|
||||||
TName extends PropertyKey,
|
TName extends PropertyKey,
|
||||||
TTypeScriptType = (typeof NumberFieldType)['Uint32']['valueType']
|
TTypeScriptType = (typeof NumberFieldType)['Uint32']['valueType']
|
||||||
|
@ -295,6 +313,11 @@ export default class Struct<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends an `int64` field to the `Struct`
|
||||||
|
*
|
||||||
|
* Requires native `BigInt` support
|
||||||
|
*/
|
||||||
public int64<
|
public int64<
|
||||||
TName extends PropertyKey,
|
TName extends PropertyKey,
|
||||||
TTypeScriptType = (typeof NumberFieldType)['Int64']['valueType']
|
TTypeScriptType = (typeof NumberFieldType)['Int64']['valueType']
|
||||||
|
@ -309,6 +332,11 @@ export default class Struct<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends an `uint64` field to the `Struct`
|
||||||
|
*
|
||||||
|
* Requires native `BigInt` support
|
||||||
|
*/
|
||||||
public uint64<
|
public uint64<
|
||||||
TName extends PropertyKey,
|
TName extends PropertyKey,
|
||||||
TTypeScriptType = (typeof NumberFieldType)['Uint64']['valueType']
|
TTypeScriptType = (typeof NumberFieldType)['Uint64']['valueType']
|
||||||
|
@ -380,6 +408,13 @@ export default class Struct<
|
||||||
return this.arrayBufferLike(name, StringFieldType.instance, options);
|
return this.arrayBufferLike(name, StringFieldType.instance, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds some extra fields into every Struct instance.
|
||||||
|
*
|
||||||
|
* Extra fields will not affect serialize or deserialize process.
|
||||||
|
*
|
||||||
|
* Multiple calls to `extra` will merge all values together.
|
||||||
|
*/
|
||||||
public extra<T extends Record<
|
public extra<T extends Record<
|
||||||
// This trick disallows any keys that are already in `TValue`
|
// This trick disallows any keys that are already in `TValue`
|
||||||
Exclude<
|
Exclude<
|
||||||
|
@ -400,14 +435,29 @@ export default class Struct<
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Registers (or replaces) a custom callback to be run after deserialized.
|
||||||
*
|
*
|
||||||
|
* A callback returning `never` (always throw an error)
|
||||||
|
* will also change the return type of `deserialize` to `never`.
|
||||||
*/
|
*/
|
||||||
public postDeserialize(
|
public postDeserialize(
|
||||||
callback: StructPostDeserialized<TValue, never>
|
callback: StructPostDeserialized<TValue, never>
|
||||||
): Struct<TValue, TInit, TExtra, never>;
|
): Struct<TValue, TInit, TExtra, never>;
|
||||||
|
/**
|
||||||
|
* Registers (or replaces) a custom callback to be run after deserialized.
|
||||||
|
*
|
||||||
|
* A callback returning `void` means it modify the result object in-place
|
||||||
|
* (or doesn't modify it at all), so `deserialize` will still return the result object.
|
||||||
|
*/
|
||||||
public postDeserialize(
|
public postDeserialize(
|
||||||
callback?: StructPostDeserialized<TValue, void>
|
callback?: StructPostDeserialized<TValue, void>
|
||||||
): Struct<TValue, TInit, TExtra, undefined>;
|
): Struct<TValue, TInit, TExtra, undefined>;
|
||||||
|
/**
|
||||||
|
* Registers (or replaces) a custom callback to be run after deserialized.
|
||||||
|
*
|
||||||
|
* A callback returning anything other than `undefined`
|
||||||
|
* will `deserialize` to return that object instead.
|
||||||
|
*/
|
||||||
public postDeserialize<TPostSerialize>(
|
public postDeserialize<TPostSerialize>(
|
||||||
callback?: StructPostDeserialized<TValue, TPostSerialize>
|
callback?: StructPostDeserialized<TValue, TPostSerialize>
|
||||||
): Struct<TValue, TInit, TExtra, TPostSerialize>;
|
): Struct<TValue, TInit, TExtra, TPostSerialize>;
|
||||||
|
@ -418,24 +468,18 @@ export default class Struct<
|
||||||
return this as any;
|
return this as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeObject(context: StructSerializationContext) {
|
private initializeObject() {
|
||||||
const object = createRuntimeObject();
|
const object = createRuntimeObject();
|
||||||
Object.defineProperties(object, this._extra);
|
Object.defineProperties(object, this._extra);
|
||||||
|
|
||||||
for (const [name, definition] of this._fields) {
|
|
||||||
const runtimeValue = definition.createValue(this.options, context, object);
|
|
||||||
setRuntimeValue(object, name, runtimeValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
public create(init: TInit, context: StructSerializationContext): Overwrite<TExtra, TValue> {
|
public create(init: TInit, context: StructSerializationContext): Overwrite<TExtra, TValue> {
|
||||||
const object = this.initializeObject(context);
|
const object = this.initializeObject();
|
||||||
|
|
||||||
for (const [name] of this._fields) {
|
for (const [name, definition] of this._fields) {
|
||||||
const runtimeValue = getRuntimeValue(object, name);
|
const runtimeValue = definition.createValue(this.options, context, object, (init as any)[name]);
|
||||||
runtimeValue.set((init as any)[name]);
|
setRuntimeValue(object, name, runtimeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return object as any;
|
return object as any;
|
||||||
|
@ -444,11 +488,11 @@ export default class Struct<
|
||||||
public async deserialize(
|
public async deserialize(
|
||||||
context: StructDeserializationContext
|
context: StructDeserializationContext
|
||||||
): Promise<TPostDeserialized extends undefined ? Overwrite<TExtra, TValue> : TPostDeserialized> {
|
): Promise<TPostDeserialized extends undefined ? Overwrite<TExtra, TValue> : TPostDeserialized> {
|
||||||
const object = this.initializeObject(context);
|
const object = this.initializeObject();
|
||||||
|
|
||||||
for (const [name] of this._fields) {
|
for (const [name, definition] of this._fields) {
|
||||||
const runtimeValue = getRuntimeValue(object, name);
|
const runtimeValue = await definition.deserialize(this.options, context, object);
|
||||||
await runtimeValue.deserialize(context);
|
setRuntimeValue(object, name, runtimeValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._postDeserialized) {
|
if (this._postDeserialized) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { FieldDefinition, FieldRuntimeValue, StructDeserializationContext, StructSerializationContext } from '../basic';
|
import { FieldDefinition, FieldRuntimeValue, StructDeserializationContext, StructOptions, StructSerializationContext } from '../basic';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for all types that
|
* Base class for all types that
|
||||||
|
@ -97,14 +97,16 @@ export class StringFieldType<TTypeScriptType = string>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EmptyArrayBuffer = new ArrayBuffer(0);
|
||||||
|
|
||||||
export abstract class ArrayBufferLikeFieldDefinition<
|
export abstract class ArrayBufferLikeFieldDefinition<
|
||||||
TType extends ArrayBufferLikeFieldType = ArrayBufferLikeFieldType,
|
TType extends ArrayBufferLikeFieldType = ArrayBufferLikeFieldType,
|
||||||
TOptions = void,
|
TOptions = void,
|
||||||
TRemoveFields = never,
|
TRemoveInitFields = never,
|
||||||
> extends FieldDefinition<
|
> extends FieldDefinition<
|
||||||
TOptions,
|
TOptions,
|
||||||
TType['valueType'],
|
TType['valueType'],
|
||||||
TRemoveFields
|
TRemoveInitFields
|
||||||
>{
|
>{
|
||||||
public readonly type: TType;
|
public readonly type: TType;
|
||||||
|
|
||||||
|
@ -112,48 +114,55 @@ export abstract class ArrayBufferLikeFieldDefinition<
|
||||||
super(options);
|
super(options);
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const EmptyArrayBuffer = new ArrayBuffer(0);
|
protected getDeserializeSize(object: any): number {
|
||||||
|
|
||||||
export abstract class ArrayBufferLikeFieldRuntimeValue<
|
|
||||||
TDefinition extends ArrayBufferLikeFieldDefinition<any, any, any>,
|
|
||||||
> extends FieldRuntimeValue<TDefinition> {
|
|
||||||
protected arrayBuffer: ArrayBuffer | undefined;
|
|
||||||
|
|
||||||
protected typedValue: unknown;
|
|
||||||
|
|
||||||
protected getDeserializeSize(): number {
|
|
||||||
return this.getSize();
|
return this.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async deserialize(context: StructDeserializationContext): Promise<void> {
|
public async deserialize(
|
||||||
const size = this.getDeserializeSize();
|
options: Readonly<StructOptions>,
|
||||||
|
context: StructDeserializationContext,
|
||||||
this.arrayBuffer = undefined;
|
object: any,
|
||||||
this.typedValue = undefined;
|
): Promise<ArrayBufferLikeFieldRuntimeValue<ArrayBufferLikeFieldDefinition<TType, TOptions, TRemoveInitFields>>> {
|
||||||
|
const size = this.getDeserializeSize(object);
|
||||||
|
|
||||||
|
let arrayBuffer: ArrayBuffer;
|
||||||
if (size === 0) {
|
if (size === 0) {
|
||||||
this.arrayBuffer = EmptyArrayBuffer;
|
arrayBuffer = EmptyArrayBuffer;
|
||||||
} else {
|
} else {
|
||||||
this.arrayBuffer = await context.read(size);
|
arrayBuffer = await context.read(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.typedValue = this.definition.type.fromArrayBuffer(this.arrayBuffer, context);
|
const value = this.type.fromArrayBuffer(arrayBuffer, context);
|
||||||
|
const runtimeValue = this.createValue(options, context, object, value);
|
||||||
|
runtimeValue.arrayBuffer = arrayBuffer;
|
||||||
|
return runtimeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(): unknown {
|
/**
|
||||||
return this.typedValue;
|
* When implemented in derived classes, creates a `FieldRuntimeValue` for the current field definition.
|
||||||
}
|
*/
|
||||||
|
public abstract createValue(
|
||||||
|
options: Readonly<StructOptions>,
|
||||||
|
context: StructSerializationContext,
|
||||||
|
object: any,
|
||||||
|
value: TType['valueType'],
|
||||||
|
): ArrayBufferLikeFieldRuntimeValue<ArrayBufferLikeFieldDefinition<TType, TOptions, TRemoveInitFields>>;
|
||||||
|
}
|
||||||
|
|
||||||
public set(value: unknown): void {
|
export class ArrayBufferLikeFieldRuntimeValue<
|
||||||
this.typedValue = value;
|
TDefinition extends ArrayBufferLikeFieldDefinition<any, any, any>,
|
||||||
|
> extends FieldRuntimeValue<TDefinition> {
|
||||||
|
public arrayBuffer: ArrayBuffer | undefined;
|
||||||
|
|
||||||
|
public set(value: TDefinition['valueType']): void {
|
||||||
|
super.set(value);
|
||||||
this.arrayBuffer = undefined;
|
this.arrayBuffer = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public serialize(dataView: DataView, offset: number, context: StructSerializationContext): void {
|
public serialize(dataView: DataView, offset: number, context: StructSerializationContext): void {
|
||||||
if (!this.arrayBuffer) {
|
if (!this.arrayBuffer) {
|
||||||
this.arrayBuffer = this.definition.type.toArrayBuffer(this.typedValue, context);
|
this.arrayBuffer = this.definition.type.toArrayBuffer(this.value, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
new Uint8Array(dataView.buffer)
|
new Uint8Array(dataView.buffer)
|
||||||
|
|
|
@ -19,15 +19,9 @@ export class FixedLengthArrayBufferLikeFieldDefinition<
|
||||||
public createValue(
|
public createValue(
|
||||||
options: Readonly<StructOptions>,
|
options: Readonly<StructOptions>,
|
||||||
context: StructSerializationContext,
|
context: StructSerializationContext,
|
||||||
object: any
|
object: any,
|
||||||
): FixedLengthArrayBufferFieldRuntimeValue {
|
value: TType['valueType']
|
||||||
return new FixedLengthArrayBufferFieldRuntimeValue(this, options, context, object);
|
): ArrayBufferLikeFieldRuntimeValue<FixedLengthArrayBufferLikeFieldDefinition<TType, TOptions>> {
|
||||||
|
return new ArrayBufferLikeFieldRuntimeValue(this, options, context, object, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class FixedLengthArrayBufferFieldRuntimeValue
|
|
||||||
extends ArrayBufferLikeFieldRuntimeValue<FixedLengthArrayBufferLikeFieldDefinition>{
|
|
||||||
public static getSize(descriptor: FixedLengthArrayBufferLikeFieldDefinition) {
|
|
||||||
return descriptor.options.length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -57,12 +57,27 @@ export class NumberFieldDefinition<
|
||||||
return this.type.size;
|
return this.type.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async deserialize(
|
||||||
|
options: Readonly<StructOptions>,
|
||||||
|
context: StructDeserializationContext,
|
||||||
|
object: any,
|
||||||
|
): Promise<NumberFieldRuntimeValue<TType, TTypeScriptType>> {
|
||||||
|
const buffer = await context.read(this.getSize());
|
||||||
|
const view = new DataView(buffer);
|
||||||
|
const value = view[this.type.dataViewGetter](
|
||||||
|
0,
|
||||||
|
options.littleEndian
|
||||||
|
) as any;
|
||||||
|
return this.createValue(options, context, object, value);
|
||||||
|
}
|
||||||
|
|
||||||
public createValue(
|
public createValue(
|
||||||
options: Readonly<StructOptions>,
|
options: Readonly<StructOptions>,
|
||||||
context: StructSerializationContext,
|
context: StructSerializationContext,
|
||||||
object: any
|
object: any,
|
||||||
|
value: TTypeScriptType,
|
||||||
): NumberFieldRuntimeValue<TType, TTypeScriptType> {
|
): NumberFieldRuntimeValue<TType, TTypeScriptType> {
|
||||||
return new NumberFieldRuntimeValue(this, options, context, object);
|
return new NumberFieldRuntimeValue(this, options, context, object, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,25 +85,6 @@ export class NumberFieldRuntimeValue<
|
||||||
TType extends NumberFieldType = NumberFieldType,
|
TType extends NumberFieldType = NumberFieldType,
|
||||||
TTypeScriptType = TType['valueType'],
|
TTypeScriptType = TType['valueType'],
|
||||||
> extends FieldRuntimeValue<NumberFieldDefinition<TType, TTypeScriptType>> {
|
> extends FieldRuntimeValue<NumberFieldDefinition<TType, TTypeScriptType>> {
|
||||||
protected value: number | bigint | undefined;
|
|
||||||
|
|
||||||
public async deserialize(context: StructDeserializationContext): Promise<void> {
|
|
||||||
const buffer = await context.read(this.getSize());
|
|
||||||
const view = new DataView(buffer);
|
|
||||||
this.value = view[this.definition.type.dataViewGetter](
|
|
||||||
0,
|
|
||||||
this.options.littleEndian
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(): unknown {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set(value: unknown): void {
|
|
||||||
this.value = value as number | bigint;
|
|
||||||
}
|
|
||||||
|
|
||||||
public serialize(dataView: DataView, offset: number): void {
|
public serialize(dataView: DataView, offset: number): void {
|
||||||
// `setBigInt64` requires a `bigint` while others require `number`
|
// `setBigInt64` requires a `bigint` while others require `number`
|
||||||
// So `dataView[DataViewSetters]` requires `bigint & number`
|
// So `dataView[DataViewSetters]` requires `bigint & number`
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { getRuntimeValue, setRuntimeValue, StructOptions, StructSerializationContext } from '../basic';
|
import { FieldRuntimeValue, getRuntimeValue, setRuntimeValue, StructOptions, StructSerializationContext } from '../basic';
|
||||||
import { ArrayBufferLikeFieldDefinition, ArrayBufferLikeFieldRuntimeValue, ArrayBufferLikeFieldType } from './array-buffer';
|
import { ArrayBufferLikeFieldDefinition, ArrayBufferLikeFieldRuntimeValue, ArrayBufferLikeFieldType } from './array-buffer';
|
||||||
import { NumberFieldDefinition, NumberFieldRuntimeValue } from './number';
|
|
||||||
import { KeysOfType } from './utils';
|
import { KeysOfType } from './utils';
|
||||||
|
|
||||||
export interface VariableLengthArrayBufferLikeFieldOptions<
|
export interface VariableLengthArrayBufferLikeFieldOptions<
|
||||||
|
@ -22,47 +21,59 @@ export class VariableLengthArrayBufferLikeFieldDefinition<
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getDeserializeSize(object: any) {
|
||||||
|
let value = object[this.options.lengthField] as number | string;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
value = Number.parseInt(value, 10);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
public createValue(
|
public createValue(
|
||||||
options: Readonly<StructOptions>,
|
options: Readonly<StructOptions>,
|
||||||
context: StructSerializationContext,
|
context: StructSerializationContext,
|
||||||
object: any
|
object: any,
|
||||||
): VariableLengthArrayBufferLikeFieldRuntimeValue {
|
value: TType['valueType'],
|
||||||
return new VariableLengthArrayBufferLikeFieldRuntimeValue(this, options, context, object);
|
): VariableLengthArrayBufferLikeFieldRuntimeValue<TType, TOptions> {
|
||||||
|
return new VariableLengthArrayBufferLikeFieldRuntimeValue(this, options, context, object, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VariableLengthArrayBufferLikeLengthFieldRuntimeValue extends NumberFieldRuntimeValue {
|
class VariableLengthArrayBufferLikeLengthFieldRuntimeValue extends FieldRuntimeValue {
|
||||||
|
protected originalValue: FieldRuntimeValue;
|
||||||
|
|
||||||
protected arrayBufferValue: VariableLengthArrayBufferLikeFieldRuntimeValue;
|
protected arrayBufferValue: VariableLengthArrayBufferLikeFieldRuntimeValue;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
definition: NumberFieldDefinition,
|
originalValue: FieldRuntimeValue,
|
||||||
options: Readonly<StructOptions>,
|
|
||||||
context: StructSerializationContext,
|
|
||||||
object: any,
|
|
||||||
arrayBufferValue: VariableLengthArrayBufferLikeFieldRuntimeValue,
|
arrayBufferValue: VariableLengthArrayBufferLikeFieldRuntimeValue,
|
||||||
) {
|
) {
|
||||||
super(definition, options, context, object);
|
super(originalValue.definition, originalValue.options, originalValue.context, originalValue.object, 0);
|
||||||
|
this.originalValue = originalValue;
|
||||||
this.arrayBufferValue = arrayBufferValue;
|
this.arrayBufferValue = arrayBufferValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDeserializeSize() {
|
public getSize() {
|
||||||
return this.value;
|
return this.originalValue.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
get() {
|
get() {
|
||||||
|
// TODO: originalValue might be a `string` type, now it always returns `number`.
|
||||||
return this.arrayBufferValue.getSize();
|
return this.arrayBufferValue.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
set() { }
|
set() { }
|
||||||
|
|
||||||
serialize(dataView: DataView, offset: number) {
|
serialize(dataView: DataView, offset: number, context: StructSerializationContext) {
|
||||||
this.value = this.get();
|
this.originalValue.set(this.get());
|
||||||
super.serialize(dataView, offset);
|
this.originalValue.serialize(dataView, offset, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VariableLengthArrayBufferLikeFieldRuntimeValue
|
class VariableLengthArrayBufferLikeFieldRuntimeValue<
|
||||||
extends ArrayBufferLikeFieldRuntimeValue<VariableLengthArrayBufferLikeFieldDefinition> {
|
TType extends ArrayBufferLikeFieldType = ArrayBufferLikeFieldType,
|
||||||
|
TOptions extends VariableLengthArrayBufferLikeFieldOptions = VariableLengthArrayBufferLikeFieldOptions
|
||||||
|
> extends ArrayBufferLikeFieldRuntimeValue<VariableLengthArrayBufferLikeFieldDefinition<TType, TOptions>> {
|
||||||
public static getSize() {
|
public static getSize() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -72,38 +83,29 @@ class VariableLengthArrayBufferLikeFieldRuntimeValue
|
||||||
protected lengthFieldValue: VariableLengthArrayBufferLikeLengthFieldRuntimeValue;
|
protected lengthFieldValue: VariableLengthArrayBufferLikeLengthFieldRuntimeValue;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
descriptor: VariableLengthArrayBufferLikeFieldDefinition,
|
definition: VariableLengthArrayBufferLikeFieldDefinition<TType, TOptions>,
|
||||||
options: Readonly<StructOptions>,
|
options: Readonly<StructOptions>,
|
||||||
context: StructSerializationContext,
|
context: StructSerializationContext,
|
||||||
object: any
|
object: any,
|
||||||
|
value: TType['valueType'],
|
||||||
) {
|
) {
|
||||||
super(descriptor, options, context, object);
|
super(definition, options, context, object, value);
|
||||||
|
|
||||||
|
// Patch the associated length field.
|
||||||
const lengthField = this.definition.options.lengthField;
|
const lengthField = this.definition.options.lengthField;
|
||||||
const oldValue = getRuntimeValue(object, lengthField) as NumberFieldRuntimeValue;
|
const originalValue = getRuntimeValue(object, lengthField);
|
||||||
this.lengthFieldValue = new VariableLengthArrayBufferLikeLengthFieldRuntimeValue(
|
this.lengthFieldValue = new VariableLengthArrayBufferLikeLengthFieldRuntimeValue(originalValue, this);
|
||||||
oldValue.definition,
|
|
||||||
this.options,
|
|
||||||
this.context,
|
|
||||||
object,
|
|
||||||
this
|
|
||||||
);
|
|
||||||
setRuntimeValue(object, lengthField, this.lengthFieldValue);
|
setRuntimeValue(object, lengthField, this.lengthFieldValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getDeserializeSize() {
|
|
||||||
const value = this.lengthFieldValue.getDeserializeSize() as number;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getSize() {
|
public getSize() {
|
||||||
if (this.length === undefined) {
|
if (this.length === undefined) {
|
||||||
if (this.arrayBuffer !== undefined) {
|
if (this.arrayBuffer !== undefined) {
|
||||||
this.length = this.arrayBuffer.byteLength;
|
this.length = this.arrayBuffer.byteLength;
|
||||||
} else {
|
} else {
|
||||||
this.length = this.definition.type.getSize(this.typedValue);
|
this.length = this.definition.type.getSize(this.value);
|
||||||
if (this.length === -1) {
|
if (this.length === -1) {
|
||||||
this.arrayBuffer = this.definition.type.toArrayBuffer(this.typedValue, this.context);
|
this.arrayBuffer = this.definition.type.toArrayBuffer(this.value, this.context);
|
||||||
this.length = this.arrayBuffer.byteLength;
|
this.length = this.arrayBuffer.byteLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
177
packages/webpack-config/package-lock.json
generated
177
packages/webpack-config/package-lock.json
generated
|
@ -263,6 +263,30 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ansi-escapes": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"type-fest": "^0.11.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-convert": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"array-union": {
|
"array-union": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
|
||||||
|
@ -294,6 +318,22 @@
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.1.0",
|
||||||
|
"supports-color": "^7.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ci-info": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"clean-webpack-plugin": {
|
"clean-webpack-plugin": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz",
|
||||||
|
@ -304,12 +344,33 @@
|
||||||
"del": "^4.1.1"
|
"del": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"color-convert": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"color-name": "~1.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"color-name": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"consola": {
|
||||||
|
"version": "2.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz",
|
||||||
|
"integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"del": {
|
"del": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz",
|
||||||
|
@ -325,6 +386,27 @@
|
||||||
"rimraf": "^2.6.3"
|
"rimraf": "^2.6.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"emoji-regex": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"escape-string-regexp": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||||
|
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"figures": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"escape-string-regexp": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
|
@ -366,6 +448,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"has-flag": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"inflight": {
|
"inflight": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
|
@ -382,6 +470,12 @@
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"is-path-cwd": {
|
"is-path-cwd": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
|
||||||
|
@ -469,6 +563,12 @@
|
||||||
"pinkie": "^2.0.0"
|
"pinkie": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"pretty-time": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pretty-time/-/pretty-time-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"rimraf": {
|
"rimraf": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||||
|
@ -484,12 +584,89 @@
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"std-env": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/std-env/-/std-env-2.2.1.tgz",
|
||||||
|
"integrity": "sha512-IjYQUinA3lg5re/YMlwlfhqNRTzMZMqE+pezevdcTaHceqx8ngEi1alX9nNCk9Sc81fy1fLDeQoaCzeiW1yBOQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ci-info": "^1.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"emoji-regex": "^8.0.0",
|
||||||
|
"is-fullwidth-code-point": "^3.0.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"has-flag": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"text-table": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
|
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"type-fest": {
|
||||||
|
"version": "0.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
|
||||||
|
"integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "4.1.3",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
|
||||||
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
|
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"webpackbar": {
|
||||||
|
"version": "5.0.0-3",
|
||||||
|
"resolved": "https://registry.npmjs.org/webpackbar/-/webpackbar-5.0.0-3.tgz",
|
||||||
|
"integrity": "sha512-viW6KCYjMb0NPoDrw2jAmLXU2dEOhRrtku28KmOfeE1vxbfwCYuTbTaMhnkrCZLFAFyY9Q49Z/jzYO80Dw5b8g==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-escapes": "^4.3.1",
|
||||||
|
"chalk": "^4.1.0",
|
||||||
|
"consola": "^2.15.0",
|
||||||
|
"figures": "^3.2.0",
|
||||||
|
"pretty-time": "^1.1.0",
|
||||||
|
"std-env": "^2.2.1",
|
||||||
|
"text-table": "^0.2.0",
|
||||||
|
"wrap-ansi": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wrap-ansi": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^4.0.0",
|
||||||
|
"string-width": "^4.1.0",
|
||||||
|
"strip-ansi": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "webpack-config",
|
"name": "webpack-config",
|
||||||
"version": "0.0.1",
|
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"version": "0.0.1",
|
||||||
"description": "Webpack config for `demo` project in TypeScript",
|
"description": "Webpack config for `demo` project in TypeScript",
|
||||||
"author": "Simon Chan <cnsimonchan@live.com>",
|
"author": "Simon Chan <cnsimonchan@live.com>",
|
||||||
"homepage": "https://github.com/yume-chan/ya-webadb#readme",
|
"homepage": "https://github.com/yume-chan/ya-webadb#readme",
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
"@types/webpack-bundle-analyzer": "3.9.0",
|
"@types/webpack-bundle-analyzer": "3.9.0",
|
||||||
"@types/webpack-dev-server": "3.11.1",
|
"@types/webpack-dev-server": "3.11.1",
|
||||||
"clean-webpack-plugin": "3.0.0",
|
"clean-webpack-plugin": "3.0.0",
|
||||||
"typescript": "4.1.3"
|
"typescript": "4.1.3",
|
||||||
|
"webpackbar": "5.0.0-3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,12 @@ import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
|
||||||
|
import WebpackBar from 'webpackbar';
|
||||||
|
|
||||||
const context = path.resolve(process.cwd());
|
const context = path.resolve(process.cwd());
|
||||||
|
|
||||||
const plugins: webpack.Plugin[] = [
|
const plugins: webpack.Plugin[] = [
|
||||||
new CleanWebpackPlugin(),
|
new WebpackBar({}),
|
||||||
new MiniCssExtractPlugin({
|
new MiniCssExtractPlugin({
|
||||||
filename: '[name].[contenthash].css',
|
filename: '[name].[contenthash].css',
|
||||||
}),
|
}),
|
||||||
|
@ -35,36 +36,42 @@ if (process.env.ANALYZE) {
|
||||||
const config: webpack.ConfigurationFactory = (
|
const config: webpack.ConfigurationFactory = (
|
||||||
env: unknown,
|
env: unknown,
|
||||||
argv: webpack.CliConfigOptions
|
argv: webpack.CliConfigOptions
|
||||||
): webpack.Configuration => ({
|
): webpack.Configuration => {
|
||||||
mode: 'development',
|
if (argv.mode !== 'production') {
|
||||||
devtool: argv.mode === 'production' ? 'source-map' : 'eval-source-map',
|
plugins.unshift(new CleanWebpackPlugin());
|
||||||
context,
|
}
|
||||||
target: 'web',
|
|
||||||
entry: {
|
return {
|
||||||
index: './src/index.tsx',
|
mode: 'development',
|
||||||
},
|
devtool: argv.mode === 'production' ? 'source-map' : 'eval-source-map',
|
||||||
output: {
|
context,
|
||||||
path: path.resolve(context, 'lib'),
|
target: 'web',
|
||||||
filename: '[name].[contenthash].js',
|
entry: {
|
||||||
},
|
index: './src/index.tsx',
|
||||||
resolve: {
|
},
|
||||||
extensions: ['.ts', '.tsx', '.js'],
|
output: {
|
||||||
// @ts-expect-error typing is not up to date
|
path: path.resolve(context, 'lib'),
|
||||||
fallback: { "path": require.resolve("path-browserify") },
|
filename: '[name].[contenthash].js',
|
||||||
},
|
},
|
||||||
plugins,
|
resolve: {
|
||||||
module: {
|
extensions: ['.ts', '.tsx', '.js'],
|
||||||
rules: [
|
// @ts-expect-error typing is not up to date
|
||||||
{ test: /\.js$/, enforce: 'pre', use: ['source-map-loader'], },
|
fallback: { "path": require.resolve("path-browserify") },
|
||||||
{ test: /\.css$/i, use: [MiniCssExtractPlugin.loader, 'css-loader'] },
|
},
|
||||||
{ test: /\.asset$/, use: { loader: "file-loader" } },
|
plugins,
|
||||||
{ test: /\.tsx?$/i, loader: 'ts-loader', options: { projectReferences: true } },
|
module: {
|
||||||
],
|
rules: [
|
||||||
},
|
{ test: /\.js$/, enforce: 'pre', use: ['source-map-loader'], },
|
||||||
devServer: {
|
{ test: /\.css$/i, use: [MiniCssExtractPlugin.loader, 'css-loader'] },
|
||||||
contentBase: path.resolve(context, 'lib'),
|
{ test: /\.asset$/, use: { loader: "file-loader" } },
|
||||||
port: 9000,
|
{ test: /\.tsx?$/i, loader: 'ts-loader', options: { projectReferences: true } },
|
||||||
},
|
],
|
||||||
});
|
},
|
||||||
|
devServer: {
|
||||||
|
contentBase: path.resolve(context, 'lib'),
|
||||||
|
port: 9000,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export = config;
|
export = config;
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
"ESNext"
|
"ESNext"
|
||||||
],
|
],
|
||||||
"declaration": false, // /* Generates corresponding '.d.ts' file. */
|
"declaration": false, // /* Generates corresponding '.d.ts' file. */
|
||||||
|
"declarationDir": null,
|
||||||
"declarationMap": false, // /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
"declarationMap": false, // /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||||
"sourceMap": false, // /* Generates corresponding '.map' file. */
|
"sourceMap": false, // /* Generates corresponding '.map' file. */
|
||||||
"outDir": "../demo", // /* Redirect output structure to the directory. */
|
"outDir": "../demo", // /* Redirect output structure to the directory. */
|
||||||
"rootDir": "./src", // /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
"rootDir": "./src", // /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||||
"composite": false, // /* Enable project compilation */
|
"composite": false, // /* Enable project compilation */
|
||||||
"tsBuildInfoFile": "./tsconfig.tsbuildinfo", /* Specify file to store incremental compilation information */
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src"
|
"src"
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"outDir": "esm",
|
"outDir": "esm",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"removeComments": true,
|
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationDir": "dts",
|
"declarationDir": "dts",
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue