master
paring 2023-05-10 15:42:54 +09:00
parent 1ccddabf78
commit e387c6e4ed
11 changed files with 1788 additions and 127 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"typescript.preferences.importModuleSpecifierEnding": "js"
}

View File

@ -4,18 +4,21 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"start": "tsx src"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"inquirer": "^9.2.2",
"json5": "^2.2.3",
"sharp": "^0.32.1",
"yargs": "^17.7.2"
"sharp": "^0.32.1"
},
"devDependencies": {
"@types/node": "^20.1.1"
"@types/inquirer": "^9.0.3",
"@types/node": "^20.1.1",
"tsx": "^3.12.7",
"typescript": "^5.0.4"
},
"type": "module"
}

View File

@ -1,32 +1,285 @@
lockfileVersion: '6.0'
dependencies:
inquirer:
specifier: ^9.2.2
version: 9.2.2
json5:
specifier: ^2.2.3
version: 2.2.3
sharp:
specifier: ^0.32.1
version: 0.32.1
yargs:
specifier: ^17.7.2
version: 17.7.2
devDependencies:
'@types/inquirer':
specifier: ^9.0.3
version: 9.0.3
'@types/node':
specifier: ^20.1.1
version: 20.1.1
tsx:
specifier: ^3.12.7
version: 3.12.7
typescript:
specifier: ^5.0.4
version: 5.0.4
packages:
/@esbuild-kit/cjs-loader@2.4.2:
resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==}
dependencies:
'@esbuild-kit/core-utils': 3.1.0
get-tsconfig: 4.5.0
dev: true
/@esbuild-kit/core-utils@3.1.0:
resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==}
dependencies:
esbuild: 0.17.18
source-map-support: 0.5.21
dev: true
/@esbuild-kit/esm-loader@2.5.5:
resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==}
dependencies:
'@esbuild-kit/core-utils': 3.1.0
get-tsconfig: 4.5.0
dev: true
/@esbuild/android-arm64@0.17.18:
resolution: {integrity: sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-arm@0.17.18:
resolution: {integrity: sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/android-x64@0.17.18:
resolution: {integrity: sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-arm64@0.17.18:
resolution: {integrity: sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/darwin-x64@0.17.18:
resolution: {integrity: sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-arm64@0.17.18:
resolution: {integrity: sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/freebsd-x64@0.17.18:
resolution: {integrity: sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm64@0.17.18:
resolution: {integrity: sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-arm@0.17.18:
resolution: {integrity: sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ia32@0.17.18:
resolution: {integrity: sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-loong64@0.17.18:
resolution: {integrity: sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-mips64el@0.17.18:
resolution: {integrity: sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-ppc64@0.17.18:
resolution: {integrity: sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-riscv64@0.17.18:
resolution: {integrity: sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-s390x@0.17.18:
resolution: {integrity: sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/linux-x64@0.17.18:
resolution: {integrity: sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/@esbuild/netbsd-x64@0.17.18:
resolution: {integrity: sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/openbsd-x64@0.17.18:
resolution: {integrity: sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/@esbuild/sunos-x64@0.17.18:
resolution: {integrity: sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-arm64@0.17.18:
resolution: {integrity: sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-ia32@0.17.18:
resolution: {integrity: sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@esbuild/win32-x64@0.17.18:
resolution: {integrity: sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/@types/inquirer@9.0.3:
resolution: {integrity: sha512-CzNkWqQftcmk2jaCWdBTf9Sm7xSw4rkI1zpU/Udw3HX5//adEZUIm9STtoRP1qgWj0CWQtJ9UTvqmO2NNjhMJw==}
dependencies:
'@types/through': 0.0.30
rxjs: 7.8.1
dev: true
/@types/node@20.1.1:
resolution: {integrity: sha512-uKBEevTNb+l6/aCQaKVnUModfEMjAl98lw2Si9P5y4hLu9tm6AlX2ZIoXZX6Wh9lJueYPrGPKk5WMCNHg/u6/A==}
dev: true
/@types/through@0.0.30:
resolution: {integrity: sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==}
dependencies:
'@types/node': 20.1.1
dev: true
/ansi-escapes@4.3.2:
resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.21.3
dev: false
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: false
/ansi-regex@6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
dev: false
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
@ -46,6 +299,10 @@ packages:
readable-stream: 3.6.2
dev: false
/buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
/buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
dependencies:
@ -53,17 +310,47 @@ packages:
ieee754: 1.2.1
dev: false
/chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
dev: false
/chalk@5.2.0:
resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
dev: false
/chardet@0.7.0:
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
dev: false
/chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
dev: false
/cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
/cli-cursor@3.1.0:
resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
engines: {node: '>=8'}
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
restore-cursor: 3.1.0
dev: false
/cli-spinners@2.9.0:
resolution: {integrity: sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==}
engines: {node: '>=6'}
dev: false
/cli-width@4.0.0:
resolution: {integrity: sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==}
engines: {node: '>= 12'}
dev: false
/clone@1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'}
dev: false
/color-convert@2.0.1:
@ -104,6 +391,12 @@ packages:
engines: {node: '>=4.0.0'}
dev: false
/defaults@1.0.4:
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
dependencies:
clone: 1.0.4
dev: false
/detect-libc@2.0.1:
resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==}
engines: {node: '>=8'}
@ -119,9 +412,39 @@ packages:
once: 1.4.0
dev: false
/escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
/esbuild@0.17.18:
resolution: {integrity: sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==}
engines: {node: '>=12'}
hasBin: true
requiresBuild: true
optionalDependencies:
'@esbuild/android-arm': 0.17.18
'@esbuild/android-arm64': 0.17.18
'@esbuild/android-x64': 0.17.18
'@esbuild/darwin-arm64': 0.17.18
'@esbuild/darwin-x64': 0.17.18
'@esbuild/freebsd-arm64': 0.17.18
'@esbuild/freebsd-x64': 0.17.18
'@esbuild/linux-arm': 0.17.18
'@esbuild/linux-arm64': 0.17.18
'@esbuild/linux-ia32': 0.17.18
'@esbuild/linux-loong64': 0.17.18
'@esbuild/linux-mips64el': 0.17.18
'@esbuild/linux-ppc64': 0.17.18
'@esbuild/linux-riscv64': 0.17.18
'@esbuild/linux-s390x': 0.17.18
'@esbuild/linux-x64': 0.17.18
'@esbuild/netbsd-x64': 0.17.18
'@esbuild/openbsd-x64': 0.17.18
'@esbuild/sunos-x64': 0.17.18
'@esbuild/win32-arm64': 0.17.18
'@esbuild/win32-ia32': 0.17.18
'@esbuild/win32-x64': 0.17.18
dev: true
/escape-string-regexp@5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
dev: false
/expand-template@2.0.3:
@ -129,19 +452,55 @@ packages:
engines: {node: '>=6'}
dev: false
/external-editor@3.1.0:
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
engines: {node: '>=4'}
dependencies:
chardet: 0.7.0
iconv-lite: 0.4.24
tmp: 0.0.33
dev: false
/figures@5.0.0:
resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==}
engines: {node: '>=14'}
dependencies:
escape-string-regexp: 5.0.0
is-unicode-supported: 1.3.0
dev: false
/fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: false
/get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
dev: false
/fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: true
optional: true
/get-tsconfig@4.5.0:
resolution: {integrity: sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==}
dev: true
/github-from-package@0.0.0:
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
dev: false
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: false
/iconv-lite@0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
dependencies:
safer-buffer: 2.1.2
dev: false
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: false
@ -154,6 +513,27 @@ packages:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
dev: false
/inquirer@9.2.2:
resolution: {integrity: sha512-VV2ZOZe4ilLlOgEo7drIdzbi+EYJcNty0leF2vJq49zOW8+IoK1miJ+V5FjZY/X21Io29j66T/AiqHvS4tPIrw==}
engines: {node: '>=14.18.0'}
dependencies:
ansi-escapes: 4.3.2
chalk: 5.2.0
cli-cursor: 3.1.0
cli-width: 4.0.0
external-editor: 3.1.0
figures: 5.0.0
lodash: 4.17.21
mute-stream: 1.0.0
ora: 5.4.1
run-async: 2.4.1
rxjs: 7.8.1
string-width: 4.2.3
strip-ansi: 7.0.1
through: 2.3.8
wrap-ansi: 6.2.0
dev: false
/is-arrayish@0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: false
@ -163,12 +543,39 @@ packages:
engines: {node: '>=8'}
dev: false
/is-interactive@1.0.0:
resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
engines: {node: '>=8'}
dev: false
/is-unicode-supported@0.1.0:
resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
engines: {node: '>=10'}
dev: false
/is-unicode-supported@1.3.0:
resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==}
engines: {node: '>=12'}
dev: false
/json5@2.2.3:
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
engines: {node: '>=6'}
hasBin: true
dev: false
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: false
/log-symbols@4.1.0:
resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
engines: {node: '>=10'}
dependencies:
chalk: 4.1.2
is-unicode-supported: 0.1.0
dev: false
/lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
@ -176,6 +583,11 @@ packages:
yallist: 4.0.0
dev: false
/mimic-fn@2.1.0:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
dev: false
/mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
@ -189,6 +601,11 @@ packages:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
dev: false
/mute-stream@1.0.0:
resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
dev: false
/napi-build-utils@1.0.2:
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
dev: false
@ -210,6 +627,33 @@ packages:
wrappy: 1.0.2
dev: false
/onetime@5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
engines: {node: '>=6'}
dependencies:
mimic-fn: 2.1.0
dev: false
/ora@5.4.1:
resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
engines: {node: '>=10'}
dependencies:
bl: 4.1.0
chalk: 4.1.2
cli-cursor: 3.1.0
cli-spinners: 2.9.0
is-interactive: 1.0.0
is-unicode-supported: 0.1.0
log-symbols: 4.1.0
strip-ansi: 6.0.1
wcwidth: 1.0.1
dev: false
/os-tmpdir@1.0.2:
resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}
engines: {node: '>=0.10.0'}
dev: false
/prebuild-install@7.1.1:
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
engines: {node: '>=10'}
@ -255,15 +699,32 @@ packages:
util-deprecate: 1.0.2
dev: false
/require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
/restore-cursor@3.1.0:
resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
engines: {node: '>=8'}
dependencies:
onetime: 5.1.2
signal-exit: 3.0.7
dev: false
/run-async@2.4.1:
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
engines: {node: '>=0.12.0'}
dev: false
/rxjs@7.8.1:
resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==}
dependencies:
tslib: 2.5.0
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: false
/safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: false
/semver@7.5.0:
resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==}
engines: {node: '>=10'}
@ -287,6 +748,10 @@ packages:
tunnel-agent: 0.6.0
dev: false
/signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
dev: false
/simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
dev: false
@ -305,6 +770,18 @@ packages:
is-arrayish: 0.3.2
dev: false
/source-map-support@0.5.21:
resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
dependencies:
buffer-from: 1.1.2
source-map: 0.6.1
dev: true
/source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
dev: true
/string-width@4.2.3:
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
engines: {node: '>=8'}
@ -327,11 +804,25 @@ packages:
ansi-regex: 5.0.1
dev: false
/strip-ansi@7.0.1:
resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==}
engines: {node: '>=12'}
dependencies:
ansi-regex: 6.0.1
dev: false
/strip-json-comments@2.0.1:
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
engines: {node: '>=0.10.0'}
dev: false
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: false
/tar-fs@2.1.1:
resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
dependencies:
@ -352,19 +843,61 @@ packages:
readable-stream: 3.6.2
dev: false
/through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: false
/tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
engines: {node: '>=0.6.0'}
dependencies:
os-tmpdir: 1.0.2
dev: false
/tslib@2.5.0:
resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==}
/tsx@3.12.7:
resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==}
hasBin: true
dependencies:
'@esbuild-kit/cjs-loader': 2.4.2
'@esbuild-kit/core-utils': 3.1.0
'@esbuild-kit/esm-loader': 2.5.5
optionalDependencies:
fsevents: 2.3.2
dev: true
/tunnel-agent@0.6.0:
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
dependencies:
safe-buffer: 5.2.1
dev: false
/type-fest@0.21.3:
resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
engines: {node: '>=10'}
dev: false
/typescript@5.0.4:
resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==}
engines: {node: '>=12.20'}
hasBin: true
dev: true
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: false
/wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'}
/wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
dependencies:
defaults: 1.0.4
dev: false
/wrap-ansi@6.2.0:
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
engines: {node: '>=8'}
dependencies:
ansi-styles: 4.3.0
string-width: 4.2.3
@ -375,29 +908,6 @@ packages:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: false
/y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
dev: false
/yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
dev: false
/yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
dev: false
/yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
dependencies:
cliui: 8.0.1
escalade: 3.1.1
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
dev: false

177
src/index.ts Normal file
View File

@ -0,0 +1,177 @@
import { copyFile, readFile } from 'fs/promises'
import inquirer from 'inquirer'
import { parseADOFAILevel } from './utils/parser.js'
import {
ActionType,
DecorationEvent,
LevelEvent,
MoveDecorations,
} from './types/events.js'
import { join } from 'path'
import { dirname } from 'path'
import sharp from 'sharp'
import { Level } from './types/level.js'
const { filePath } = await inquirer.prompt([
{
message: 'wow give me level file path',
name: 'filePath',
},
])
const levelDir = dirname(filePath)
const distPath = join(process.cwd(), 'dist')
console.log(filePath)
// todo functions
// .filter(x=>x.tag.split(' ').includes(tag))
// function findAndFilterDecorationEventWithTagReference(levelEvents: LevelEvent[], tag: string): LevelEvent[]
// occupiedTags: string[]
// let newTag = createUniqueTag(tag)
// findAndFilterDecorationEventWithTagReference(levelEvents, tag).forEachasfhgjksguhds
// function createTagAndCopyUsageReference(levelEvents: LevelEvent[], tag: string): LevelEvent[]
// function splitTagByCondition(levelEvents: LevelEvent[], tag: string, condition: (levelEvent: LevelEvent) => boolean): LevelEvent[]
// function minimizeEvent(levelEvents: LevelEvent[]): LevelEvent[]
class EventSans {
origEvents: MoveDecorations[] = []
events: MoveDecorations[] = []
// decorationsByTag: Map<string, Decoration[]> = new Map()
get decorations() {
return this._level.decorations as Decoration[]
}
constructor(private _level: Level) {
this.filterEvents()
}
filterEvents() {
const actions = this._level.actions
for (let index = actions.length - 1; index >= 0; index--) {
const event = actions[index]
if (event.eventType === ActionType.MoveDecorations) {
actions.splice(index, 1)
for (const tag of event.tag.split(' ')) {
if (!tag) {
this.origEvents.push({ ...event })
continue
}
this.origEvents.push({ ...event, tag })
}
}
}
}
/**
* wow
*/
tagDecorations() {
// ? 뭐해야하지
// of -> array의 엘리먼트 / 오브젝트의 value 부분
// in -> array의 index를 string으로 만들어버린거 / 오브젝트의 key 부분
let decorationsByTag: Map<string, Decoration[]> = new Map()
const setOrPush = (tag: string, deco: Decoration) => {
if (decorationsByTag.has(tag)) {
let arr = decorationsByTag.get(tag)!.slice()
arr.push(deco)
decorationsByTag.set(tag, arr)
} else decorationsByTag.set(tag, [deco])
}
// 이거 끝난거 아닌가(????) -> 원래 태그는 근데 가지고 있어야 나중에 육안으로 잘 됐는지 구분 가능할듯
for (const deco of this.decorations) {
const tag = `${deco.tag}-${deco.id}`
for (const ev of this.origEvents) {
if (ev.tag.split(' ').includes(deco.tag)) {
// 이벤트에는 태그 여러개들어감..................... 스페이스로 구분해서............
this.events.push({ ...ev, tag })
}
}
deco.tag = tag
}
}
}
type Decoration = DecorationEvent & { id: number }
type ImageSize = { width: number; height: number }
// Read file
const content: string = await readFile(filePath, 'utf-8')
// Objectify content JSON.parse (or similar method)
const level = parseADOFAILevel(content)
const decorations: Decoration[] = []
const imagePaths: Map<string, ImageSize> = new Map()
let lastId = 0
const registerDecorationImage = async (decorationImage: string) => {
if (!decorationImage || imagePaths.has(decorationImage)) return
const imagePath = join(levelDir, decorationImage)
const meta = await sharp(imagePath).metadata()
imagePaths.set(decorationImage, {
width: meta.width!,
height: meta.height!,
})
}
for (const event of [...level.actions, ...level.decorations]) {
// Read through decorations, apply id to each decoration
if (
event.eventType === ActionType.AddDecoration ||
event.eventType === ActionType.AddText
) {
const decoration: Decoration = event as Decoration
decoration.id = lastId++
decorations.push(decoration)
// Record file path in decorationImage property then acquire image resolution, match these
if (decoration.eventType != ActionType.AddDecoration) continue
await registerDecorationImage(decoration.decorationImage)
}
// Record file path in decorationImage property then acquire image resolution, match these
if (event.eventType === ActionType.MoveDecorations)
await registerDecorationImage(event.decorationImage)
}
// Create a new directory, then copy over all files to new directory
for (const [imagePath, image] of imagePaths) {
let newPath = join(distPath, imagePath)
// Apply resolution changes to image files
await sharp(join(levelDir, imagePath))
.resize({ width: image.width, height: image.height })
.toFile(newPath)
// 충격: 아직 파일별로 ratio로 나누는거 구현안함
// wow
}
// Iterate through decorations:
// 1) record which tags are used in each decoration
// 2) split image decoration(AddDecoration eventType) and text decoration(AddText eventType) tag references
// 3) make changes to pivotOffset and scale properties depending on which image path is stored in decorationImage
//!4) ensure one to one relation to image files and image decoration tag by duplicating tag and its usage. duplicate the event if needed
// Iterate through actions
// 1) make changes to pivotOffset and scale properties corresponding to tag
// Save file to new directory

567
src/types/events.ts Normal file
View File

@ -0,0 +1,567 @@
import {
SpeedType,
BgDisplayMode,
ToggleBool,
TrackColorType,
TrackColorPulse,
TrackStyle,
TrackAnimationType,
TrackAnimationType2,
DecPlacementType,
DecorationBlendMode,
MaskingType,
Hitbox,
FlashPlane,
Ease,
RandomMode,
CamMovementType,
GameSound,
HitSound,
Filter,
EasePartBehavior,
HoldStartSound,
HoldLoopSound,
HoldEndSound,
HoldMidSound,
HoldMidSoundType,
HoldMidSoundTimingRelativeTo,
PlanetCount,
FontName,
TargetPlanet,
} from './types'
export enum ActionType {
SetSpeed = 'SetSpeed',
Twirl = 'Twirl',
Multitap = 'Multitap',
Checkpoint = 'Checkpoint',
CustomBackground = 'CustomBackground',
ChangeTrack = 'ChangeTrack',
ColorTrack = 'ColorTrack',
AnimateTrack = 'AnimateTrack',
AddDecoration = 'AddDecoration',
Flash = 'Flash',
MoveCamera = 'MoveCamera',
SetHitsound = 'SetHitsound',
SetGameSound = 'SetGameSound',
PlaySound = 'PlaySound',
RecolorTrack = 'RecolorTrack',
MoveTrack = 'MoveTrack',
SetFilter = 'SetFilter',
HallOfMirrors = 'HallOfMirrors',
ShakeScreen = 'ShakeScreen',
SetPlanetRotation = 'SetPlanetRotation',
KillPlayer = 'KillPlayer',
MoveDecorations = 'MoveDecorations',
PositionTrack = 'PositionTrack',
Hold = 'Hold',
SetHoldSound = 'SetHoldSound',
TileDimensions = 'TileDimensions',
RepeatEvents = 'RepeatEvents',
Bloom = 'Bloom',
SetConditionalEvents = 'SetConditionalEvents',
MultiPlanet = 'MultiPlanet',
FreeRoam = 'FreeRoam',
FreeRoamTwirl = 'FreeRoamTwirl',
FreeRoamRemove = 'FreeRoamRemove',
FreeRoamWarning = 'FreeRoamWarning',
Pause = 'Pause',
AutoPlayTiles = 'AutoPlayTiles',
Hide = 'Hide',
ScaleMargin = 'ScaleMargin',
ScaleRadius = 'ScaleRadius',
ScreenTile = 'ScreenTile',
ScreenScroll = 'ScreenScroll',
AddText = 'AddText',
SetText = 'SetText',
EditorComment = 'EditorComment',
Bookmark = 'Bookmark',
CallMethod = 'CallMethod',
AddComponent = 'AddComponent',
ScalePlanets = 'ScalePlanets',
}
export interface Action<T extends ActionType> {
floor: number
eventType: T
}
export type Tile = [number, TileType]
export enum TileType {
ThisTile = 'ThisTile',
FirstTile = 'FirstTile',
LastTile = 'LastTile',
}
export type Color = `#${string}`
export type Vector2 = [number, number]
export interface SetSpeed extends Action<ActionType.SetSpeed> {
speedType: SpeedType
beatsPerMinute: number
bpmMultiplier: number
}
export interface Twirl extends Action<ActionType.Twirl> {}
export interface Multitap extends Action<ActionType.Multitap> {
taps: number
}
export interface Checkpoint extends Action<ActionType.Checkpoint> {
tileOffset: number
}
export interface CustomBackground extends Action<ActionType.CustomBackground> {
color: Color
bgImage: string
imageColor: Color
parallax: Vector2
bgDisplayMode: BgDisplayMode
lockRot: ToggleBool
loopBG: ToggleBool
unscaledSize: number
angleOffset: number
eventTag: string
}
export interface ChangeTrack extends Action<ActionType.ChangeTrack> {
trackColorType: TrackColorType
trackColor: Color
secondaryTrackColor: Color
trackColorAnimDuration: number
trackColorPulse: TrackColorPulse
trackPulseLength: number
trackStyle: TrackStyle
trackAnimation: TrackAnimationType
beatsAhead: number
trackDisappearAnimation: TrackAnimationType2
beatsBehind: number
}
export interface ColorTrack extends Action<ActionType.ColorTrack> {
trackColorType: TrackColorType
trackColor: Color
secondaryTrackColor: Color
trackColorAnimDuration: number
trackColorPulse: TrackColorPulse
trackPulseLength: number
trackStyle: TrackStyle
trackTexture: string
trackTextureScale: number
trackGlowIntensity: number
}
export interface AnimateTrack extends Action<ActionType.AnimateTrack> {
trackAnimation: TrackAnimationType
beatsAhead: number
trackDisappearAnimation: TrackAnimationType2
beatsBehind: number
}
export interface AddDecoration extends Action<ActionType.AddDecoration> {
decorationImage: string
position: Vector2
relativeTo: DecPlacementType
pivotOffset: Vector2
rotation: number
lockRotation: ToggleBool
scale: Vector2
lockScale: ToggleBool
tile: Vector2
color: Color
opacity: number
depth: number
parallax: Vector2
parallaxOffset: Vector2
tag: string
imageSmoothing: ToggleBool
blendMode: DecorationBlendMode
maskingType: MaskingType
useMaskingDepth: ToggleBool
maskingFrontDepth: number
maskingBackDepth: number
failHitbox: ToggleBool
failHitboxType: Hitbox
failHitboxScale: Vector2
failHitboxOffset: Vector2
failHitboxRotation: number
components: string
}
export interface Flash extends Action<ActionType.Flash> {
duration: number
plane: FlashPlane
startColor: Color
startOpacity: number
endColor: Color
endOpacity: number
angleOffset: number
ease: Ease
eventTag: string
}
export interface MoveCamera extends Action<ActionType.MoveCamera> {
duration: number
durationRandomMode: RandomMode
durationRandomValue: number
relativeTo: CamMovementType
position: Vector2
positionRandomMode: RandomMode
positionRandomValue: Vector2
rotation: number
rotationRandomMode: RandomMode
rotationRandomValue: number
zoom: number
zoomRandomMode: RandomMode
zoomRandomValue: number
angleOffset: number
ease: Ease
dontDisable: ToggleBool
minVfxOnly: ToggleBool
eventTag: string
}
export interface SetHitsound extends Action<ActionType.SetHitsound> {
gameSound: GameSound
hitsound: HitSound
hitsoundVolume: number
}
export interface SetGameSound extends Action<ActionType.SetGameSound> {
gameSound: GameSound
hitsound: HitSound
volume: number
}
export interface PlaySound extends Action<ActionType.PlaySound> {
hitsound: HitSound
hitsoundVolume: number
angleOffset: number
eventTag: string
}
export interface RecolorTrack extends Action<ActionType.RecolorTrack> {
startTile: Tile
endTile: Tile
gapLength: number
trackColorType: TrackColorType
trackColor: Color
secondaryTrackColor: Color
trackColorAnimDuration: number
trackColorPulse: TrackColorPulse
trackPulseLength: number
trackStyle: TrackStyle
trackGlowIntensity: number
angleOffset: number
eventTag: string
}
export interface MoveTrack extends Action<ActionType.MoveTrack> {
startTile: Tile
endTile: Tile
gapLength: number
duration: number
positionOffset: Vector2
rotationOffset: number
scale: Vector2
opacity: number
angleOffset: number
ease: Ease
maxVfxOnly: ToggleBool
eventTag: string
}
export interface SetFilter extends Action<ActionType.SetFilter> {
filter: Filter
enabled: ToggleBool
intensity: number
duration: number
ease: Ease
disableOthers: ToggleBool
angleOffset: number
eventTag: string
}
export interface HallOfMirrors extends Action<ActionType.HallOfMirrors> {
enabled: ToggleBool
angleOffset: number
eventTag: string
}
export interface ShakeScreen extends Action<ActionType.ShakeScreen> {
duration: number
strength: number
intensity: number
fadeOut: ToggleBool
angleOffset: number
eventTag: string
}
export interface SetPlanetRotation
extends Action<ActionType.SetPlanetRotation> {
ease: Ease
easeParts: number
easePartBehavior: EasePartBehavior
}
export interface KillPlayer extends Action<ActionType.KillPlayer> {
playAnimation: ToggleBool
failMessage: string
eventTag: string
}
export interface MoveDecorations extends Action<ActionType.MoveDecorations> {
duration: number
tag: string
decorationImage: string
positionOffset: Vector2
pivotOffset: Vector2
rotationOffset: number
scale: Vector2
color: Color
opacity: number
depth: number
parallax: Vector2
parallaxOffset: Vector2
angleOffset: number
ease: Ease
eventTag: string
maskingType: MaskingType
useMaskingDepth: ToggleBool
maskingFrontDepth: number
maskingBackDepth: number
}
export interface PositionTrack extends Action<ActionType.PositionTrack> {
positionOffset: Vector2
relativeTo: Tile
rotation: number
scale: number
opacity: number
justThisTile: ToggleBool
editorOnly: ToggleBool
stickToFloors: ToggleBool
}
export interface Hold extends Action<ActionType.Hold> {
duration: number
distanceMultiplier: number
landingAnimation: ToggleBool
}
export interface SetHoldSound extends Action<ActionType.SetHoldSound> {
holdStartSound: HoldStartSound
holdLoopSound: HoldLoopSound
holdEndSound: HoldEndSound
holdMidSound: HoldMidSound
holdMidSoundType: HoldMidSoundType
holdMidSoundDelay: number
holdMidSoundTimingRelativeTo: HoldMidSoundTimingRelativeTo
holdSoundVolume: number
}
export interface TileDimensions extends Action<ActionType.TileDimensions> {
width: number
length: number
}
export interface RepeatEvents extends Action<ActionType.RepeatEvents> {
repetitions: number
interval: number
tag: string
}
export interface Bloom extends Action<ActionType.Bloom> {
enabled: ToggleBool
threshold: number
intensity: number
color: Color
duration: number
ease: Ease
angleOffset: number
eventTag: string
}
export interface SetConditionalEvents
extends Action<ActionType.SetConditionalEvents> {
perfectTag: string
hitTag: string
earlyPerfectTag: string
latePerfectTag: string
barelyTag: string
veryEarlyTag: string
veryLateTag: string
missTag: string
tooEarlyTag: string
tooLateTag: string
lossTag: string
}
export interface MultiPlanet extends Action<ActionType.MultiPlanet> {
planets: PlanetCount
}
export interface FreeRoam extends Action<ActionType.FreeRoam> {
duration: number
size: Vector2
positionOffset: Vector2
outTime: number
outEase: Ease
hitsoundOnBeats: HitSound
hitsoundOffBeats: HitSound
countdownTicks: number
angleCorrectionDir: number
}
export interface FreeRoamTwirl extends Action<ActionType.FreeRoamTwirl> {
position: Vector2
}
export interface FreeRoamRemove extends Action<ActionType.FreeRoamRemove> {
position: Vector2
size: Vector2
}
export interface FreeRoamWarning extends Action<ActionType.FreeRoamWarning> {
position: Vector2
}
export interface Pause extends Action<ActionType.Pause> {
duration: number
countdownTicks: number
angleCorrectionDir: number
}
export interface AutoPlayTiles extends Action<ActionType.AutoPlayTiles> {
enabled: ToggleBool
safetyTiles: ToggleBool
}
export interface Hide extends Action<ActionType.Hide> {
hideJudgment: ToggleBool
hideTileIcon: ToggleBool
}
export interface ScaleMargin extends Action<ActionType.ScaleMargin> {
scale: number
}
export interface ScaleRadius extends Action<ActionType.ScaleRadius> {
scale: number
}
export interface ScreenTile extends Action<ActionType.ScreenTile> {
tile: Vector2
angleOffset: number
eventTag: string
}
export interface ScreenScroll extends Action<ActionType.ScreenScroll> {
scroll: Vector2
angleOffset: number
eventTag: string
}
export interface AddText extends Action<ActionType.AddText> {
decText: string
font: FontName
position: Vector2
relativeTo: DecPlacementType
pivotOffset: Vector2
rotation: number
lockRotation: ToggleBool
scale: Vector2
lockScale: ToggleBool
color: Color
opacity: number
depth: number
parallax: Vector2
tag: string
}
export interface SetText extends Action<ActionType.SetText> {
decText: string
tag: string
angleOffset: number
eventTag: string
}
export interface EditorComment extends Action<ActionType.EditorComment> {
comment: string
}
export interface Bookmark extends Action<ActionType.Bookmark> {}
export interface CallMethod extends Action<ActionType.CallMethod> {
method: string
angleOffset: number
}
export interface AddComponent extends Action<ActionType.AddComponent> {
component: string
properties: string
duration: number
angleOffset: number
}
export interface ScalePlanets extends Action<ActionType.ScalePlanets> {
duration: number
targetPlanet: TargetPlanet
scale: number
angleOffset: number
ease: Ease
eventTag: string
}
export type LevelEvent =
| SetSpeed
| Twirl
| Multitap
| Checkpoint
| CustomBackground
| ChangeTrack
| ColorTrack
| AnimateTrack
| Flash
| MoveCamera
| SetHitsound
| SetGameSound
| PlaySound
| RecolorTrack
| MoveTrack
| SetFilter
| HallOfMirrors
| ShakeScreen
| SetPlanetRotation
| KillPlayer
| MoveDecorations
| PositionTrack
| Hold
| SetHoldSound
| TileDimensions
| RepeatEvents
| Bloom
| SetConditionalEvents
| MultiPlanet
| FreeRoam
| FreeRoamTwirl
| FreeRoamRemove
| FreeRoamWarning
| Pause
| AutoPlayTiles
| Hide
| ScaleMargin
| ScaleRadius
| ScreenTile
| ScreenScroll
| SetText
| EditorComment
| Bookmark
| CallMethod
| AddComponent
| ScalePlanets
export type DecorationEvent = AddDecoration | AddText

3
src/types/index.ts Normal file
View File

@ -0,0 +1,3 @@
export * from './events.js'
export * from './types.js'
export * from './level.js'

78
src/types/level.ts Normal file
View File

@ -0,0 +1,78 @@
import { DecorationEvent, LevelEvent } from './events.js'
type AngleData = number[]
export interface Level {
angleData: AngleData
settings: LevelSettings
actions: LevelEvent[]
decorations: DecorationEvent[]
}
export interface LevelSettings {
version: 12
artist: ''
specialArtistType: 'None'
artistPermission: ''
song: ''
author: ''
separateCountdownTime: 'Enabled'
previewImage: ''
previewIcon: ''
previewIconColor: '003f52'
previewSongStart: 0
previewSongDuration: 10
seizureWarning: 'Disabled'
levelDesc: ''
levelTags: ''
artistLinks: ''
difficulty: 1
requiredMods: []
songFilename: 'L_X.wav'
bpm: 107.5
volume: 100
offset: 502
pitch: 100
hitsound: 'Sizzle'
hitsoundVolume: 100
countdownTicks: 4
trackColorType: 'Single'
trackColor: 'ffffffaa'
secondaryTrackColor: 'ffffff'
trackColorAnimDuration: 2
trackColorPulse: 'None'
trackPulseLength: 10
trackStyle: 'Minimal'
trackGlowIntensity: 50
trackAnimation: 'Fade'
beatsAhead: 6
trackDisappearAnimation: 'Fade'
beatsBehind: 0
backgroundColor: '000000'
showDefaultBGIfNoImage: 'Disabled'
bgImage: ''
bgImageColor: 'ffffff'
parallax: [100, 100]
bgDisplayMode: 'Unscaled'
lockRot: 'Disabled'
loopBG: 'Disabled'
unscaledSize: 100
relativeTo: 'Player'
position: [0, 0]
rotation: 0
zoom: 175
pulseOnFloor: 'Enabled'
startCamLowVFX: 'Disabled'
bgVideo: ''
loopVideo: 'Disabled'
vidOffset: 0
floorIconOutlines: 'Disabled'
stickToFloors: 'Enabled'
planetEase: 'Linear'
planetEaseParts: 1
planetEasePartBehavior: 'Mirror'
customClass: ''
legacyFlash: false
legacyCamRelativeTo: false
legacySpriteTiles: false
}

287
src/types/types.ts Normal file
View File

@ -0,0 +1,287 @@
export enum SpeedType {
Bpm = 'Bpm',
Multiplier = 'Multiplier',
}
export enum BgDisplayMode {
FitToScreen = 'FitToScreen',
Unscaled = 'Unscaled',
Tiled = 'Tiled',
}
export enum ToggleBool {
Enabled = 'Enabled',
Disabled = 'Disabled',
}
export enum TrackColorType {
Single = 'Single',
Stripes = 'Stripes',
Glow = 'Glow',
Blink = 'Blink',
Switch = 'Switch',
Rainbow = 'Rainbow',
Volume = 'Volume',
}
export enum TrackColorPulse {
None = 'None',
Forward = 'Forward',
Backward = 'Backward',
}
export enum TrackStyle {
Standard = 'Standard',
Neon = 'Neon',
NeonLight = 'NeonLight',
Basic = 'Basic',
Gems = 'Gems',
Minimal = 'Minimal',
}
export enum TrackAnimationType {
None = 'None',
Assemble = 'Assemble',
Assemble_Far = 'Assemble_Far',
Extend = 'Extend',
Grow = 'Grow',
Grow_Spin = 'Grow_Spin',
Fade = 'Fade',
Drop = 'Drop',
Rise = 'Rise',
}
export enum TrackAnimationType2 {
None = 'None',
Scatter = 'Scatter',
Scatter_Far = 'Scatter_Far',
Retract = 'Retract',
Shrink = 'Shrink',
Shrink_Spin = 'Shrink_Spin',
Fade = 'Fade',
}
export enum DecPlacementType {
Tile = 'Tile',
Global = 'Global',
RedPlanet = 'RedPlanet',
BluePlanet = 'BluePlanet',
Camera = 'Camera',
CameraAspect = 'CameraAspect',
}
export enum DecorationBlendMode {
None = 'None',
Screen = 'Screen',
LinearDodge = 'LinearDodge',
Overlay = 'Overlay',
SoftLight = 'SoftLight',
Difference = 'Difference',
}
export enum MaskingType {
None = 'None',
Mask = 'Mask',
VisibleInsideMask = 'VisibleInsideMask',
VisibleOutsideMask = 'VisibleOutsideMask',
}
export enum Hitbox {
Box = 'Box',
Circle = 'Circle',
Capsule = 'Capsule',
}
export enum FlashPlane {
Foreground = 'Foreground',
Background = 'Background',
}
export enum Ease {
Linear = 'Linear',
InSine = 'InSine',
OutSine = 'OutSine',
InOutSine = 'InOutSine',
InQuad = 'InQuad',
OutQuad = 'OutQuad',
InOutQuad = 'InOutQuad',
InCubic = 'InCubic',
OutCubic = 'OutCubic',
InOutCubic = 'InOutCubic',
InQuart = 'InQuart',
OutQuart = 'OutQuart',
InOutQuart = 'InOutQuart',
InQuint = 'InQuint',
OutQuint = 'OutQuint',
InOutQuint = 'InOutQuint',
InExpo = 'InExpo',
OutExpo = 'OutExpo',
InOutExpo = 'InOutExpo',
InCirc = 'InCirc',
OutCirc = 'OutCirc',
InOutCirc = 'InOutCirc',
InElastic = 'InElastic',
OutElastic = 'OutElastic',
InOutElastic = 'InOutElastic',
InBack = 'InBack',
OutBack = 'OutBack',
InOutBack = 'InOutBack',
InBounce = 'InBounce',
OutBounce = 'OutBounce',
InOutBounce = 'InOutBounce',
Flash = 'Flash',
InFlash = 'InFlash',
OutFlash = 'OutFlash',
InOutFlash = 'InOutFlash',
}
export enum RandomMode {
None = 'None',
Between = 'Between',
OneOrOther = 'OneOrOther',
}
export enum CamMovementType {
Player = 'Player',
Tile = 'Tile',
Global = 'Global',
LastPosition = 'LastPosition',
LastPositionNoRotation = 'LastPositionNoRotation',
}
export enum GameSound {
Hitsound = 'Hitsound',
Midspin = 'Midspin',
}
export enum HitSound {
Hat = 'Hat',
Kick = 'Kick',
Shaker = 'Shaker',
Sizzle = 'Sizzle',
Chuck = 'Chuck',
ShakerLoud = 'ShakerLoud',
None = 'None',
Hammer = 'Hammer',
KickChroma = 'KickChroma',
SnareAcoustic2 = 'SnareAcoustic2',
Sidestick = 'Sidestick',
Stick = 'Stick',
ReverbClack = 'ReverbClack',
Squareshot = 'Squareshot',
PowerDown = 'PowerDown',
PowerUp = 'PowerUp',
KickHouse = 'KickHouse',
KickRupture = 'KickRupture',
HatHouse = 'HatHouse',
SnareHouse = 'SnareHouse',
SnareVapor = 'SnareVapor',
ClapHit = 'ClapHit',
ClapHitEcho = 'ClapHitEcho',
ReverbClap = 'ReverbClap',
FireTile = 'FireTile',
IceTile = 'IceTile',
VehiclePositive = 'VehiclePositive',
VehicleNegative = 'VehicleNegative',
}
export enum Filter {
Grayscale = 'Grayscale',
Sepia = 'Sepia',
Invert = 'Invert',
VHS = 'VHS',
EightiesTV = 'EightiesTV',
FiftiesTV = 'FiftiesTV',
Arcade = 'Arcade',
LED = 'LED',
Rain = 'Rain',
Blizzard = 'Blizzard',
PixelSnow = 'PixelSnow',
Compression = 'Compression',
Glitch = 'Glitch',
Pixelate = 'Pixelate',
Waves = 'Waves',
Static = 'Static',
Grain = 'Grain',
MotionBlur = 'MotionBlur',
Fisheye = 'Fisheye',
Aberration = 'Aberration',
Drawing = 'Drawing',
Neon = 'Neon',
Handheld = 'Handheld',
NightVision = 'NightVision',
Funk = 'Funk',
Tunnel = 'Tunnel',
Weird3D = 'Weird3D',
Blur = 'Blur',
BlurFocus = 'BlurFocus',
GaussianBlur = 'GaussianBlur',
HexagonBlack = 'HexagonBlack',
Posterize = 'Posterize',
Sharpen = 'Sharpen',
Contrast = 'Contrast',
EdgeBlackLine = 'EdgeBlackLine',
OilPaint = 'OilPaint',
SuperDot = 'SuperDot',
WaterDrop = 'WaterDrop',
LightWater = 'LightWater',
Petals = 'Petals',
PetalsInstant = 'PetalsInstant',
}
export enum EasePartBehavior {
Mirror = 'Mirror',
Repeat = 'Repeat',
}
export enum HoldStartSound {
Fuse = 'Fuse',
None = 'None',
}
export enum HoldLoopSound {
Fuse = 'Fuse',
None = 'None',
}
export enum HoldEndSound {
Fuse = 'Fuse',
None = 'None',
}
export enum HoldMidSound {
Fuse = 'Fuse',
SingSing = 'SingSing',
None = 'None',
}
export enum HoldMidSoundType {
Once = 'Once',
Repeat = 'Repeat',
}
export enum HoldMidSoundTimingRelativeTo {
Start = 'Start',
End = 'End',
}
export enum PlanetCount {
TwoPlanets = 'TwoPlanets',
ThreePlanets = 'ThreePlanets',
}
export enum FontName {
Default = 'Default',
Arial = 'Arial',
ComicSansMS = 'ComicSansMS',
CourierNew = 'CourierNew',
Georgia = 'Georgia',
Impact = 'Impact',
TimesNewRoman = 'TimesNewRoman',
}
export enum TargetPlanet {
FirePlanet = 'FirePlanet',
IcePlanet = 'IcePlanet',
Both = 'Both',
}

View File

@ -1,10 +1,7 @@
import JSON5 from 'json5'
import { Level } from '../types'
/**
* @param {string} level
* @returns {any} level json
*/
export const parseADOFAILevel = (level) => {
export const parseADOFAILevel = (level: string): Level => {
try {
return JSON5.parse(level)
} catch (e) {
@ -24,7 +21,6 @@ export const parseADOFAILevel = (level) => {
.replaceAll(']\t"decorations', '],\t"decorations')
.replaceAll('\r', '')
// require('fs').writeFileSync('./debug.adofai', formattedLevel);
return JSON5.parse(formattedLevel)
}
}

109
tsconfig.json Normal file
View File

@ -0,0 +1,109 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "ESNext" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */,
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
// "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */
// "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */
// "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true /* Enable all strict type-checking options. */,
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

View File

@ -1,72 +0,0 @@
import { copyFile, mkdir, readFile, readdir, rm, writeFile } from 'fs/promises'
import yargs from 'yargs'
import { parseADOFAILevel } from './parser.js'
import { basename, dirname, join } from 'path'
import { existsSync } from 'fs'
import sharp from 'sharp'
const args = yargs(process.argv)
const path = args.argv._[2]
const ratio = Number(args.argv._[3])
if (isNaN(ratio)) throw new Error('ratio is not number')
console.log(path)
const file = await readFile(path)
const level = parseADOFAILevel(file)
const workDir = join(process.cwd(), 'work')
if (existsSync(workDir)) await rm(workDir, { recursive: true, force: true })
await mkdir(workDir)
const origLevelDir = dirname(path)
for (const item of await readdir(origLevelDir)) {
await copyFile(join(origLevelDir, item), join(workDir, item))
}
const decoFiles = new Set()
const textTags = new Set()
for (const deco of level.decorations) {
if (deco.eventType === 'AddDecoration') {
deco.scale = deco.scale.map((x) => x / ratio)
decoFiles.add(deco.decorationImage)
} else if (deco.eventType === 'AddText') {
textTags.add(deco.tag)
}
}
for (const action of level.actions) {
if (action.eventType === 'MoveDecorations') {
if (textTags.has(action.tag)) continue
if (action.scale) action.scale = action.scale.map((x) => x / ratio)
if (action.decorationImage) decoFiles.add(action.decorationImage)
}
}
for (const f of decoFiles) {
try {
const orig = join(origLevelDir, f)
const dest = join(workDir, f)
const meta = await sharp(orig).metadata()
await sharp(orig)
.resize(Math.round(meta.width * ratio), Math.round(meta.height * ratio))
.toFile(dest)
console.log(f)
} catch (e) {
console.error(e)
}
}
await writeFile(join(workDir, basename(path)), JSON.stringify(level))