diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 61acbdb..43f8840 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,9 @@ jobs: npx tsx pkg/native/test/test_icon.cts npx tsx pkg/native/test/test_link.cts npx tsx pkg/native/test/test_operation.cts + npx tsx pkg/native/test/test_depth.cts npx tsx pkg/native/test/test_os.cts + npx tsx pkg/native/test/test_arc.cts npx tsx pkg/native/test/test_arc_tar.cts npx tsx pkg/native/test/test_arc_tgz.cts npx tsx pkg/native/test/test_arc_zip.cts diff --git a/README.md b/README.md index a7fba65..b98128b 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Windows と Mac で同じファイラーを使いたかったので作りまし - ファイル操作 - 正規表現による再帰検索 - ビューア + - アーカイブ (7z / rar / tar / tar.gz / tgz / tar.xz / txz / zip) - 画像 (gif / jpg / jpeg / png / webp) - 音声 (mp3 / m4a / ogg / wav / wave) - 動画 (mp4 / webm) diff --git a/config/sys.json b/config/sys.json index bcc54fc..7c37f3d 100644 --- a/config/sys.json +++ b/config/sys.json @@ -3,5 +3,11 @@ "ver": "0.1", "styleFontFamily": "Consolas, Menlo, monospace", "styleFontSize": 14, - "styleLineHeight": 18 + "styleLineHeight": 18, + "favorites": [ + { + "name": "home", + "path": "~" + } + ] } \ No newline at end of file diff --git a/config/sys.schema b/config/sys.schema index 7a0e040..edb0226 100644 --- a/config/sys.schema +++ b/config/sys.schema @@ -5,7 +5,8 @@ "ver", "styleFontFamily", "styleFontSize", - "styleLineHeight" + "styleLineHeight", + "favorites" ], "properties": { "$schema": { @@ -28,6 +29,27 @@ "styleLineHeight": { "type": "number", "minimum": 1 + }, + "favorites": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "path" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "path": { + "type": "string", + "minLength": 1 + } + } + } } } } \ No newline at end of file diff --git a/dprint.json b/dprint.json index b86ea72..88d27fc 100644 --- a/dprint.json +++ b/dprint.json @@ -12,6 +12,6 @@ "**/node_modules" ], "plugins": [ - "https://plugins.dprint.dev/typescript-0.95.13.wasm" + "https://plugins.dprint.dev/typescript-0.95.15.wasm" ] } \ No newline at end of file diff --git a/extension/src/fs.trash.cts b/extension/src/fs.trash.cts index 28aff40..a337d84 100644 --- a/extension/src/fs.trash.cts +++ b/extension/src/fs.trash.cts @@ -11,10 +11,11 @@ module.exports = async (ex: Extension): Promise => { title: title, text: ex.active.cursor[0].full, }) - - if (alert !== null) { - await ex.filer.trash(ex.active.cursor[0].full) + if (alert === null) { + return } + + await ex.filer.trash(ex.active.cursor[0].full) } else { const alert = await ex.dialog.open({ @@ -22,11 +23,12 @@ module.exports = async (ex: Extension): Promise => { title: title, text: `${ex.active.select.length} files`, }) + if (alert === null) { + return + } - if (alert !== null) { - for (const v of ex.active.select) { - await ex.filer.trash(v[0].full) - } + for (const v of ex.active.select) { + await ex.filer.trash(v[0].full) } } diff --git a/extension/tsconfig.json b/extension/tsconfig.json index 08c4cbb..6bcaea6 100644 --- a/extension/tsconfig.json +++ b/extension/tsconfig.json @@ -14,6 +14,9 @@ "./src/*", ], }, + "types": [ + "@types/node", + ], // Type Checking "alwaysStrict": true, diff --git a/package-lock.json b/package-lock.json index 08d4521..97a32c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "eyna", - "version": "0.0.60", + "version": "0.0.61", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "eyna", - "version": "0.0.60", + "version": "0.0.61", "hasInstallScript": true, "workspaces": [ "pkg/fixture", @@ -18,17 +18,17 @@ "@eyna/lib": "workspace:*", "@eyna/native": "workspace:*", "@eyna/util": "workspace:*", - "@vue/runtime-dom": "3.5.28", + "@vue/runtime-dom": "3.5.29", "codemirror": "6.0.2", - "electron": "40.2.1", - "electron-builder": "26.7.0", + "electron": "40.7.0", + "electron-builder": "26.8.2", "esbuild": "0.27.3", "monaco-editor": "0.55.1", "pug": "3.0.3", "stylus": "0.64.0", - "tar": "7.5.7", + "tar": "7.5.10", "tsx": "4.21.0", - "typescript": "5.9.3" + "typescript": "6.0.0-beta" } }, "node_modules/@adobe/css-tools": { @@ -89,9 +89,9 @@ } }, "node_modules/@codemirror/autocomplete": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", - "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", + "version": "6.20.1", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.1.tgz", + "integrity": "sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==", "dev": true, "license": "MIT", "dependencies": { @@ -115,9 +115,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.12.1", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.1.tgz", - "integrity": "sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==", + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.2.tgz", + "integrity": "sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==", "dev": true, "license": "MIT", "dependencies": { @@ -130,9 +130,9 @@ } }, "node_modules/@codemirror/lint": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.3.tgz", - "integrity": "sha512-y3YkYhdnhjDBAe0VIA0c4wVoFOvnp8CnAvfLqi0TqotIv92wIlAAP7HELOpLBsKwjAX6W92rSflA6an/2zBvXw==", + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.5.tgz", + "integrity": "sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==", "dev": true, "license": "MIT", "dependencies": { @@ -164,9 +164,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.39.13", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.13.tgz", - "integrity": "sha512-QBO8ZsgJLCbI28KdY0/oDy5NQLqOQVZCozBknxc2/7L98V+TVYFHnfaCsnGh1U+alpd2LOkStVwYY7nW2R1xbw==", + "version": "6.39.16", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.16.tgz", + "integrity": "sha512-m6S22fFpKtOWhq8HuhzsI1WzUP/hB9THbDj0Tl5KX4gbO6Y91hwBl7Yky33NdvB6IffuRFiBxf1R8kJMyXmA4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -212,19 +212,6 @@ "node": ">=10.12.0" } }, - "node_modules/@electron/asar/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/@electron/fuses": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz", @@ -488,20 +475,10 @@ "node": ">=16.4" } }, - "node_modules/@electron/universal/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", - "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", "dev": true, "license": "MIT", "dependencies": { @@ -526,22 +503,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@electron/universal/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@electron/universal/node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -575,9 +536,9 @@ } }, "node_modules/@electron/windows-sign/node_modules/fs-extra": { - "version": "11.3.3", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", - "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", "dev": true, "license": "MIT", "optional": true, @@ -1076,29 +1037,6 @@ "resolved": "pkg/util", "link": true }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz", - "integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", @@ -1358,9 +1296,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.12.tgz", - "integrity": "sha512-68e+T28EbdmLSTkPgs3+UacC6rzmqrcWFPQs1C8mwJhI/r5Uxr0yEuQotczNRROd1gq30NGxee+fo0rSIxpyAw==", + "version": "24.11.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.11.0.tgz", + "integrity": "sha512-fPxQqz4VTgPI/IQ+lj9r0h+fDR66bzoeMGHp8ASee+32OSGIkeASsoZuJixsQoVef1QJbeubcPBxKk22QVoWdw==", "dev": true, "license": "MIT", "dependencies": { @@ -1417,43 +1355,43 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.28.tgz", - "integrity": "sha512-gr5hEsxvn+RNyu9/9o1WtdYdwDjg5FgjUSBEkZWqgTKlo/fvwZ2+8W6AfKsc9YN2k/+iHYdS9vZYAhpi10kNaw==", + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.29.tgz", + "integrity": "sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.5.28" + "@vue/shared": "3.5.29" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.28.tgz", - "integrity": "sha512-POVHTdbgnrBBIpnbYU4y7pOMNlPn2QVxVzkvEA2pEgvzbelQq4ZOUxbp2oiyo+BOtiYlm8Q44wShHJoBvDPAjQ==", + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.29.tgz", + "integrity": "sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.28", - "@vue/shared": "3.5.28" + "@vue/reactivity": "3.5.29", + "@vue/shared": "3.5.29" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.28.tgz", - "integrity": "sha512-4SXxSF8SXYMuhAIkT+eBRqOkWEfPu6nhccrzrkioA6l0boiq7sp18HCOov9qWJA5HML61kW8p/cB4MmBiG9dSA==", + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.29.tgz", + "integrity": "sha512-AHvvJEtcY9tw/uk+s/YRLSlxxQnqnAkjqvK25ZiM4CllCZWzElRAoQnCM42m9AHRLNJ6oe2kC5DCgD4AUdlvXg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.28", - "@vue/runtime-core": "3.5.28", - "@vue/shared": "3.5.28", + "@vue/reactivity": "3.5.29", + "@vue/runtime-core": "3.5.29", + "@vue/shared": "3.5.29", "csstype": "^3.2.3" } }, "node_modules/@vue/shared": { - "version": "3.5.28", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.28.tgz", - "integrity": "sha512-cfWa1fCGBxrvaHRhvV3Is0MgmrbSCxYTXCSCau2I0a1Xw1N1pHAvkWCiXPRAqjvToILvguNyEwjevUqAuBQWvQ==", + "version": "3.5.29", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.29.tgz", + "integrity": "sha512-w7SR0A5zyRByL9XUkCfdLs7t9XOHUyJ67qPGQjOou3p6GvBeBW+AVjUUmlxtZ4PIYaRvE+1LmK44O4uajlZwcg==", "dev": true, "license": "MIT" }, @@ -1508,9 +1446,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -1568,9 +1506,9 @@ "license": "MIT" }, "node_modules/app-builder-lib": { - "version": "26.7.0", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.7.0.tgz", - "integrity": "sha512-/UgCD8VrO79Wv8aBNpjMfsS1pIUfIPURoRn0Ik6tMe5avdZF+vQgl/juJgipcMmH3YS0BD573lCdCHyoi84USg==", + "version": "26.8.2", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.8.2.tgz", + "integrity": "sha512-z3ptLzJwNl35fyR0wxv4qWOfZuU36VysYHnbs8PDtf8S0QzIl2OWimdDFVmCxYMkIV1k/RT9CeTgcP7oUznFOw==", "dev": true, "license": "MIT", "dependencies": { @@ -1585,7 +1523,7 @@ "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", - "builder-util": "26.4.1", + "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chromium-pickle-js": "^0.2.0", "ci-info": "4.3.1", @@ -1593,7 +1531,7 @@ "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", - "electron-publish": "26.6.0", + "electron-publish": "26.8.1", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", @@ -1615,8 +1553,8 @@ "node": ">=14.0.0" }, "peerDependencies": { - "dmg-builder": "26.7.0", - "electron-builder-squirrel-windows": "26.7.0" + "dmg-builder": "26.8.2", + "electron-builder-squirrel-windows": "26.8.2" } }, "node_modules/app-builder-lib/node_modules/@electron/get": { @@ -1824,11 +1762,14 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/base64-js": { "version": "1.5.1", @@ -1873,14 +1814,16 @@ "optional": true }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/buffer": { @@ -1926,9 +1869,9 @@ "license": "MIT" }, "node_modules/builder-util": { - "version": "26.4.1", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.4.1.tgz", - "integrity": "sha512-FlgH43XZ50w3UtS1RVGDWOz8v9qMXPC7upMtKMtBEnYdt1OVoS61NYhKm/4x+cIaWqJTXua0+VVPI+fSPGXNIw==", + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.8.1.tgz", + "integrity": "sha512-pm1lTYbGyc90DHgCDO7eo8Rl4EqKLciayNbZqGziqnH9jrlKe8ZANGdityLZU+pJh16dfzjAx2xQq9McuIPEtw==", "dev": true, "license": "MIT", "dependencies": { @@ -2304,13 +2247,6 @@ "node": ">=0.10.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/constantinople": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", @@ -2549,28 +2485,15 @@ "p-limit": "^3.1.0 " } }, - "node_modules/dir-compare/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/dmg-builder": { - "version": "26.7.0", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.7.0.tgz", - "integrity": "sha512-uOOBA3f+kW3o4KpSoMQ6SNpdXU7WtxlJRb9vCZgOvqhTz4b3GjcoWKstdisizNZLsylhTMv8TLHFPFW0Uxsj/g==", + "version": "26.8.2", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.8.2.tgz", + "integrity": "sha512-DaWI+p4DOqiFVZFMovdGYammBOyJAiHHFWUTQ0Z7gNc0twfdIN0LvyJ+vFsgZEDR1fjgbpCj690IVtbYIsZObQ==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "26.7.0", - "builder-util": "26.4.1", + "app-builder-lib": "26.8.2", + "builder-util": "26.8.1", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -2722,9 +2645,9 @@ } }, "node_modules/electron": { - "version": "40.2.1", - "resolved": "https://registry.npmjs.org/electron/-/electron-40.2.1.tgz", - "integrity": "sha512-0zOeyN8LB1KHIjVV5jyMmQmkqx3J8OkkVlab3p7vOM28jI46blxW7M52Tcdi6X2m5o2jj8ejOlAh5+boL3w8aQ==", + "version": "40.7.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-40.7.0.tgz", + "integrity": "sha512-oQe76S/3V1rcb0+i45hAxnCH8udkRZSaHUNwglzNAEKbB94LSJ1qwbFo8+uRc2UsYZgCqSIMRcyX40GyOkD+Xw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2741,18 +2664,18 @@ } }, "node_modules/electron-builder": { - "version": "26.7.0", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.7.0.tgz", - "integrity": "sha512-LoXbCvSFxLesPneQ/fM7FB4OheIDA2tjqCdUkKlObV5ZKGhYgi5VHPHO/6UUOUodAlg7SrkPx7BZJPby+Vrtbg==", + "version": "26.8.2", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.8.2.tgz", + "integrity": "sha512-ieiiXPdgH3qrG6lcvy2mtnI5iEmAopmLuVRMSJ5j40weU0tgpNx0OAk9J5X5nnO0j9+KIkxHzwFZVUDk1U3aGw==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "26.7.0", - "builder-util": "26.4.1", + "app-builder-lib": "26.8.2", + "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "ci-info": "^4.2.0", - "dmg-builder": "26.7.0", + "dmg-builder": "26.8.2", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", @@ -2767,15 +2690,15 @@ } }, "node_modules/electron-builder-squirrel-windows": { - "version": "26.7.0", - "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.7.0.tgz", - "integrity": "sha512-3EqkQK+q0kGshdPSKEPb2p5F75TENMKu6Fe5aTdeaPfdzFK4Yjp5L0d6S7K8iyvqIsGQ/ei4bnpyX9wt+kVCKQ==", + "version": "26.8.2", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.8.2.tgz", + "integrity": "sha512-kXhajX6DzdIQcTlctVTKoG1oO39JhWcTG0lH7ZEJ4FzPaKJy7KFNfNJUd5BoEmLjv5GlrRZpEOYnniD+LcwNJA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "app-builder-lib": "26.7.0", - "builder-util": "26.4.1", + "app-builder-lib": "26.8.2", + "builder-util": "26.8.1", "electron-winstaller": "5.4.0" } }, @@ -2818,14 +2741,14 @@ } }, "node_modules/electron-publish": { - "version": "26.6.0", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.6.0.tgz", - "integrity": "sha512-LsyHMMqbvJ2vsOvuWJ19OezgF2ANdCiHpIucDHNiLhuI+/F3eW98ouzWSRmXXi82ZOPZXC07jnIravY4YYwCLQ==", + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.8.1.tgz", + "integrity": "sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w==", "dev": true, "license": "MIT", "dependencies": { "@types/fs-extra": "^9.0.11", - "builder-util": "26.4.1", + "builder-util": "26.8.1", "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "form-data": "^4.0.5", @@ -3160,38 +3083,15 @@ } }, "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", "dev": true, "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/form-data": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", @@ -3341,18 +3241,18 @@ } }, "node_modules/glob": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.1.tgz", - "integrity": "sha512-B7U/vJpE3DkJ5WXTgTpTRN63uV42DseiXXKMwG14LQBXmsdeIoHAPbU/MEo6II0k5ED74uc2ZGTC6MwHFQhF6w==", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "minimatch": "^10.1.2", - "minipass": "^7.1.2", - "path-scurry": "^2.0.0" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4056,16 +3956,16 @@ } }, "node_modules/minimatch": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz", - "integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4082,11 +3982,11 @@ } }, "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -4515,9 +4415,9 @@ "license": "MIT" }, "node_modules/path-scurry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", - "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -4525,16 +4425,16 @@ "minipass": "^7.1.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -4821,9 +4721,9 @@ "license": "MIT" }, "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", "dependencies": { @@ -4986,14 +4886,14 @@ } }, "node_modules/rimraf": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.2.tgz", - "integrity": "sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", "dev": true, "license": "BlueOak-1.0.0", "peer": true, "dependencies": { - "glob": "^13.0.0", + "glob": "^13.0.3", "package-json-from-dist": "^1.0.1" }, "bin": { @@ -5064,9 +4964,9 @@ } }, "node_modules/sax": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", - "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.5.0.tgz", + "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -5341,6 +5241,16 @@ "url": "https://opencollective.com/stylus" } }, + "node_modules/stylus/node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, "node_modules/stylus/node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", @@ -5391,9 +5301,9 @@ } }, "node_modules/tar": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz", - "integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz", + "integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -5590,9 +5500,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.0-beta", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.0-beta.tgz", + "integrity": "sha512-CldZdztDpQRLM1HC6WDQjQkQN5Ub5zRau737a1diGh3lPmb9oRsaWHk1y5iqK0o7+1bNJ0oXfEGRkAogFZBL+Q==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index c3ce13b..64c3e6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eyna", - "version": "0.0.60", + "version": "0.0.61", "private": true, "type": "module", "main": "app/browser.cjs", @@ -14,21 +14,22 @@ "@eyna/lib": "workspace:*", "@eyna/native": "workspace:*", "@eyna/util": "workspace:*", - "@vue/runtime-dom": "3.5.28", + "@vue/runtime-dom": "3.5.29", "codemirror": "6.0.2", - "electron": "40.2.1", - "electron-builder": "26.7.0", + "electron": "40.7.0", + "electron-builder": "26.8.2", "esbuild": "0.27.3", "monaco-editor": "0.55.1", "pug": "3.0.3", "stylus": "0.64.0", - "tar": "7.5.7", + "tar": "7.5.10", "tsx": "4.21.0", - "typescript": "5.9.3" + "typescript": "6.0.0-beta" }, "overrides": { "dompurify": "3", "glob": "13", + "minimatch": "10", "rimraf": "6" }, "scripts": { diff --git a/pkg/lib/scripts/_vcpkg.mts b/pkg/lib/scripts/_vcpkg.mts index 40ae6e8..a4438da 100644 --- a/pkg/lib/scripts/_vcpkg.mts +++ b/pkg/lib/scripts/_vcpkg.mts @@ -47,3 +47,38 @@ export async function install(stdout: IOType = "ignore") { }) }) } + +export async function status(): Promise> { + const file = path.join(__top, "vcpkg_installed", "vcpkg", "status") + const data = await fs.promises.readFile(file, "utf-8") + + const status: Record = {} + const items = data.split("\n\n") + + for (const item of items) { + const lines = item.split("\n") + + let pkg: string | null = null + let ver: string | null = null + + for (const line of lines) { + if (line.indexOf("Package: ") === 0) { + pkg = line.slice("Package: ".length).trim() + } + else if (line.indexOf("Version: ") === 0) { + ver = line.slice("Version: ".length).trim() + } + } + + if (pkg && ver) { + status[pkg] = ver + } + } + + const sorted: Record = {} + for (const key of Object.keys(status).sort()) { + sorted[key] = status[key] + } + + return sorted +} diff --git a/pkg/native/lib/_type.ts b/pkg/native/lib/_type.ts index bd49ad1..e1913ea 100644 --- a/pkg/native/lib/_type.ts +++ b/pkg/native/lib/_type.ts @@ -4,7 +4,7 @@ export enum Sort { } export enum FileType { - HomeUser = -2, + Favorite = -2, Drive = -1, None = 0, Directory = 1, diff --git a/pkg/native/lib/browser.ts b/pkg/native/lib/browser.ts index 372d3da..d8b56b8 100644 --- a/pkg/native/lib/browser.ts +++ b/pkg/native/lib/browser.ts @@ -29,7 +29,7 @@ export function exists(abstract: string): Promise { return native.exists(abstract) } -export function getArchive(abstract: string, base: string, depth: number = 0): Promise { +export function getArchive(abstract: string, base: string = "", depth: number = 0): Promise { return native.getArchive(abstract, base, depth) } diff --git a/pkg/native/src/common_attribute.hpp b/pkg/native/src/common_attribute.hpp index f78f6e9..2428764 100644 --- a/pkg/native/src/common_attribute.hpp +++ b/pkg/native/src/common_attribute.hpp @@ -86,7 +86,7 @@ void attribute(_attribute& attribute) time -= 116444736000000000; } attribute.time = time / 10000000; - attribute.nsec = time % 10000000; + attribute.nsec = (time % 10000000) * 100; attribute.win_attribute = info.dwFileAttributes; @@ -112,13 +112,13 @@ void attribute(_attribute& attribute) HANDLE handle = CreateFileW(attribute.full.c_str(), 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (handle != NULL) { + if (handle != INVALID_HANDLE_VALUE) { int8_t buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*)buffer; DWORD bytes; - if (handle != INVALID_HANDLE_VALUE && DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, sizeof(buffer), &bytes, NULL)) { + if (DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, sizeof(buffer), &bytes, NULL)) { // シンボリック if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { _string_t str( @@ -242,13 +242,11 @@ void attribute(_attribute& attribute) } if (attribute.file_type == FILE_TYPE::FILE_TYPE_LINK) { - if ([[dic objectForKey:NSURLIsAliasFileKey] boolValue]) { - attribute.link_type = LINK_TYPE::LINK_TYPE_SYMBOLIC; + attribute.link_type = LINK_TYPE::LINK_TYPE_SYMBOLIC; - _char_t link[PATH_MAX] = {}; - if (-1 != readlink(attribute.full.c_str(), link, PATH_MAX)) { - attribute.link = std::filesystem::path(_string_t(link)); - } + _char_t link[PATH_MAX] = {}; + if (-1 != readlink(attribute.full.c_str(), link, PATH_MAX)) { + attribute.link = std::filesystem::path(_string_t(link)); } } else if (attribute.file_type == FILE_TYPE::FILE_TYPE_FILE) { diff --git a/pkg/native/src/get_archive.hpp b/pkg/native/src/get_archive.hpp index 45b3bc1..4da389b 100644 --- a/pkg/native/src/get_archive.hpp +++ b/pkg/native/src/get_archive.hpp @@ -173,6 +173,11 @@ void get_archive(const v8::FunctionCallbackInfo& info) } work->min_depth = std::ranges::distance(work->base); work->max_depth = work->min_depth + info[2]->Int32Value(CONTEXT).ToChecked(); + if (work->max_depth < work->min_depth || 100 < work->max_depth) { + promise->Reject(CONTEXT, to_string(ERROR_INVALID_ARGUMENT)); + delete work; + return; + } work->m.clear(); diff --git a/pkg/native/src/get_archive_entry.hpp b/pkg/native/src/get_archive_entry.hpp index d1b2e12..5fcc152 100644 --- a/pkg/native/src/get_archive_entry.hpp +++ b/pkg/native/src/get_archive_entry.hpp @@ -180,7 +180,7 @@ void get_archive_entry(const v8::FunctionCallbackInfo& info) || !info[2]->IsString() || !info[3]->IsBigInt()) { - ISOLATE->ThrowException(to_string(ERROR_INVALID_ARGUMENT)); + promise->Reject(CONTEXT, to_string(ERROR_INVALID_ARGUMENT)); return; } @@ -192,18 +192,23 @@ void get_archive_entry(const v8::FunctionCallbackInfo& info) async->abst = generic_path(to_string(info[1].As())); if (is_relative(async->abst) || is_traversal(async->abst)) { - ISOLATE->ThrowException(to_string(ERROR_INVALID_PATH)); + promise->Reject(CONTEXT, to_string(ERROR_INVALID_PATH)); delete async; return; } async->path = generic_path(to_string(info[2].As())); if (is_traversal(async->path)) { - ISOLATE->ThrowException(to_string(ERROR_INVALID_T_PATH)); + promise->Reject(CONTEXT, to_string(ERROR_INVALID_T_PATH)); delete async; return; } async->seek = info[3].As()->Int64Value(); + if (async->seek < 0) { + promise->Reject(CONTEXT, to_string(ERROR_INVALID_ARGUMENT)); + delete async; + return; + } v8::Local readable = info[0].As(); diff --git a/pkg/native/src/get_directory.hpp b/pkg/native/src/get_directory.hpp index f0fcd41..9736bd8 100644 --- a/pkg/native/src/get_directory.hpp +++ b/pkg/native/src/get_directory.hpp @@ -162,6 +162,11 @@ void get_directory(const v8::FunctionCallbackInfo& info) } work->dp = info[3]->Int32Value(CONTEXT).ToChecked(); + if (work->dp < 0 || 100 < work->dp) { + promise->Reject(CONTEXT, to_string(ERROR_INVALID_ARGUMENT)); + delete work; + return; + } if (info[4]->IsNull()) { work->pt = V(""); diff --git a/pkg/native/src/get_path_attribute.hpp b/pkg/native/src/get_path_attribute.hpp index 81f8324..7d1b6cb 100644 --- a/pkg/native/src/get_path_attribute.hpp +++ b/pkg/native/src/get_path_attribute.hpp @@ -76,10 +76,22 @@ static void get_path_attribute_complete(uv_work_t* req, int status) obj->Set(CONTEXT, to_string(V("time")), v8::Number::New(ISOLATE, (double)a.time)); obj->Set(CONTEXT, to_string(V("nsec")), v8::Number::New(ISOLATE, (double)a.nsec)); - obj->Set(CONTEXT, to_string(V("readonly")), v8::Boolean::New(ISOLATE, a.readonly)); - obj->Set(CONTEXT, to_string(V("hidden")), v8::Boolean::New(ISOLATE, a.hidden)); - obj->Set(CONTEXT, to_string(V("system")), v8::Boolean::New(ISOLATE, a.system)); - obj->Set(CONTEXT, to_string(V("cloud")), v8::Boolean::New(ISOLATE, a.cloud)); + v8::Local x = v8::Object::New(ISOLATE); + if (a.readonly) { + x->Set(CONTEXT, to_string(V("readonly")), v8::Boolean::New(ISOLATE, true)); + } + if (a.hidden) { + x->Set(CONTEXT, to_string(V("hidden")), v8::Boolean::New(ISOLATE, true)); + } + if (a.system) { + x->Set(CONTEXT, to_string(V("system")), v8::Boolean::New(ISOLATE, true)); + } + if (a.cloud) { + x->Set(CONTEXT, to_string(V("cloud")), v8::Boolean::New(ISOLATE, true)); + } + if (0 < x->GetOwnPropertyNames(CONTEXT).ToLocalChecked()->Length()) { + obj->Set(CONTEXT, to_string(V("x")), x); + } array->Set(CONTEXT, array->Length(), obj); } diff --git a/pkg/native/src/get_volume.hpp b/pkg/native/src/get_volume.hpp index 26052b5..912a850 100644 --- a/pkg/native/src/get_volume.hpp +++ b/pkg/native/src/get_volume.hpp @@ -34,18 +34,21 @@ static void get_volume_async(uv_work_t *req) } } #elif OS_MAC64 - NSArray* array = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:nil options:NSVolumeEnumerationSkipHiddenVolumes]; + NSArray* array = [[NSFileManager defaultManager] + mountedVolumeURLsIncludingResourceValuesForKeys:@[NSURLVolumeNameKey] + options:NSVolumeEnumerationSkipHiddenVolumes]; for (NSURL* url in array) { - NSError* error = nil; - NSDictionary* dic = [url resourceValuesForKeys:@[ - NSURLVolumeNameKey - ] error:&error]; + NSString* name = nil; + [url getResourceValue:&name forKey:NSURLVolumeNameKey error:nil]; + if (name == nil) { + name = [[url path] lastPathComponent]; + } work->volumes.push_back(_volume()); _volume& v = work->volumes.back(); - v.name = _string_t([[dic objectForKey:NSURLVolumeNameKey] UTF8String]); + v.name = _string_t([name UTF8String]); v.full = std::filesystem::path(_string_t([[url path] UTF8String])); } #endif diff --git a/pkg/native/src/set_exte.hpp b/pkg/native/src/set_exte.hpp index 739f839..2ead565 100644 --- a/pkg/native/src/set_exte.hpp +++ b/pkg/native/src/set_exte.hpp @@ -13,6 +13,10 @@ void set_exte(const v8::FunctionCallbackInfo& info) } v8::Local array = info[0].As(); + if (100 < array->Length()) { + ISOLATE->ThrowException(to_string(ERROR_INVALID_ARGUMENT)); + return; + } multi_exte.clear(); diff --git a/pkg/native/test/_util.cts b/pkg/native/test/_util.cts index c71166a..4133983 100644 --- a/pkg/native/test/_util.cts +++ b/pkg/native/test/_util.cts @@ -27,3 +27,11 @@ export enum ERROR { INVALID_T_PATH = "traversal paths not allowed", FAILED = "failed", } + +export async function readStream(stream: NodeJS.ReadableStream): Promise { + const chunks: Buffer[] = [] + for await (const chunk of stream) { + chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk as string)) + } + return Buffer.concat(chunks) +} diff --git a/pkg/native/test/test_arc.cts b/pkg/native/test/test_arc.cts new file mode 100644 index 0000000..9942c9a --- /dev/null +++ b/pkg/native/test/test_arc.cts @@ -0,0 +1,91 @@ +import * as native from "@eyna/native/lib/browser.ts" + +import assert from "node:assert" +import path from "node:path/posix" + +import { TEST } from "./_util.cts" + +const main = async () => { + const DIR = path.join(TEST, "archive") + + if (await native.exists(DIR)) { + await native.moveToTrash(DIR) + } + await native.createDirectory(path.join(DIR)) + + await native.createFile(path.join(DIR, "arc.tar.gz")) + await native.createFile(path.join(DIR, "arc.tar.xz")) + + native.setExte([ + ".tar.gz", + ".tar.xz", + ]) + + { + const tgz = await native.getAttribute(path.join(DIR, "arc.tar.gz")) + assert.strictEqual(tgz.length, 1) + assert.strictEqual(tgz[0].file_type, 3) + assert.strictEqual(tgz[0].full, path.join(DIR, "arc.tar.gz")) + assert.strictEqual(tgz[0].base, "") + assert.strictEqual(tgz[0].rltv, path.join(DIR, "arc.tar.gz")) + assert.strictEqual(tgz[0].name, "arc.tar.gz") + assert.strictEqual(tgz[0].stem, "arc") + assert.strictEqual(tgz[0].exte, ".tar.gz") + assert.strictEqual(tgz[0].link_type, 0) + assert.strictEqual(tgz[0].link, null) + assert.strictEqual(tgz[0].size, 0n) + + const txz = await native.getAttribute(path.join(DIR, "arc.tar.xz")) + assert.strictEqual(txz.length, 1) + assert.strictEqual(txz[0].file_type, 3) + assert.strictEqual(txz[0].full, path.join(DIR, "arc.tar.xz")) + assert.strictEqual(txz[0].base, "") + assert.strictEqual(txz[0].rltv, path.join(DIR, "arc.tar.xz")) + assert.strictEqual(txz[0].name, "arc.tar.xz") + assert.strictEqual(txz[0].stem, "arc") + assert.strictEqual(txz[0].exte, ".tar.xz") + assert.strictEqual(txz[0].link_type, 0) + assert.strictEqual(txz[0].link, null) + assert.strictEqual(txz[0].size, 0n) + } + + native.setExte([]) + + { + const tgz = await native.getAttribute(path.join(DIR, "arc.tar.gz")) + assert.strictEqual(tgz.length, 1) + assert.strictEqual(tgz[0].file_type, 3) + assert.strictEqual(tgz[0].full, path.join(DIR, "arc.tar.gz")) + assert.strictEqual(tgz[0].base, "") + assert.strictEqual(tgz[0].rltv, path.join(DIR, "arc.tar.gz")) + assert.strictEqual(tgz[0].name, "arc.tar.gz") + assert.strictEqual(tgz[0].stem, "arc.tar") + assert.strictEqual(tgz[0].exte, ".gz") + assert.strictEqual(tgz[0].link_type, 0) + assert.strictEqual(tgz[0].link, null) + assert.strictEqual(tgz[0].size, 0n) + + const txz = await native.getAttribute(path.join(DIR, "arc.tar.xz")) + assert.strictEqual(txz.length, 1) + assert.strictEqual(txz[0].file_type, 3) + assert.strictEqual(txz[0].full, path.join(DIR, "arc.tar.xz")) + assert.strictEqual(txz[0].base, "") + assert.strictEqual(txz[0].rltv, path.join(DIR, "arc.tar.xz")) + assert.strictEqual(txz[0].name, "arc.tar.xz") + assert.strictEqual(txz[0].stem, "arc.tar") + assert.strictEqual(txz[0].exte, ".xz") + assert.strictEqual(txz[0].link_type, 0) + assert.strictEqual(txz[0].link, null) + assert.strictEqual(txz[0].size, 0n) + } +} + +try { + main().then(() => { + console.log("") + console.log("done (test_arc)") + }) +} +catch (err) { + console.error(err) +} diff --git a/pkg/native/test/test_arc_tar.cts b/pkg/native/test/test_arc_tar.cts index 02a7328..28ad6af 100644 --- a/pkg/native/test/test_arc_tar.cts +++ b/pkg/native/test/test_arc_tar.cts @@ -3,7 +3,7 @@ import * as native from "@eyna/native/lib/browser.ts" import assert from "node:assert" import path from "node:path/posix" -import { ERROR } from "./_util.cts" +import { ERROR, readStream } from "./_util.cts" const main = async () => { const TAR = path.join(import.meta.dirname ?? __dirname, "fixtures", "test.tar") @@ -96,6 +96,33 @@ const main = async () => { ) } + { + const entry1 = await native.getArchiveEntry(TAR, "file.txt") + assert.strictEqual(entry1.size, 8n) + const buf1 = await readStream(entry1.reader) + assert.strictEqual(buf1.toString(), "file.txt") + + const entry2 = await native.getArchiveEntry(TAR, "dir/file.txt") + assert.strictEqual(entry2.size, 12n) + const buf2 = await readStream(entry2.reader) + assert.strictEqual(buf2.toString(), "dir/file.txt") + + const entry3 = await native.getArchiveEntry(TAR, "🍋") + assert.strictEqual(entry3.size, 4n) + const buf3 = await readStream(entry3.reader) + assert.strictEqual(buf3.toString(), "🍋") + + const entry4 = await native.getArchiveEntry(TAR, "🍋‍🟩") + assert.strictEqual(entry4.size, 11n) + const buf4 = await readStream(entry4.reader) + assert.strictEqual(buf4.toString(), "🍋‍🟩") + + const entry5 = await native.getArchiveEntry(TAR, "🍋‍🟩", 7n) + assert.strictEqual(entry5.size, 11n) + const buf5 = await readStream(entry5.reader) + assert.strictEqual(buf5.toString(), "🟩") + } + for (const error_path of [".", "./", "..", "../"]) { await assert.rejects( async () => await native.getArchive(TAR, error_path), diff --git a/pkg/native/test/test_arc_tgz.cts b/pkg/native/test/test_arc_tgz.cts index b9a90c7..43daa67 100644 --- a/pkg/native/test/test_arc_tgz.cts +++ b/pkg/native/test/test_arc_tgz.cts @@ -3,7 +3,7 @@ import * as native from "@eyna/native/lib/browser.ts" import assert from "node:assert" import path from "node:path/posix" -import { ERROR } from "./_util.cts" +import { ERROR, readStream } from "./_util.cts" const main = async () => { const TGZ = path.join(import.meta.dirname ?? __dirname, "fixtures", "test.tgz") @@ -96,6 +96,33 @@ const main = async () => { ) } + { + const entry1 = await native.getArchiveEntry(TGZ, "file.txt") + assert.strictEqual(entry1.size, 8n) + const buf1 = await readStream(entry1.reader) + assert.strictEqual(buf1.toString(), "file.txt") + + const entry2 = await native.getArchiveEntry(TGZ, "dir/file.txt") + assert.strictEqual(entry2.size, 12n) + const buf2 = await readStream(entry2.reader) + assert.strictEqual(buf2.toString(), "dir/file.txt") + + const entry3 = await native.getArchiveEntry(TGZ, "🍋") + assert.strictEqual(entry3.size, 4n) + const buf3 = await readStream(entry3.reader) + assert.strictEqual(buf3.toString(), "🍋") + + const entry4 = await native.getArchiveEntry(TGZ, "🍋‍🟩") + assert.strictEqual(entry4.size, 11n) + const buf4 = await readStream(entry4.reader) + assert.strictEqual(buf4.toString(), "🍋‍🟩") + + const entry5 = await native.getArchiveEntry(TGZ, "🍋‍🟩", 7n) + assert.strictEqual(entry5.size, 11n) + const buf5 = await readStream(entry5.reader) + assert.strictEqual(buf5.toString(), "🟩") + } + for (const error_path of [".", "./", "..", "../"]) { await assert.rejects( async () => await native.getArchive(TGZ, error_path), diff --git a/pkg/native/test/test_arc_zip.cts b/pkg/native/test/test_arc_zip.cts index e186abf..9cab339 100644 --- a/pkg/native/test/test_arc_zip.cts +++ b/pkg/native/test/test_arc_zip.cts @@ -3,7 +3,7 @@ import * as native from "@eyna/native/lib/browser.ts" import assert from "node:assert" import path from "node:path/posix" -import { ERROR } from "./_util.cts" +import { ERROR, readStream } from "./_util.cts" const main = async () => { const ZIP = path.join(import.meta.dirname ?? __dirname, "fixtures", "test.zip") @@ -96,6 +96,33 @@ const main = async () => { ) } + { + const entry1 = await native.getArchiveEntry(ZIP, "file.txt") + assert.strictEqual(entry1.size, 8n) + const buf1 = await readStream(entry1.reader) + assert.strictEqual(buf1.toString(), "file.txt") + + const entry2 = await native.getArchiveEntry(ZIP, "dir/file.txt") + assert.strictEqual(entry2.size, 12n) + const buf2 = await readStream(entry2.reader) + assert.strictEqual(buf2.toString(), "dir/file.txt") + + const entry3 = await native.getArchiveEntry(ZIP, "🍋") + assert.strictEqual(entry3.size, 4n) + const buf3 = await readStream(entry3.reader) + assert.strictEqual(buf3.toString(), "🍋") + + const entry4 = await native.getArchiveEntry(ZIP, "🍋‍🟩") + assert.strictEqual(entry4.size, 11n) + const buf4 = await readStream(entry4.reader) + assert.strictEqual(buf4.toString(), "🍋‍🟩") + + const entry5 = await native.getArchiveEntry(ZIP, "🍋‍🟩", 7n) + assert.strictEqual(entry5.size, 11n) + const buf5 = await readStream(entry5.reader) + assert.strictEqual(buf5.toString(), "🟩") + } + for (const error_path of [".", "./", "..", "../"]) { await assert.rejects( async () => await native.getArchive(ZIP, error_path), diff --git a/pkg/native/test/test_compare.cts b/pkg/native/test/test_compare.cts index eb9f2bd..3a13fa9 100644 --- a/pkg/native/test/test_compare.cts +++ b/pkg/native/test/test_compare.cts @@ -4,7 +4,7 @@ import assert from "node:assert" import fs from "node:fs/promises" import path from "node:path/posix" -import { TEST } from "./_util.cts" +import { ERROR, TEST } from "./_util.cts" const main = async () => { const DIR = path.join(TEST, "compare") @@ -25,7 +25,39 @@ const main = async () => { await fs.writeFile(path.join(DIR, "file2"), "TEST") assert.strictEqual(await native.compare(path.join(DIR, "file1"), path.join(DIR, "file2")), false) - await native.moveToTrash(path.join(DIR)) + await assert.rejects( + async () => await native.compare(path.join(DIR, "file1"), path.join(DIR, "file1")), + (err) => err === ERROR.FAILED, + ) + + await assert.rejects( + async () => await native.compare(path.join(DIR, "file1"), DIR), + (err) => err === ERROR.FAILED, + ) + await assert.rejects( + async () => await native.compare(DIR, path.join(DIR, "file1")), + (err) => err === ERROR.FAILED, + ) + + await assert.rejects( + async () => await native.compare(path.join(DIR, "file1"), path.join(DIR, "test-not-exist-file")), + (err) => err === ERROR.FAILED, + ) + await assert.rejects( + async () => await native.compare(path.join(DIR, "test-not-exist-file"), path.join(DIR, "file1")), + (err) => err === ERROR.FAILED, + ) + + for (const error_path of ["", ".", "./", "..", "../"]) { + await assert.rejects( + async () => await native.compare(path.join(DIR, "file1"), error_path), + (err) => err === ERROR.INVALID_PATH, + ) + await assert.rejects( + async () => await native.compare(error_path, path.join(DIR, "file1")), + (err) => err === ERROR.INVALID_PATH, + ) + } } try { diff --git a/pkg/native/test/test_depth.cts b/pkg/native/test/test_depth.cts new file mode 100644 index 0000000..bd1c9ca --- /dev/null +++ b/pkg/native/test/test_depth.cts @@ -0,0 +1,114 @@ +import * as native from "@eyna/native/lib/browser.ts" + +import assert from "node:assert" +import fs from "node:fs/promises" +import path from "node:path/posix" + +import { ERROR, TEST } from "./_util.cts" + +const main = async () => { + const DIR = path.join(TEST, "depth") + + if (await native.exists(DIR)) { + await native.moveToTrash(DIR) + } + await native.createDirectory(path.join(DIR)) + + await native.createDirectory(path.join(DIR, "depth_0", "depth_1", "depth_2", "depth_3", "depth_4")) + await native.createFile(path.join(DIR, "01")) + await native.createFile(path.join(DIR, "02")) + await native.createFile(path.join(DIR, "depth_0", "01")) + await native.createFile(path.join(DIR, "depth_0", "02")) + await native.createFile(path.join(DIR, "depth_0", "depth_1", "01")) + await native.createFile(path.join(DIR, "depth_0", "depth_1", "02")) + await native.createFile(path.join(DIR, "depth_0", "depth_1", "depth_2", "01")) + await native.createFile(path.join(DIR, "depth_0", "depth_1", "depth_2", "02")) + await native.createFile(path.join(DIR, "depth_0", "depth_1", "depth_2", "depth_3", "01")) + await native.createFile(path.join(DIR, "depth_0", "depth_1", "depth_2", "depth_3", "02")) + await assert.rejects( + async () => + await native.createFile(path.join(DIR, "depth_0", "depth_1", "depth_2", "depth_3", "depth_4", "depth_5", "01")), + (err) => err === ERROR.FAILED, + ) + await assert.rejects( + async () => + await native.createFile(path.join(DIR, "depth_0", "depth_1", "depth_2", "depth_3", "depth_4", "depth_5", "02")), + (err) => err === ERROR.FAILED, + ) + + { + const d1 = await native.getDirectory(DIR, "", native.Sort.DepthFirst, 0) + const d2 = await native.getDirectory(DIR, "", native.Sort.DepthFirst, 0) + assert.deepEqual(d1.list.length, 3) + assert.deepEqual(d1.s, 0n) + assert.deepEqual(d1.d, 1) + assert.deepEqual(d1.f, 2) + assert.deepEqual(d1.e, 0) + assert.deepStrictEqual(d1, d2) + } + + { + const d1 = await native.getDirectory(DIR, "", native.Sort.DepthFirst, 1) + const d2 = await native.getDirectory(DIR, "", native.Sort.DepthFirst, 1) + assert.deepEqual(d1.list.length, 6) + assert.deepEqual(d1.s, 0n) + assert.deepEqual(d1.d, 2) + assert.deepEqual(d1.f, 4) + assert.deepEqual(d1.e, 0) + assert.deepStrictEqual(d1, d2) + } + + { + const d1 = await native.getDirectory(DIR, "", native.Sort.DepthFirst, 2) + const d2 = await native.getDirectory(DIR + "/", "", native.Sort.DepthFirst, 2) + assert.deepEqual(d1.full, DIR) + assert.deepEqual(d1.base, "") + assert.deepEqual(d1.list.length, 9) + assert.deepEqual(d1.list[0].rltv, path.join(DIR, "01")) + assert.deepEqual(d1.list[1].rltv, path.join(DIR, "02")) + assert.deepEqual(d1.list[2].rltv, path.join(DIR, "depth_0")) + assert.deepEqual(d1.list[3].rltv, path.join(DIR, "depth_0", "01")) + assert.deepEqual(d1.list[4].rltv, path.join(DIR, "depth_0", "02")) + assert.deepEqual(d1.list[5].rltv, path.join(DIR, "depth_0", "depth_1")) + assert.deepEqual(d1.list[6].rltv, path.join(DIR, "depth_0", "depth_1", "01")) + assert.deepEqual(d1.list[7].rltv, path.join(DIR, "depth_0", "depth_1", "02")) + assert.deepEqual(d1.list[8].rltv, path.join(DIR, "depth_0", "depth_1", "depth_2")) + assert.deepEqual(d1.s, 0n) + assert.deepEqual(d1.d, 3) + assert.deepEqual(d1.f, 6) + assert.deepEqual(d1.e, 0) + assert.deepStrictEqual(d1, d2) + } + + { + const d1 = await native.getDirectory(DIR, "", native.Sort.ShallowFirst, 2) + const d2 = await native.getDirectory(DIR + "/", "", native.Sort.ShallowFirst, 2) + assert.deepEqual(d1.full, DIR) + assert.deepEqual(d1.base, "") + assert.deepEqual(d1.list.length, 9) + assert.deepEqual(d1.list[0].rltv, path.join(DIR, "01")) + assert.deepEqual(d1.list[1].rltv, path.join(DIR, "02")) + assert.deepEqual(d1.list[2].rltv, path.join(DIR, "depth_0", "01")) + assert.deepEqual(d1.list[3].rltv, path.join(DIR, "depth_0", "02")) + assert.deepEqual(d1.list[4].rltv, path.join(DIR, "depth_0", "depth_1", "01")) + assert.deepEqual(d1.list[5].rltv, path.join(DIR, "depth_0", "depth_1", "02")) + assert.deepEqual(d1.list[6].rltv, path.join(DIR, "depth_0", "depth_1", "depth_2")) + assert.deepEqual(d1.list[7].rltv, path.join(DIR, "depth_0", "depth_1")) + assert.deepEqual(d1.list[8].rltv, path.join(DIR, "depth_0")) + assert.deepEqual(d1.s, 0n) + assert.deepEqual(d1.d, 3) + assert.deepEqual(d1.f, 6) + assert.deepEqual(d1.e, 0) + assert.deepStrictEqual(d1, d2) + } +} + +try { + main().then(() => { + console.log("") + console.log("done (test_compare)") + }) +} +catch (err) { + console.error(err) +} diff --git a/pkg/native/types/_type.d.ts b/pkg/native/types/_type.d.ts index 3c117af..bf0b26e 100644 --- a/pkg/native/types/_type.d.ts +++ b/pkg/native/types/_type.d.ts @@ -4,7 +4,7 @@ declare namespace Type { ShallowFirst = 1, } enum FileType { - HomeUser = -2, + Favorite = -2, Drive = -1, None = 0, Directory = 1, diff --git a/scripts/postinstall.mts b/scripts/postinstall.mts index 52c3385..96d66dd 100644 --- a/scripts/postinstall.mts +++ b/scripts/postinstall.mts @@ -1,7 +1,7 @@ import module from "node:module" import path from "node:path" -import { install } from "@eyna/lib/scripts/_vcpkg.mts" +import { install, status } from "@eyna/lib/scripts/_vcpkg.mts" import { headers } from "./_headers.mts" const __top = path.join(import.meta.dirname, "..") @@ -18,6 +18,13 @@ try { console.log(`\x1b[34mpostinstall vcpkg-install\x1b[0m`) await install("inherit") + console.log("") + const packages = await status() + for (const [name, version] of Object.entries(packages)) { + console.log(`\x1b[36m${name}: ${version}\x1b[0m`) + } + console.log("") + console.log(`\x1b[34mpostinstall complete\x1b[0m`) } catch (err) { diff --git a/src/app/itcss/_5_objects.filer.styl b/src/app/itcss/_5_objects.filer.styl index 97a0925..b35001a 100644 --- a/src/app/itcss/_5_objects.filer.styl +++ b/src/app/itcss/_5_objects.filer.styl @@ -14,7 +14,7 @@ _scroll_width = 6px color: _blue .c-drive color: _white -.c-homeuser +.c-favorite color: _white .c-file color: _white diff --git a/src/browser/Root.ts b/src/browser/Root.ts index 962c0fa..9e6c9d3 100644 --- a/src/browser/Root.ts +++ b/src/browser/Root.ts @@ -19,7 +19,6 @@ import { SystemFragment } from "@/browser/fragment/system/SystemFragment" import { ViewerFragment } from "@/browser/fragment/viewer/ViewerFragment" import { Protocol } from "@/browser/Protocol" -// @ts-ignore import drugBase64 from "@/app/asset/drug.png" const drug = electron.nativeImage.createFromDataURL(`data:image/png;base64,${drugBase64}`) diff --git a/src/browser/conf/SysConfig.ts b/src/browser/conf/SysConfig.ts index cd26442..332814e 100644 --- a/src/browser/conf/SysConfig.ts +++ b/src/browser/conf/SysConfig.ts @@ -1,10 +1,12 @@ import { Abstract } from "@/browser/conf/Abstract" import * as Util from "@eyna/util" +import { Path } from "../core/Path" type FileFormat = { styleFontFamily: string styleFontSize: number styleLineHeight: number + favorites: { name: string; path: string }[] } class Sys extends Abstract { @@ -18,6 +20,24 @@ class Sys extends Abstract { if (!Util.isNumber(this.data.styleLineHeight) || this.data.styleLineHeight <= 0) { throw new Error("styleLineHeight must be positive") } + if (!Util.isArray(this.data.favorites)) { + throw new Error("favorites must be an array") + } + for (const f of this.data.favorites) { + if (!Util.isString(f.name) || f.name.length === 0) { + throw new Error("favorites.name must be non-empty string") + } + if (!Util.isString(f.path) || f.path.length === 0) { + throw new Error("favorites.path must be non-empty string") + } + + if (f.path === "~") { + f.path = Path.home() + } + else if (f.path.startsWith("~/")) { + f.path = Path.home(f.path.slice(2)) + } + } } } diff --git a/src/browser/core/Dir.ts b/src/browser/core/Dir.ts index c55b3d6..42b388a 100644 --- a/src/browser/core/Dir.ts +++ b/src/browser/core/Dir.ts @@ -3,8 +3,8 @@ import * as perf_hooks from "node:perf_hooks" import * as Native from "@eyna/native/lib/browser" import * as Util from "@eyna/util" +import { SysConfig } from "@/browser/conf/SysConfig" import { Location } from "@/browser/core/Location" -import { Path } from "@/browser/core/Path" export class Dir { static readonly HOME: string = "home" @@ -34,7 +34,7 @@ export class Dir { if (Location.isHome(location)) { this.dp = 0 this.rg = null - const st = [_attr(Native.FileType.HomeUser, Dir.HOME, Dir.HOME)] + const st = [_attr(Native.FileType.Favorite, Dir.HOME, Dir.HOME)] Native.getVolume().then( (vol: Native.Volume[]) => { _log(location.frn.split("\0"), "volume", `${(perf_hooks.performance.now() - _time).toFixed(3)}ms`) @@ -42,7 +42,9 @@ export class Dir { for (const v of vol) { ls.push([_attr(Native.FileType.Drive, v.full, v.name)]) } - ls.push([_attr(Native.FileType.HomeUser, Path.home(), "user")]) + for (const f of SysConfig.data.favorites) { + ls.push([_attr(Native.FileType.Favorite, f.path, f.name)]) + } cb(location.frn, st, ls, 0) }, ) diff --git a/src/browser/fragment/filer/FilerFragment.ts b/src/browser/fragment/filer/FilerFragment.ts index 2852d08..54ab33c 100644 --- a/src/browser/fragment/filer/FilerFragment.ts +++ b/src/browser/fragment/filer/FilerFragment.ts @@ -131,7 +131,7 @@ export class FilerFragment extends AbstractFragment { return Promise.reject("stop chain") } active.cursorUp() - active.scroll() + active.adjustScroll() active.sendCursor() return Promise.resolve() }) @@ -143,7 +143,7 @@ export class FilerFragment extends AbstractFragment { return Promise.reject("stop chain") } active.cursorUp(active.mv) - active.scroll() + active.adjustScroll() active.sendCursor() return Promise.resolve() }) @@ -155,7 +155,7 @@ export class FilerFragment extends AbstractFragment { return Promise.reject("stop chain") } active.cursorDown() - active.scroll() + active.adjustScroll() active.sendCursor() return Promise.resolve() }) @@ -167,7 +167,7 @@ export class FilerFragment extends AbstractFragment { return Promise.reject("stop chain") } active.cursorDown(active.mv) - active.scroll() + active.adjustScroll() active.sendCursor() return Promise.resolve() }) @@ -250,9 +250,10 @@ export class FilerFragment extends AbstractFragment { false, ) ) { - active.scroll() + active.adjustScroll() active.sendScan() active.sendAttrAll() + active.sendMarkAll() } resolve() }) @@ -274,7 +275,7 @@ export class FilerFragment extends AbstractFragment { if (trgt.file_type === Native.FileType.File) { if (Location.isFile(active.location)) { if (await active.sendChange(Location.toArch(trgt.full, ""), 0, null, null, false)) { - active.scroll() + active.adjustScroll() active.sendScan() active.sendAttrAll() } @@ -372,26 +373,26 @@ export class FilerFragment extends AbstractFragment { return } // drive - // homeuser + // favorite // directory // link(symbolic or junction) -> directory if ( attr.file_type === Native.FileType.Drive - || attr.file_type === Native.FileType.HomeUser + || attr.file_type === Native.FileType.Favorite || attr.file_type === Native.FileType.Directory || attr.file_type === Native.FileType.Link && trgt.file_type === Native.FileType.Directory ) { if (Location.isHome(active.location) || Location.isFile(active.location)) { if (await active.sendChange(Location.toFile(attr.full), 0, null, null, false)) { - active.scroll() + active.adjustScroll() active.sendScan() active.sendAttrAll() } } else if (Location.isArch(active.location)) { if (await active.sendChange(Location.toArch(active.location.path, attr.full), 0, null, null, false)) { - active.scroll() + active.adjustScroll() active.sendScan() active.sendAttrAll() } @@ -405,7 +406,7 @@ export class FilerFragment extends AbstractFragment { ) { if (Location.isFile(active.location)) { if (await active.sendChange(Location.toFile(trgt.full), 0, null, null, false)) { - active.scroll() + active.adjustScroll() active.sendScan() active.sendAttrAll() } @@ -421,7 +422,7 @@ export class FilerFragment extends AbstractFragment { if (Location.isFile(active.location)) { if (Conf.ARCHIVE_EXTE.test(trgt.exte)) { if (await active.sendChange(Location.toArch(trgt.full, ""), 0, null, null, false)) { - active.scroll() + active.adjustScroll() active.sendScan() active.sendAttrAll() } @@ -530,7 +531,7 @@ export class FilerFragment extends AbstractFragment { return new Promise(async (resolve, _reject) => { const next = Location.updir(active.location.frn) if (await active.sendChange(next.frn, 0, null, next.anchor ?? null, false)) { - active.scroll() + active.adjustScroll() active.sendScan() active.sendAttrAll() } @@ -540,7 +541,7 @@ export class FilerFragment extends AbstractFragment { .on2("list.targetequal", (active, target) => { return new Promise(async (resolve, _reject) => { if (await target.sendChange(active.location.frn, 0, null, null, false)) { - target.scroll() + target.adjustScroll() target.sendScan() target.sendAttrAll() } @@ -556,18 +557,18 @@ export class FilerFragment extends AbstractFragment { return } // drive - // homeuser + // favorite // directory // link(symbolic or junction) -> directory if ( attr.file_type === Native.FileType.Drive - || attr.file_type === Native.FileType.HomeUser + || attr.file_type === Native.FileType.Favorite || attr.file_type === Native.FileType.Directory || attr.file_type === Native.FileType.Link && trgt.file_type === Native.FileType.Directory ) { if (await target.sendChange(Location.toFile(attr.full), 0, null, null, false)) { - target.scroll() + target.adjustScroll() target.sendScan() target.sendAttrAll() } @@ -579,7 +580,7 @@ export class FilerFragment extends AbstractFragment { && trgt.file_type === Native.FileType.Directory ) { if (await target.sendChange(Location.toFile(attr.full), 0, null, null, false)) { - target.scroll() + target.adjustScroll() target.sendScan() target.sendAttrAll() } @@ -632,7 +633,7 @@ export class FilerFragment extends AbstractFragment { continue } active.data.cursor = i - active.scroll() + active.adjustScroll() active.sendCursor() return Promise.resolve() } @@ -657,7 +658,7 @@ export class FilerFragment extends AbstractFragment { continue } active.data.cursor = i - active.scroll() + active.adjustScroll() active.sendCursor() return Promise.resolve() } diff --git a/src/browser/fragment/filer/FilerManager.ts b/src/browser/fragment/filer/FilerManager.ts index 1c8c642..1835a60 100644 --- a/src/browser/fragment/filer/FilerManager.ts +++ b/src/browser/fragment/filer/FilerManager.ts @@ -51,14 +51,14 @@ export class FilerManager { } else { this.data.watch = 1 - root.send(Bridge.List.Watch.CH, this.id, { watch: this.data.watch }) + this.sendWatch() } } } exit() { this.watch_run = false - Native.unwatch(this.id) + this.unwatch() } mounted(screenSize: number, contentsSize: number): Promise { @@ -72,7 +72,7 @@ export class FilerManager { resized(h: number) { if (this.sc.screenSize !== h) { this.sc.screenSize = h - this.scroll() + this.adjustScroll() this.sendCursor() } } @@ -116,9 +116,10 @@ export class FilerManager { } update(forceMarkClear: boolean): Promise { + _log("update", this.id, { frn: this.location.frn.split("\0"), forceMarkClear }) return new Promise(async (resolve, _reject) => { if (await this.sendChange(this.location.frn, 0, null, this.data.cursor, forceMarkClear)) { - this.scroll() + this.adjustScroll() this.sendScan() this.sendAttrAll() this.sendMarkAll() @@ -127,7 +128,7 @@ export class FilerManager { }) } - scroll() { + adjustScroll() { const contPos = this.sc.contentsSize * this.data.cursor const drawPos = contPos - this.sc.contentsPosition const margin = Math.min(this.sc.contentsSize, (this.sc.screenSize - this.sc.contentsSize) / 2) // スクロール時に選択位置が端でない限りマージンを設ける @@ -168,6 +169,26 @@ export class FilerManager { return 0 } + private unwatch() { + _log("unwatch", this.id) + Native.unwatch(this.id) + } + + private watch(next: Location.Data, create: number, dp: number) { + if (Location.isFile(next)) { + _log("watch", this.id, { path: next.path }) + Native.watch(this.id, next.path, (_id, depth, _abstract) => { + _log("watch_callback", this.id, { depth, abstract: _abstract }) + if (create !== this.data.create || dp < depth) { + return + } + if (this.watch_queue.length === 0 || this.watch_queue.at(-1) !== next.frn) { + this.watch_queue.push(next.frn) + } + }) + } + } + private sendTitle(next: Location.Data | null = null) { if (this.data.status !== Bridge.Status.Active) { return @@ -234,17 +255,8 @@ export class FilerManager { this.data.elapse = 0 this.data.search = true - Native.unwatch(this.id) - if (Location.isFile(next)) { - Native.watch(this.id, next.path, (_id, depth, _abstract) => { - if (create !== this.data.create || dp < depth) { - return - } - if (this.watch_queue.length === 0 || this.watch_queue[this.watch_queue.length - 1] !== next.frn) { - this.watch_queue.push(next.frn) - } - }) - } + this.unwatch() + this.watch(next, create, dp) this.sendTitle(next) root.send( @@ -387,4 +399,18 @@ export class FilerManager { }, ) } + + sendWatch() { + root.send( + Bridge.List.Watch.CH, + this.id, + { + watch: this.data.watch, + }, + ) + } +} + +function _log(...args: any) { + console.log(`\u001b[36m[filer]\u001b[0m`, ...args) } diff --git a/src/renderer/fragment/filer/CellComponent.ts b/src/renderer/fragment/filer/CellComponent.ts index 66baafc..97f9521 100644 --- a/src/renderer/fragment/filer/CellComponent.ts +++ b/src/renderer/fragment/filer/CellComponent.ts @@ -153,8 +153,8 @@ const attr = vue.defineComponent({ else if (attr.value.one?.file_type === Native.FileType.Drive) { return "c-drive" } - else if (attr.value.one?.file_type === Native.FileType.HomeUser) { - return "c-homeuser" + else if (attr.value.one?.file_type === Native.FileType.Favorite) { + return "c-favorite" } else if (attr.value.one?.file_type === Native.FileType.Special) { return "c-special" @@ -214,7 +214,7 @@ const attr = vue.defineComponent({ const date = vue.computed((): { date: string; time: string } | undefined => { if ( - attr.value.one?.file_type === Native.FileType.Drive || attr.value.one?.file_type === Native.FileType.HomeUser + attr.value.one?.file_type === Native.FileType.Drive || attr.value.one?.file_type === Native.FileType.Favorite ) { return undefined } diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..48c2234 --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,5 @@ +// esbuild loader: { ".png": "base64" } +declare module "*.png" { + const base64: string + export default base64 +} diff --git a/tsconfig.json b/tsconfig.json index 08c4cbb..6bcaea6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,9 @@ "./src/*", ], }, + "types": [ + "@types/node", + ], // Type Checking "alwaysStrict": true,