mirror of
https://github.com/acamarata/solar-spa.git
synced 2026-06-30 19:04:28 +00:00
refactor: code quality improvements across the board
This commit is contained in:
parent
1db4c24537
commit
f21be803fe
11 changed files with 1221 additions and 344 deletions
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
|
|
@ -8,6 +8,7 @@ on:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
name: Test (Node ${{ matrix.node-version }})
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
|
@ -30,12 +31,32 @@ jobs:
|
||||||
run: pnpm run build:ts
|
run: pnpm run build:ts
|
||||||
|
|
||||||
- name: Run tests (ESM)
|
- name: Run tests (ESM)
|
||||||
run: node test.mjs
|
run: node --test test.mjs
|
||||||
|
|
||||||
- name: Run tests (CJS)
|
- name: Run tests (CJS)
|
||||||
run: node test-cjs.cjs
|
run: node --test test-cjs.cjs
|
||||||
|
|
||||||
|
lint:
|
||||||
|
name: Lint & Format
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 10
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 24
|
||||||
|
cache: pnpm
|
||||||
|
|
||||||
|
- run: pnpm install --frozen-lockfile
|
||||||
|
- run: pnpm run lint
|
||||||
|
- run: pnpm run format:check
|
||||||
|
|
||||||
typecheck:
|
typecheck:
|
||||||
|
name: Typecheck
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
@ -53,6 +74,7 @@ jobs:
|
||||||
- run: pnpm run typecheck
|
- run: pnpm run typecheck
|
||||||
|
|
||||||
pack-check:
|
pack-check:
|
||||||
|
name: Pack Check
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
|
||||||
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -61,3 +61,9 @@ coverage/
|
||||||
# C compilation artifacts (WASM binary is pre-compiled and tracked)
|
# C compilation artifacts (WASM binary is pre-compiled and tracked)
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
|
.vscode/*
|
||||||
|
.codex/
|
||||||
|
.aider/
|
||||||
|
.aider.chat.history.md
|
||||||
|
.continue/
|
||||||
|
.gemini/
|
||||||
|
|
|
||||||
6
.prettierrc
Normal file
6
.prettierrc
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"printWidth": 100,
|
||||||
|
"tabWidth": 2
|
||||||
|
}
|
||||||
12
eslint.config.mjs
Normal file
12
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
import eslint from '@eslint/js';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
import eslintConfigPrettier from 'eslint-config-prettier';
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
eslint.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
eslintConfigPrettier,
|
||||||
|
{
|
||||||
|
ignores: ['dist/', 'node_modules/', 'test.mjs', 'test-cjs.cjs', 'wasm/', 'src/spa.c', 'src/spa.h', 'validate.mjs'],
|
||||||
|
},
|
||||||
|
);
|
||||||
17
package.json
17
package.json
|
|
@ -21,7 +21,10 @@
|
||||||
},
|
},
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"files": [
|
"files": [
|
||||||
"dist/",
|
"dist/index.cjs",
|
||||||
|
"dist/index.mjs",
|
||||||
|
"dist/index.d.ts",
|
||||||
|
"dist/index.d.mts",
|
||||||
"wasm/",
|
"wasm/",
|
||||||
"README.md",
|
"README.md",
|
||||||
"CHANGELOG.md",
|
"CHANGELOG.md",
|
||||||
|
|
@ -33,7 +36,10 @@
|
||||||
"build": "pnpm run build:wasm && pnpm run build:ts",
|
"build": "pnpm run build:wasm && pnpm run build:ts",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"pretest": "pnpm run build:ts",
|
"pretest": "pnpm run build:ts",
|
||||||
"test": "node test.mjs && node test-cjs.cjs",
|
"test": "node --test test.mjs && node --test test-cjs.cjs",
|
||||||
|
"lint": "eslint src/",
|
||||||
|
"format": "prettier --write src/",
|
||||||
|
"format:check": "prettier --check src/",
|
||||||
"validate": "node validate.mjs",
|
"validate": "node validate.mjs",
|
||||||
"prepublishOnly": "pnpm run build:ts"
|
"prepublishOnly": "pnpm run build:ts"
|
||||||
},
|
},
|
||||||
|
|
@ -67,8 +73,13 @@
|
||||||
"registry": "https://registry.npmjs.org/"
|
"registry": "https://registry.npmjs.org/"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^10.0.1",
|
||||||
"@types/node": "^25.3.0",
|
"@types/node": "^25.3.0",
|
||||||
|
"eslint": "^10.0.3",
|
||||||
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
"prettier": "^3.8.1",
|
||||||
"tsup": "^8.5.1",
|
"tsup": "^8.5.1",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3",
|
||||||
|
"typescript-eslint": "^8.56.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
733
pnpm-lock.yaml
733
pnpm-lock.yaml
|
|
@ -8,15 +8,30 @@ importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@eslint/js':
|
||||||
|
specifier: ^10.0.1
|
||||||
|
version: 10.0.1(eslint@10.0.3)
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^25.3.0
|
specifier: ^25.3.0
|
||||||
version: 25.3.0
|
version: 25.3.0
|
||||||
|
eslint:
|
||||||
|
specifier: ^10.0.3
|
||||||
|
version: 10.0.3
|
||||||
|
eslint-config-prettier:
|
||||||
|
specifier: ^10.1.8
|
||||||
|
version: 10.1.8(eslint@10.0.3)
|
||||||
|
prettier:
|
||||||
|
specifier: ^3.8.1
|
||||||
|
version: 3.8.1
|
||||||
tsup:
|
tsup:
|
||||||
specifier: ^8.5.1
|
specifier: ^8.5.1
|
||||||
version: 8.5.1(typescript@5.9.3)
|
version: 8.5.1(typescript@5.9.3)
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ^5.9.3
|
specifier: ^5.9.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
|
typescript-eslint:
|
||||||
|
specifier: ^8.56.1
|
||||||
|
version: 8.56.1(eslint@10.0.3)(typescript@5.9.3)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
|
|
@ -176,6 +191,61 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@eslint-community/eslint-utils@4.9.1':
|
||||||
|
resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==}
|
||||||
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
||||||
|
|
||||||
|
'@eslint-community/regexpp@4.12.2':
|
||||||
|
resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
|
||||||
|
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
||||||
|
|
||||||
|
'@eslint/config-array@0.23.3':
|
||||||
|
resolution: {integrity: sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
|
'@eslint/config-helpers@0.5.3':
|
||||||
|
resolution: {integrity: sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
|
'@eslint/core@1.1.1':
|
||||||
|
resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
|
'@eslint/js@10.0.1':
|
||||||
|
resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^10.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
eslint:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@eslint/object-schema@3.0.3':
|
||||||
|
resolution: {integrity: sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
|
'@eslint/plugin-kit@0.6.1':
|
||||||
|
resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
|
'@humanfs/core@0.19.1':
|
||||||
|
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||||
|
engines: {node: '>=18.18.0'}
|
||||||
|
|
||||||
|
'@humanfs/node@0.16.7':
|
||||||
|
resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==}
|
||||||
|
engines: {node: '>=18.18.0'}
|
||||||
|
|
||||||
|
'@humanwhocodes/module-importer@1.0.1':
|
||||||
|
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
|
||||||
|
engines: {node: '>=12.22'}
|
||||||
|
|
||||||
|
'@humanwhocodes/retry@0.4.3':
|
||||||
|
resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==}
|
||||||
|
engines: {node: '>=18.18'}
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.13':
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
|
||||||
|
|
||||||
|
|
@ -327,20 +397,101 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@types/esrecurse@4.3.1':
|
||||||
|
resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==}
|
||||||
|
|
||||||
'@types/estree@1.0.8':
|
'@types/estree@1.0.8':
|
||||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
|
'@types/json-schema@7.0.15':
|
||||||
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
'@types/node@25.3.0':
|
'@types/node@25.3.0':
|
||||||
resolution: {integrity: sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==}
|
resolution: {integrity: sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==}
|
||||||
|
|
||||||
|
'@typescript-eslint/eslint-plugin@8.56.1':
|
||||||
|
resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
'@typescript-eslint/parser': ^8.56.1
|
||||||
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
|
typescript: '>=4.8.4 <6.0.0'
|
||||||
|
|
||||||
|
'@typescript-eslint/parser@8.56.1':
|
||||||
|
resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
|
typescript: '>=4.8.4 <6.0.0'
|
||||||
|
|
||||||
|
'@typescript-eslint/project-service@8.56.1':
|
||||||
|
resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '>=4.8.4 <6.0.0'
|
||||||
|
|
||||||
|
'@typescript-eslint/scope-manager@8.56.1':
|
||||||
|
resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
|
'@typescript-eslint/tsconfig-utils@8.56.1':
|
||||||
|
resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '>=4.8.4 <6.0.0'
|
||||||
|
|
||||||
|
'@typescript-eslint/type-utils@8.56.1':
|
||||||
|
resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
|
typescript: '>=4.8.4 <6.0.0'
|
||||||
|
|
||||||
|
'@typescript-eslint/types@8.56.1':
|
||||||
|
resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
|
'@typescript-eslint/typescript-estree@8.56.1':
|
||||||
|
resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '>=4.8.4 <6.0.0'
|
||||||
|
|
||||||
|
'@typescript-eslint/utils@8.56.1':
|
||||||
|
resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
|
typescript: '>=4.8.4 <6.0.0'
|
||||||
|
|
||||||
|
'@typescript-eslint/visitor-keys@8.56.1':
|
||||||
|
resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
|
acorn-jsx@5.3.2:
|
||||||
|
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||||
|
peerDependencies:
|
||||||
|
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||||
|
|
||||||
acorn@8.16.0:
|
acorn@8.16.0:
|
||||||
resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
|
resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
ajv@6.14.0:
|
||||||
|
resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==}
|
||||||
|
|
||||||
any-promise@1.3.0:
|
any-promise@1.3.0:
|
||||||
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
|
||||||
|
|
||||||
|
balanced-match@4.0.4:
|
||||||
|
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
|
||||||
|
engines: {node: 18 || 20 || >=22}
|
||||||
|
|
||||||
|
brace-expansion@5.0.4:
|
||||||
|
resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==}
|
||||||
|
engines: {node: 18 || 20 || >=22}
|
||||||
|
|
||||||
bundle-require@5.1.0:
|
bundle-require@5.1.0:
|
||||||
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
|
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
|
@ -366,6 +517,10 @@ packages:
|
||||||
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
|
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
|
||||||
engines: {node: ^14.18.0 || >=16.10.0}
|
engines: {node: ^14.18.0 || >=16.10.0}
|
||||||
|
|
||||||
|
cross-spawn@7.0.6:
|
||||||
|
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
debug@4.4.3:
|
debug@4.4.3:
|
||||||
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
||||||
engines: {node: '>=6.0'}
|
engines: {node: '>=6.0'}
|
||||||
|
|
@ -375,11 +530,75 @@ packages:
|
||||||
supports-color:
|
supports-color:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
deep-is@0.1.4:
|
||||||
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
|
|
||||||
esbuild@0.27.3:
|
esbuild@0.27.3:
|
||||||
resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
|
resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
escape-string-regexp@4.0.0:
|
||||||
|
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
eslint-config-prettier@10.1.8:
|
||||||
|
resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
eslint: '>=7.0.0'
|
||||||
|
|
||||||
|
eslint-scope@9.1.2:
|
||||||
|
resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
|
eslint-visitor-keys@3.4.3:
|
||||||
|
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
|
||||||
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
|
||||||
|
eslint-visitor-keys@5.0.1:
|
||||||
|
resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
|
eslint@10.0.3:
|
||||||
|
resolution: {integrity: sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
jiti: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
jiti:
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
espree@11.2.0:
|
||||||
|
resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==}
|
||||||
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||||
|
|
||||||
|
esquery@1.7.0:
|
||||||
|
resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==}
|
||||||
|
engines: {node: '>=0.10'}
|
||||||
|
|
||||||
|
esrecurse@4.3.0:
|
||||||
|
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
|
||||||
|
estraverse@5.3.0:
|
||||||
|
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
|
||||||
|
esutils@2.0.3:
|
||||||
|
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
fast-deep-equal@3.1.3:
|
||||||
|
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||||
|
|
||||||
|
fast-json-stable-stringify@2.1.0:
|
||||||
|
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
|
||||||
|
|
||||||
|
fast-levenshtein@2.0.6:
|
||||||
|
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
|
||||||
|
|
||||||
fdir@6.5.0:
|
fdir@6.5.0:
|
||||||
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
@ -389,18 +608,76 @@ packages:
|
||||||
picomatch:
|
picomatch:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
file-entry-cache@8.0.0:
|
||||||
|
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
||||||
|
engines: {node: '>=16.0.0'}
|
||||||
|
|
||||||
|
find-up@5.0.0:
|
||||||
|
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
fix-dts-default-cjs-exports@1.0.1:
|
fix-dts-default-cjs-exports@1.0.1:
|
||||||
resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==}
|
resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==}
|
||||||
|
|
||||||
|
flat-cache@4.0.1:
|
||||||
|
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
|
flatted@3.3.4:
|
||||||
|
resolution: {integrity: sha512-3+mMldrTAPdta5kjX2G2J7iX4zxtnwpdA8Tr2ZSjkyPSanvbZAcy6flmtnXbEybHrDcU9641lxrMfFuUxVz9vA==}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
|
glob-parent@6.0.2:
|
||||||
|
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
|
||||||
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
|
ignore@5.3.2:
|
||||||
|
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
|
ignore@7.0.5:
|
||||||
|
resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==}
|
||||||
|
engines: {node: '>= 4'}
|
||||||
|
|
||||||
|
imurmurhash@0.1.4:
|
||||||
|
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
|
||||||
|
engines: {node: '>=0.8.19'}
|
||||||
|
|
||||||
|
is-extglob@2.1.1:
|
||||||
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
is-glob@4.0.3:
|
||||||
|
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
isexe@2.0.0:
|
||||||
|
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
|
||||||
|
|
||||||
joycon@3.1.1:
|
joycon@3.1.1:
|
||||||
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
json-buffer@3.0.1:
|
||||||
|
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
|
||||||
|
|
||||||
|
json-schema-traverse@0.4.1:
|
||||||
|
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||||
|
|
||||||
|
json-stable-stringify-without-jsonify@1.0.1:
|
||||||
|
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
|
||||||
|
|
||||||
|
keyv@4.5.4:
|
||||||
|
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||||
|
|
||||||
|
levn@0.4.1:
|
||||||
|
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
lilconfig@3.1.3:
|
lilconfig@3.1.3:
|
||||||
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
|
resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
@ -412,9 +689,17 @@ packages:
|
||||||
resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
|
resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
|
||||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||||
|
|
||||||
|
locate-path@6.0.0:
|
||||||
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
|
||||||
|
|
||||||
|
minimatch@10.2.4:
|
||||||
|
resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==}
|
||||||
|
engines: {node: 18 || 20 || >=22}
|
||||||
|
|
||||||
mlly@1.8.0:
|
mlly@1.8.0:
|
||||||
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
|
||||||
|
|
||||||
|
|
@ -424,10 +709,33 @@ packages:
|
||||||
mz@2.7.0:
|
mz@2.7.0:
|
||||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||||
|
|
||||||
|
natural-compare@1.4.0:
|
||||||
|
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||||
|
|
||||||
object-assign@4.1.1:
|
object-assign@4.1.1:
|
||||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
optionator@0.9.4:
|
||||||
|
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
|
p-limit@3.1.0:
|
||||||
|
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
p-locate@5.0.0:
|
||||||
|
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
path-exists@4.0.0:
|
||||||
|
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
path-key@3.1.1:
|
||||||
|
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
pathe@2.0.3:
|
pathe@2.0.3:
|
||||||
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
|
||||||
|
|
||||||
|
|
@ -463,6 +771,19 @@ packages:
|
||||||
yaml:
|
yaml:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
prelude-ls@1.2.1:
|
||||||
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
|
prettier@3.8.1:
|
||||||
|
resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
punycode@2.3.1:
|
||||||
|
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
readdirp@4.1.2:
|
readdirp@4.1.2:
|
||||||
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
|
||||||
engines: {node: '>= 14.18.0'}
|
engines: {node: '>= 14.18.0'}
|
||||||
|
|
@ -476,6 +797,19 @@ packages:
|
||||||
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
semver@7.7.4:
|
||||||
|
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
shebang-command@2.0.0:
|
||||||
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
shebang-regex@3.0.0:
|
||||||
|
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
source-map@0.7.6:
|
source-map@0.7.6:
|
||||||
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==}
|
||||||
engines: {node: '>= 12'}
|
engines: {node: '>= 12'}
|
||||||
|
|
@ -503,6 +837,12 @@ packages:
|
||||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
ts-api-utils@2.4.0:
|
||||||
|
resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==}
|
||||||
|
engines: {node: '>=18.12'}
|
||||||
|
peerDependencies:
|
||||||
|
typescript: '>=4.8.4'
|
||||||
|
|
||||||
ts-interface-checker@0.1.13:
|
ts-interface-checker@0.1.13:
|
||||||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||||
|
|
||||||
|
|
@ -525,6 +865,17 @@ packages:
|
||||||
typescript:
|
typescript:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
type-check@0.4.0:
|
||||||
|
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||||
|
engines: {node: '>= 0.8.0'}
|
||||||
|
|
||||||
|
typescript-eslint@8.56.1:
|
||||||
|
resolution: {integrity: sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==}
|
||||||
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
peerDependencies:
|
||||||
|
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||||
|
typescript: '>=4.8.4 <6.0.0'
|
||||||
|
|
||||||
typescript@5.9.3:
|
typescript@5.9.3:
|
||||||
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
|
|
@ -536,6 +887,22 @@ packages:
|
||||||
undici-types@7.18.2:
|
undici-types@7.18.2:
|
||||||
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
|
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
|
||||||
|
|
||||||
|
uri-js@4.4.1:
|
||||||
|
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||||
|
|
||||||
|
which@2.0.2:
|
||||||
|
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
|
||||||
|
engines: {node: '>= 8'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
word-wrap@1.2.5:
|
||||||
|
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||||
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
yocto-queue@0.1.0:
|
||||||
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.27.3':
|
'@esbuild/aix-ppc64@0.27.3':
|
||||||
|
|
@ -616,6 +983,51 @@ snapshots:
|
||||||
'@esbuild/win32-x64@0.27.3':
|
'@esbuild/win32-x64@0.27.3':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@eslint-community/eslint-utils@4.9.1(eslint@10.0.3)':
|
||||||
|
dependencies:
|
||||||
|
eslint: 10.0.3
|
||||||
|
eslint-visitor-keys: 3.4.3
|
||||||
|
|
||||||
|
'@eslint-community/regexpp@4.12.2': {}
|
||||||
|
|
||||||
|
'@eslint/config-array@0.23.3':
|
||||||
|
dependencies:
|
||||||
|
'@eslint/object-schema': 3.0.3
|
||||||
|
debug: 4.4.3
|
||||||
|
minimatch: 10.2.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@eslint/config-helpers@0.5.3':
|
||||||
|
dependencies:
|
||||||
|
'@eslint/core': 1.1.1
|
||||||
|
|
||||||
|
'@eslint/core@1.1.1':
|
||||||
|
dependencies:
|
||||||
|
'@types/json-schema': 7.0.15
|
||||||
|
|
||||||
|
'@eslint/js@10.0.1(eslint@10.0.3)':
|
||||||
|
optionalDependencies:
|
||||||
|
eslint: 10.0.3
|
||||||
|
|
||||||
|
'@eslint/object-schema@3.0.3': {}
|
||||||
|
|
||||||
|
'@eslint/plugin-kit@0.6.1':
|
||||||
|
dependencies:
|
||||||
|
'@eslint/core': 1.1.1
|
||||||
|
levn: 0.4.1
|
||||||
|
|
||||||
|
'@humanfs/core@0.19.1': {}
|
||||||
|
|
||||||
|
'@humanfs/node@0.16.7':
|
||||||
|
dependencies:
|
||||||
|
'@humanfs/core': 0.19.1
|
||||||
|
'@humanwhocodes/retry': 0.4.3
|
||||||
|
|
||||||
|
'@humanwhocodes/module-importer@1.0.1': {}
|
||||||
|
|
||||||
|
'@humanwhocodes/retry@0.4.3': {}
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.13':
|
'@jridgewell/gen-mapping@0.3.13':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
@ -705,16 +1117,128 @@ snapshots:
|
||||||
'@rollup/rollup-win32-x64-msvc@4.59.0':
|
'@rollup/rollup-win32-x64-msvc@4.59.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@types/esrecurse@4.3.1': {}
|
||||||
|
|
||||||
'@types/estree@1.0.8': {}
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/node@25.3.0':
|
'@types/node@25.3.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 7.18.2
|
undici-types: 7.18.2
|
||||||
|
|
||||||
|
'@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@eslint-community/regexpp': 4.12.2
|
||||||
|
'@typescript-eslint/parser': 8.56.1(eslint@10.0.3)(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/scope-manager': 8.56.1
|
||||||
|
'@typescript-eslint/type-utils': 8.56.1(eslint@10.0.3)(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/utils': 8.56.1(eslint@10.0.3)(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/visitor-keys': 8.56.1
|
||||||
|
eslint: 10.0.3
|
||||||
|
ignore: 7.0.5
|
||||||
|
natural-compare: 1.4.0
|
||||||
|
ts-api-utils: 2.4.0(typescript@5.9.3)
|
||||||
|
typescript: 5.9.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@typescript-eslint/parser@8.56.1(eslint@10.0.3)(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/scope-manager': 8.56.1
|
||||||
|
'@typescript-eslint/types': 8.56.1
|
||||||
|
'@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/visitor-keys': 8.56.1
|
||||||
|
debug: 4.4.3
|
||||||
|
eslint: 10.0.3
|
||||||
|
typescript: 5.9.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@typescript-eslint/project-service@8.56.1(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/types': 8.56.1
|
||||||
|
debug: 4.4.3
|
||||||
|
typescript: 5.9.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@typescript-eslint/scope-manager@8.56.1':
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/types': 8.56.1
|
||||||
|
'@typescript-eslint/visitor-keys': 8.56.1
|
||||||
|
|
||||||
|
'@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
typescript: 5.9.3
|
||||||
|
|
||||||
|
'@typescript-eslint/type-utils@8.56.1(eslint@10.0.3)(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/types': 8.56.1
|
||||||
|
'@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/utils': 8.56.1(eslint@10.0.3)(typescript@5.9.3)
|
||||||
|
debug: 4.4.3
|
||||||
|
eslint: 10.0.3
|
||||||
|
ts-api-utils: 2.4.0(typescript@5.9.3)
|
||||||
|
typescript: 5.9.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@typescript-eslint/types@8.56.1': {}
|
||||||
|
|
||||||
|
'@typescript-eslint/typescript-estree@8.56.1(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/project-service': 8.56.1(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/types': 8.56.1
|
||||||
|
'@typescript-eslint/visitor-keys': 8.56.1
|
||||||
|
debug: 4.4.3
|
||||||
|
minimatch: 10.2.4
|
||||||
|
semver: 7.7.4
|
||||||
|
tinyglobby: 0.2.15
|
||||||
|
ts-api-utils: 2.4.0(typescript@5.9.3)
|
||||||
|
typescript: 5.9.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@typescript-eslint/utils@8.56.1(eslint@10.0.3)(typescript@5.9.3)':
|
||||||
|
dependencies:
|
||||||
|
'@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3)
|
||||||
|
'@typescript-eslint/scope-manager': 8.56.1
|
||||||
|
'@typescript-eslint/types': 8.56.1
|
||||||
|
'@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3)
|
||||||
|
eslint: 10.0.3
|
||||||
|
typescript: 5.9.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@typescript-eslint/visitor-keys@8.56.1':
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/types': 8.56.1
|
||||||
|
eslint-visitor-keys: 5.0.1
|
||||||
|
|
||||||
|
acorn-jsx@5.3.2(acorn@8.16.0):
|
||||||
|
dependencies:
|
||||||
|
acorn: 8.16.0
|
||||||
|
|
||||||
acorn@8.16.0: {}
|
acorn@8.16.0: {}
|
||||||
|
|
||||||
|
ajv@6.14.0:
|
||||||
|
dependencies:
|
||||||
|
fast-deep-equal: 3.1.3
|
||||||
|
fast-json-stable-stringify: 2.1.0
|
||||||
|
json-schema-traverse: 0.4.1
|
||||||
|
uri-js: 4.4.1
|
||||||
|
|
||||||
any-promise@1.3.0: {}
|
any-promise@1.3.0: {}
|
||||||
|
|
||||||
|
balanced-match@4.0.4: {}
|
||||||
|
|
||||||
|
brace-expansion@5.0.4:
|
||||||
|
dependencies:
|
||||||
|
balanced-match: 4.0.4
|
||||||
|
|
||||||
bundle-require@5.1.0(esbuild@0.27.3):
|
bundle-require@5.1.0(esbuild@0.27.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.27.3
|
esbuild: 0.27.3
|
||||||
|
|
@ -732,10 +1256,18 @@ snapshots:
|
||||||
|
|
||||||
consola@3.4.2: {}
|
consola@3.4.2: {}
|
||||||
|
|
||||||
|
cross-spawn@7.0.6:
|
||||||
|
dependencies:
|
||||||
|
path-key: 3.1.1
|
||||||
|
shebang-command: 2.0.0
|
||||||
|
which: 2.0.2
|
||||||
|
|
||||||
debug@4.4.3:
|
debug@4.4.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.3
|
ms: 2.1.3
|
||||||
|
|
||||||
|
deep-is@0.1.4: {}
|
||||||
|
|
||||||
esbuild@0.27.3:
|
esbuild@0.27.3:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/aix-ppc64': 0.27.3
|
'@esbuild/aix-ppc64': 0.27.3
|
||||||
|
|
@ -765,31 +1297,164 @@ snapshots:
|
||||||
'@esbuild/win32-ia32': 0.27.3
|
'@esbuild/win32-ia32': 0.27.3
|
||||||
'@esbuild/win32-x64': 0.27.3
|
'@esbuild/win32-x64': 0.27.3
|
||||||
|
|
||||||
|
escape-string-regexp@4.0.0: {}
|
||||||
|
|
||||||
|
eslint-config-prettier@10.1.8(eslint@10.0.3):
|
||||||
|
dependencies:
|
||||||
|
eslint: 10.0.3
|
||||||
|
|
||||||
|
eslint-scope@9.1.2:
|
||||||
|
dependencies:
|
||||||
|
'@types/esrecurse': 4.3.1
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
esrecurse: 4.3.0
|
||||||
|
estraverse: 5.3.0
|
||||||
|
|
||||||
|
eslint-visitor-keys@3.4.3: {}
|
||||||
|
|
||||||
|
eslint-visitor-keys@5.0.1: {}
|
||||||
|
|
||||||
|
eslint@10.0.3:
|
||||||
|
dependencies:
|
||||||
|
'@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3)
|
||||||
|
'@eslint-community/regexpp': 4.12.2
|
||||||
|
'@eslint/config-array': 0.23.3
|
||||||
|
'@eslint/config-helpers': 0.5.3
|
||||||
|
'@eslint/core': 1.1.1
|
||||||
|
'@eslint/plugin-kit': 0.6.1
|
||||||
|
'@humanfs/node': 0.16.7
|
||||||
|
'@humanwhocodes/module-importer': 1.0.1
|
||||||
|
'@humanwhocodes/retry': 0.4.3
|
||||||
|
'@types/estree': 1.0.8
|
||||||
|
ajv: 6.14.0
|
||||||
|
cross-spawn: 7.0.6
|
||||||
|
debug: 4.4.3
|
||||||
|
escape-string-regexp: 4.0.0
|
||||||
|
eslint-scope: 9.1.2
|
||||||
|
eslint-visitor-keys: 5.0.1
|
||||||
|
espree: 11.2.0
|
||||||
|
esquery: 1.7.0
|
||||||
|
esutils: 2.0.3
|
||||||
|
fast-deep-equal: 3.1.3
|
||||||
|
file-entry-cache: 8.0.0
|
||||||
|
find-up: 5.0.0
|
||||||
|
glob-parent: 6.0.2
|
||||||
|
ignore: 5.3.2
|
||||||
|
imurmurhash: 0.1.4
|
||||||
|
is-glob: 4.0.3
|
||||||
|
json-stable-stringify-without-jsonify: 1.0.1
|
||||||
|
minimatch: 10.2.4
|
||||||
|
natural-compare: 1.4.0
|
||||||
|
optionator: 0.9.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
espree@11.2.0:
|
||||||
|
dependencies:
|
||||||
|
acorn: 8.16.0
|
||||||
|
acorn-jsx: 5.3.2(acorn@8.16.0)
|
||||||
|
eslint-visitor-keys: 5.0.1
|
||||||
|
|
||||||
|
esquery@1.7.0:
|
||||||
|
dependencies:
|
||||||
|
estraverse: 5.3.0
|
||||||
|
|
||||||
|
esrecurse@4.3.0:
|
||||||
|
dependencies:
|
||||||
|
estraverse: 5.3.0
|
||||||
|
|
||||||
|
estraverse@5.3.0: {}
|
||||||
|
|
||||||
|
esutils@2.0.3: {}
|
||||||
|
|
||||||
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
|
fast-json-stable-stringify@2.1.0: {}
|
||||||
|
|
||||||
|
fast-levenshtein@2.0.6: {}
|
||||||
|
|
||||||
fdir@6.5.0(picomatch@4.0.3):
|
fdir@6.5.0(picomatch@4.0.3):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.3
|
picomatch: 4.0.3
|
||||||
|
|
||||||
|
file-entry-cache@8.0.0:
|
||||||
|
dependencies:
|
||||||
|
flat-cache: 4.0.1
|
||||||
|
|
||||||
|
find-up@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
locate-path: 6.0.0
|
||||||
|
path-exists: 4.0.0
|
||||||
|
|
||||||
fix-dts-default-cjs-exports@1.0.1:
|
fix-dts-default-cjs-exports@1.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
magic-string: 0.30.21
|
magic-string: 0.30.21
|
||||||
mlly: 1.8.0
|
mlly: 1.8.0
|
||||||
rollup: 4.59.0
|
rollup: 4.59.0
|
||||||
|
|
||||||
|
flat-cache@4.0.1:
|
||||||
|
dependencies:
|
||||||
|
flatted: 3.3.4
|
||||||
|
keyv: 4.5.4
|
||||||
|
|
||||||
|
flatted@3.3.4: {}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
glob-parent@6.0.2:
|
||||||
|
dependencies:
|
||||||
|
is-glob: 4.0.3
|
||||||
|
|
||||||
|
ignore@5.3.2: {}
|
||||||
|
|
||||||
|
ignore@7.0.5: {}
|
||||||
|
|
||||||
|
imurmurhash@0.1.4: {}
|
||||||
|
|
||||||
|
is-extglob@2.1.1: {}
|
||||||
|
|
||||||
|
is-glob@4.0.3:
|
||||||
|
dependencies:
|
||||||
|
is-extglob: 2.1.1
|
||||||
|
|
||||||
|
isexe@2.0.0: {}
|
||||||
|
|
||||||
joycon@3.1.1: {}
|
joycon@3.1.1: {}
|
||||||
|
|
||||||
|
json-buffer@3.0.1: {}
|
||||||
|
|
||||||
|
json-schema-traverse@0.4.1: {}
|
||||||
|
|
||||||
|
json-stable-stringify-without-jsonify@1.0.1: {}
|
||||||
|
|
||||||
|
keyv@4.5.4:
|
||||||
|
dependencies:
|
||||||
|
json-buffer: 3.0.1
|
||||||
|
|
||||||
|
levn@0.4.1:
|
||||||
|
dependencies:
|
||||||
|
prelude-ls: 1.2.1
|
||||||
|
type-check: 0.4.0
|
||||||
|
|
||||||
lilconfig@3.1.3: {}
|
lilconfig@3.1.3: {}
|
||||||
|
|
||||||
lines-and-columns@1.2.4: {}
|
lines-and-columns@1.2.4: {}
|
||||||
|
|
||||||
load-tsconfig@0.2.5: {}
|
load-tsconfig@0.2.5: {}
|
||||||
|
|
||||||
|
locate-path@6.0.0:
|
||||||
|
dependencies:
|
||||||
|
p-locate: 5.0.0
|
||||||
|
|
||||||
magic-string@0.30.21:
|
magic-string@0.30.21:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
minimatch@10.2.4:
|
||||||
|
dependencies:
|
||||||
|
brace-expansion: 5.0.4
|
||||||
|
|
||||||
mlly@1.8.0:
|
mlly@1.8.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 8.16.0
|
acorn: 8.16.0
|
||||||
|
|
@ -805,8 +1470,31 @@ snapshots:
|
||||||
object-assign: 4.1.1
|
object-assign: 4.1.1
|
||||||
thenify-all: 1.6.0
|
thenify-all: 1.6.0
|
||||||
|
|
||||||
|
natural-compare@1.4.0: {}
|
||||||
|
|
||||||
object-assign@4.1.1: {}
|
object-assign@4.1.1: {}
|
||||||
|
|
||||||
|
optionator@0.9.4:
|
||||||
|
dependencies:
|
||||||
|
deep-is: 0.1.4
|
||||||
|
fast-levenshtein: 2.0.6
|
||||||
|
levn: 0.4.1
|
||||||
|
prelude-ls: 1.2.1
|
||||||
|
type-check: 0.4.0
|
||||||
|
word-wrap: 1.2.5
|
||||||
|
|
||||||
|
p-limit@3.1.0:
|
||||||
|
dependencies:
|
||||||
|
yocto-queue: 0.1.0
|
||||||
|
|
||||||
|
p-locate@5.0.0:
|
||||||
|
dependencies:
|
||||||
|
p-limit: 3.1.0
|
||||||
|
|
||||||
|
path-exists@4.0.0: {}
|
||||||
|
|
||||||
|
path-key@3.1.1: {}
|
||||||
|
|
||||||
pathe@2.0.3: {}
|
pathe@2.0.3: {}
|
||||||
|
|
||||||
picocolors@1.1.1: {}
|
picocolors@1.1.1: {}
|
||||||
|
|
@ -825,6 +1513,12 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
lilconfig: 3.1.3
|
lilconfig: 3.1.3
|
||||||
|
|
||||||
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
|
prettier@3.8.1: {}
|
||||||
|
|
||||||
|
punycode@2.3.1: {}
|
||||||
|
|
||||||
readdirp@4.1.2: {}
|
readdirp@4.1.2: {}
|
||||||
|
|
||||||
resolve-from@5.0.0: {}
|
resolve-from@5.0.0: {}
|
||||||
|
|
@ -860,6 +1554,14 @@ snapshots:
|
||||||
'@rollup/rollup-win32-x64-msvc': 4.59.0
|
'@rollup/rollup-win32-x64-msvc': 4.59.0
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
semver@7.7.4: {}
|
||||||
|
|
||||||
|
shebang-command@2.0.0:
|
||||||
|
dependencies:
|
||||||
|
shebang-regex: 3.0.0
|
||||||
|
|
||||||
|
shebang-regex@3.0.0: {}
|
||||||
|
|
||||||
source-map@0.7.6: {}
|
source-map@0.7.6: {}
|
||||||
|
|
||||||
sucrase@3.35.1:
|
sucrase@3.35.1:
|
||||||
|
|
@ -889,6 +1591,10 @@ snapshots:
|
||||||
|
|
||||||
tree-kill@1.2.2: {}
|
tree-kill@1.2.2: {}
|
||||||
|
|
||||||
|
ts-api-utils@2.4.0(typescript@5.9.3):
|
||||||
|
dependencies:
|
||||||
|
typescript: 5.9.3
|
||||||
|
|
||||||
ts-interface-checker@0.1.13: {}
|
ts-interface-checker@0.1.13: {}
|
||||||
|
|
||||||
tsup@8.5.1(typescript@5.9.3):
|
tsup@8.5.1(typescript@5.9.3):
|
||||||
|
|
@ -918,8 +1624,35 @@ snapshots:
|
||||||
- tsx
|
- tsx
|
||||||
- yaml
|
- yaml
|
||||||
|
|
||||||
|
type-check@0.4.0:
|
||||||
|
dependencies:
|
||||||
|
prelude-ls: 1.2.1
|
||||||
|
|
||||||
|
typescript-eslint@8.56.1(eslint@10.0.3)(typescript@5.9.3):
|
||||||
|
dependencies:
|
||||||
|
'@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/parser': 8.56.1(eslint@10.0.3)(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/typescript-estree': 8.56.1(typescript@5.9.3)
|
||||||
|
'@typescript-eslint/utils': 8.56.1(eslint@10.0.3)(typescript@5.9.3)
|
||||||
|
eslint: 10.0.3
|
||||||
|
typescript: 5.9.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
typescript@5.9.3: {}
|
typescript@5.9.3: {}
|
||||||
|
|
||||||
ufo@1.6.3: {}
|
ufo@1.6.3: {}
|
||||||
|
|
||||||
undici-types@7.18.2: {}
|
undici-types@7.18.2: {}
|
||||||
|
|
||||||
|
uri-js@4.4.1:
|
||||||
|
dependencies:
|
||||||
|
punycode: 2.3.1
|
||||||
|
|
||||||
|
which@2.0.2:
|
||||||
|
dependencies:
|
||||||
|
isexe: 2.0.0
|
||||||
|
|
||||||
|
word-wrap@1.2.5: {}
|
||||||
|
|
||||||
|
yocto-queue@0.1.0: {}
|
||||||
|
|
|
||||||
131
src/index.ts
131
src/index.ts
|
|
@ -52,19 +52,36 @@ export function init(): Promise<void> {
|
||||||
if (_module) return Promise.resolve();
|
if (_module) return Promise.resolve();
|
||||||
if (_pending) return _pending;
|
if (_pending) return _pending;
|
||||||
|
|
||||||
_pending = createSpaModule().then((mod: SpaWasmModule) => {
|
_pending = createSpaModule()
|
||||||
_module = mod;
|
.then((mod: SpaWasmModule) => {
|
||||||
_calculate = mod.cwrap('spa_calculate_wrapper', 'number', [
|
_module = mod;
|
||||||
'number', 'number', 'number', 'number', 'number', 'number',
|
_calculate = mod.cwrap('spa_calculate_wrapper', 'number', [
|
||||||
'number', 'number', 'number', 'number', 'number', 'number',
|
'number',
|
||||||
'number', 'number', 'number', 'number', 'number', 'number',
|
'number',
|
||||||
]) as (...args: number[]) => number;
|
'number',
|
||||||
_free = mod.cwrap('spa_free_result', null, ['number']) as (ptr: number) => void;
|
'number',
|
||||||
_pending = null;
|
'number',
|
||||||
}).catch((err: unknown) => {
|
'number',
|
||||||
_pending = null;
|
'number',
|
||||||
throw err;
|
'number',
|
||||||
});
|
'number',
|
||||||
|
'number',
|
||||||
|
'number',
|
||||||
|
'number',
|
||||||
|
'number',
|
||||||
|
'number',
|
||||||
|
'number',
|
||||||
|
'number',
|
||||||
|
'number',
|
||||||
|
'number',
|
||||||
|
]) as (...args: number[]) => number;
|
||||||
|
_free = mod.cwrap('spa_free_result', null, ['number']) as (ptr: number) => void;
|
||||||
|
_pending = null;
|
||||||
|
})
|
||||||
|
.catch((err: unknown) => {
|
||||||
|
_pending = null;
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
return _pending;
|
return _pending;
|
||||||
}
|
}
|
||||||
|
|
@ -72,21 +89,20 @@ export function init(): Promise<void> {
|
||||||
/**
|
/**
|
||||||
* Format fractional hours to HH:MM:SS string.
|
* Format fractional hours to HH:MM:SS string.
|
||||||
* Returns "N/A" for non-finite or negative values (polar night/day scenarios).
|
* Returns "N/A" for non-finite or negative values (polar night/day scenarios).
|
||||||
|
*
|
||||||
|
* @param hours - Fractional hours (e.g. 6.5 for 06:30:00). Values >= 24 wrap.
|
||||||
|
* @returns Formatted time string in HH:MM:SS format, or "N/A" if input is invalid.
|
||||||
*/
|
*/
|
||||||
export function formatTime(hours: number): string {
|
export function formatTime(hours: number): string {
|
||||||
if (!isFinite(hours) || hours < 0) return 'N/A';
|
if (!isFinite(hours) || hours < 0) return 'N/A';
|
||||||
|
|
||||||
const totalSec = Math.round(hours * 3600);
|
const totalSec = Math.round(hours * 3600);
|
||||||
// Wrap at 24h: values near midnight can round to 24:00:00
|
|
||||||
const h = Math.floor(totalSec / 3600) % 24;
|
const h = Math.floor(totalSec / 3600) % 24;
|
||||||
const rem = totalSec - Math.floor(totalSec / 3600) * 3600;
|
const m = Math.floor((totalSec % 3600) / 60);
|
||||||
const m = Math.floor(rem / 60);
|
const s = totalSec % 60;
|
||||||
const s = rem - m * 60;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
String(h).padStart(2, '0') + ':' +
|
String(h).padStart(2, '0') + ':' + String(m).padStart(2, '0') + ':' + String(s).padStart(2, '0')
|
||||||
String(m).padStart(2, '0') + ':' +
|
|
||||||
String(s).padStart(2, '0')
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,16 +110,16 @@ export function formatTime(hours: number): string {
|
||||||
function readResult(ptr: number): SpaResult {
|
function readResult(ptr: number): SpaResult {
|
||||||
const m = _module!;
|
const m = _module!;
|
||||||
const result: SpaResult = {
|
const result: SpaResult = {
|
||||||
zenith: m.getValue(ptr + OFFSET.zenith, 'double'),
|
zenith: m.getValue(ptr + OFFSET.zenith, 'double'),
|
||||||
azimuth_astro: m.getValue(ptr + OFFSET.azimuth_astro, 'double'),
|
azimuth_astro: m.getValue(ptr + OFFSET.azimuth_astro, 'double'),
|
||||||
azimuth: m.getValue(ptr + OFFSET.azimuth, 'double'),
|
azimuth: m.getValue(ptr + OFFSET.azimuth, 'double'),
|
||||||
incidence: m.getValue(ptr + OFFSET.incidence, 'double'),
|
incidence: m.getValue(ptr + OFFSET.incidence, 'double'),
|
||||||
sunrise: m.getValue(ptr + OFFSET.sunrise, 'double'),
|
sunrise: m.getValue(ptr + OFFSET.sunrise, 'double'),
|
||||||
sunset: m.getValue(ptr + OFFSET.sunset, 'double'),
|
sunset: m.getValue(ptr + OFFSET.sunset, 'double'),
|
||||||
suntransit: m.getValue(ptr + OFFSET.suntransit, 'double'),
|
suntransit: m.getValue(ptr + OFFSET.suntransit, 'double'),
|
||||||
sun_transit_alt: m.getValue(ptr + OFFSET.sun_transit_alt, 'double'),
|
sun_transit_alt: m.getValue(ptr + OFFSET.sun_transit_alt, 'double'),
|
||||||
eot: m.getValue(ptr + OFFSET.eot, 'double'),
|
eot: m.getValue(ptr + OFFSET.eot, 'double'),
|
||||||
error_code: m.getValue(ptr + OFFSET.error_code, 'i32'),
|
error_code: m.getValue(ptr + OFFSET.error_code, 'i32'),
|
||||||
};
|
};
|
||||||
_free!(ptr);
|
_free!(ptr);
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -114,8 +130,34 @@ function readResult(ptr: number): SpaResult {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
function assertFiniteNumber(value: unknown, name: string): asserts value is number {
|
function assertFiniteNumber(value: unknown, name: string): asserts value is number {
|
||||||
if (typeof value !== 'number' || !isFinite(value)) {
|
if (typeof value !== 'number') {
|
||||||
throw new TypeError(`SPA: ${name} must be a finite number, got ${typeof value === 'number' ? value : typeof value}`);
|
throw new TypeError(`SPA: ${name} must be a finite number, got ${typeof value}`);
|
||||||
|
}
|
||||||
|
if (!isFinite(value)) {
|
||||||
|
throw new RangeError(`SPA: ${name} must be a finite number, got ${value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Field names in SpaOptions that must be finite numbers when provided. */
|
||||||
|
const NUMERIC_OPTION_FIELDS = [
|
||||||
|
'elevation',
|
||||||
|
'pressure',
|
||||||
|
'temperature',
|
||||||
|
'delta_t',
|
||||||
|
'slope',
|
||||||
|
'azm_rotation',
|
||||||
|
'atmos_refract',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate numeric option fields. Each, if provided, must be a finite number.
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
function validateOptions(opts: SpaOptions): void {
|
||||||
|
for (const field of NUMERIC_OPTION_FIELDS) {
|
||||||
|
if (opts[field] !== undefined) {
|
||||||
|
assertFiniteNumber(opts[field], `options.${field}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,6 +169,8 @@ function assertFiniteNumber(value: unknown, name: string): asserts value is numb
|
||||||
* @param longitude - Observer longitude in degrees (-180 to 180)
|
* @param longitude - Observer longitude in degrees (-180 to 180)
|
||||||
* @param options - Optional parameters
|
* @param options - Optional parameters
|
||||||
* @returns Solar position result with all computed values
|
* @returns Solar position result with all computed values
|
||||||
|
* @throws {TypeError} If date is not a valid Date, or if latitude/longitude/option fields are not numbers
|
||||||
|
* @throws {RangeError} If latitude/longitude are out of bounds, or if option fields are Infinity/NaN
|
||||||
*/
|
*/
|
||||||
export async function spa(
|
export async function spa(
|
||||||
date: Date,
|
date: Date,
|
||||||
|
|
@ -148,6 +192,10 @@ export async function spa(
|
||||||
throw new RangeError(`SPA: longitude must be between -180 and 180, got ${longitude}`);
|
throw new RangeError(`SPA: longitude must be between -180 and 180, got ${longitude}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options) {
|
||||||
|
validateOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
await init();
|
await init();
|
||||||
|
|
||||||
const opts = options ?? {};
|
const opts = options ?? {};
|
||||||
|
|
@ -192,6 +240,9 @@ export async function spa(
|
||||||
*
|
*
|
||||||
* Same parameters as spa(). Returns sunrise, sunset, and suntransit
|
* Same parameters as spa(). Returns sunrise, sunset, and suntransit
|
||||||
* as HH:MM:SS strings instead of fractional hours.
|
* as HH:MM:SS strings instead of fractional hours.
|
||||||
|
*
|
||||||
|
* @throws {TypeError} If date is not a valid Date, or if latitude/longitude/option fields are not numbers
|
||||||
|
* @throws {RangeError} If latitude/longitude are out of bounds, or if option fields are Infinity/NaN
|
||||||
*/
|
*/
|
||||||
export async function spaFormatted(
|
export async function spaFormatted(
|
||||||
date: Date,
|
date: Date,
|
||||||
|
|
@ -201,16 +252,16 @@ export async function spaFormatted(
|
||||||
): Promise<SpaFormattedResult> {
|
): Promise<SpaFormattedResult> {
|
||||||
const result = await spa(date, latitude, longitude, options);
|
const result = await spa(date, latitude, longitude, options);
|
||||||
return {
|
return {
|
||||||
zenith: result.zenith,
|
zenith: result.zenith,
|
||||||
azimuth_astro: result.azimuth_astro,
|
azimuth_astro: result.azimuth_astro,
|
||||||
azimuth: result.azimuth,
|
azimuth: result.azimuth,
|
||||||
incidence: result.incidence,
|
incidence: result.incidence,
|
||||||
sunrise: formatTime(result.sunrise),
|
sunrise: formatTime(result.sunrise),
|
||||||
sunset: formatTime(result.sunset),
|
sunset: formatTime(result.sunset),
|
||||||
suntransit: formatTime(result.suntransit),
|
suntransit: formatTime(result.suntransit),
|
||||||
sun_transit_alt: result.sun_transit_alt,
|
sun_transit_alt: result.sun_transit_alt,
|
||||||
eot: result.eot,
|
eot: result.eot,
|
||||||
error_code: result.error_code,
|
error_code: result.error_code,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
13
src/types.ts
13
src/types.ts
|
|
@ -1,10 +1,17 @@
|
||||||
/** SPA function codes. Control which outputs are computed. */
|
/** Compute zenith and azimuth only. */
|
||||||
export const SPA_ZA = 0 as const;
|
export const SPA_ZA = 0 as const;
|
||||||
|
/** Compute zenith, azimuth, and incidence angle. */
|
||||||
export const SPA_ZA_INC = 1 as const;
|
export const SPA_ZA_INC = 1 as const;
|
||||||
|
/** Compute zenith, azimuth, and rise/transit/set times. */
|
||||||
export const SPA_ZA_RTS = 2 as const;
|
export const SPA_ZA_RTS = 2 as const;
|
||||||
|
/** Compute all outputs: zenith, azimuth, incidence, and rise/transit/set. */
|
||||||
export const SPA_ALL = 3 as const;
|
export const SPA_ALL = 3 as const;
|
||||||
|
|
||||||
export type SpaFunctionCode = typeof SPA_ZA | typeof SPA_ZA_INC | typeof SPA_ZA_RTS | typeof SPA_ALL;
|
export type SpaFunctionCode =
|
||||||
|
| typeof SPA_ZA
|
||||||
|
| typeof SPA_ZA_INC
|
||||||
|
| typeof SPA_ZA_RTS
|
||||||
|
| typeof SPA_ALL;
|
||||||
|
|
||||||
export interface SpaOptions {
|
export interface SpaOptions {
|
||||||
/**
|
/**
|
||||||
|
|
@ -69,6 +76,6 @@ export interface SpaFormattedResult extends Omit<SpaResult, 'sunrise' | 'sunset'
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export interface SpaWasmModule {
|
export interface SpaWasmModule {
|
||||||
cwrap(name: string, returnType: string | null, argTypes: string[]): Function;
|
cwrap(name: string, returnType: string | null, argTypes: string[]): (...args: never[]) => unknown;
|
||||||
getValue(ptr: number, type: string): number;
|
getValue(ptr: number, type: string): number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
120
test-cjs.cjs
120
test-cjs.cjs
|
|
@ -1,58 +1,72 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const { describe, it } = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
const { spa, spaFormatted, formatTime, init, SPA_ZA, SPA_ALL } = require('./dist/index.cjs');
|
const { spa, spaFormatted, formatTime, init, SPA_ZA, SPA_ALL } = require('./dist/index.cjs');
|
||||||
|
|
||||||
let passed = 0;
|
describe('CJS exports', () => {
|
||||||
let failed = 0;
|
it('all exports are available', () => {
|
||||||
|
assert.equal(typeof spa, 'function');
|
||||||
function assert(condition, message) {
|
assert.equal(typeof spaFormatted, 'function');
|
||||||
if (condition) {
|
assert.equal(typeof formatTime, 'function');
|
||||||
passed++;
|
assert.equal(typeof init, 'function');
|
||||||
} else {
|
assert.equal(SPA_ZA, 0);
|
||||||
failed++;
|
assert.equal(SPA_ALL, 3);
|
||||||
console.error(' FAIL: ' + message);
|
});
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
describe('CJS spa()', () => {
|
||||||
async function run() {
|
it('core calculation succeeds', async () => {
|
||||||
console.log('CJS smoke test\n');
|
const result = await spa(
|
||||||
|
new Date(2023, 3, 1, 0, 0, 0),
|
||||||
// Verify all exports are available
|
40.7128, -74.006,
|
||||||
assert(typeof spa === 'function', 'spa is a function');
|
{ timezone: -4, elevation: 10 },
|
||||||
assert(typeof spaFormatted === 'function', 'spaFormatted is a function');
|
);
|
||||||
assert(typeof formatTime === 'function', 'formatTime is a function');
|
assert.equal(result.error_code, 0);
|
||||||
assert(typeof init === 'function', 'init is a function');
|
assert.ok(result.zenith > 0);
|
||||||
assert(SPA_ZA === 0, 'SPA_ZA constant is 0');
|
assert.ok(result.azimuth > 0);
|
||||||
assert(SPA_ALL === 3, 'SPA_ALL constant is 3');
|
assert.ok(result.sunrise > 0);
|
||||||
|
});
|
||||||
// Core calculation
|
});
|
||||||
const result = await spa(
|
|
||||||
new Date(2023, 3, 1, 0, 0, 0),
|
describe('CJS spaFormatted()', () => {
|
||||||
40.7128, -74.006,
|
it('returns formatted time strings', async () => {
|
||||||
{ timezone: -4, elevation: 10 },
|
const fmt = await spaFormatted(
|
||||||
);
|
new Date(2023, 3, 1, 12, 0, 0),
|
||||||
assert(result.error_code === 0, 'calculation succeeds');
|
40.7128, -74.006,
|
||||||
assert(result.zenith > 0, 'zenith is positive');
|
{ timezone: -4 },
|
||||||
assert(result.azimuth > 0, 'azimuth is positive');
|
);
|
||||||
assert(result.sunrise > 0, 'sunrise is positive');
|
assert.equal(typeof fmt.sunrise, 'string');
|
||||||
|
assert.match(fmt.sunrise, /^\d{2}:\d{2}:\d{2}$/);
|
||||||
// Formatted output
|
});
|
||||||
const fmt = await spaFormatted(
|
});
|
||||||
new Date(2023, 3, 1, 12, 0, 0),
|
|
||||||
40.7128, -74.006,
|
describe('CJS formatTime()', () => {
|
||||||
{ timezone: -4 },
|
it('formats correctly', () => {
|
||||||
);
|
assert.equal(formatTime(6.5), '06:30:00');
|
||||||
assert(typeof fmt.sunrise === 'string', 'formatted sunrise is a string');
|
});
|
||||||
assert(/^\d{2}:\d{2}:\d{2}$/.test(fmt.sunrise), 'sunrise matches HH:MM:SS');
|
});
|
||||||
|
|
||||||
// formatTime
|
describe('CJS option validation', () => {
|
||||||
assert(formatTime(6.5) === '06:30:00', 'formatTime works');
|
it('rejects non-number elevation', async () => {
|
||||||
|
await assert.rejects(() => spa(new Date(), 40, -74, { elevation: 'high' }), TypeError);
|
||||||
console.log('\n' + passed + ' passed, ' + failed + ' failed');
|
});
|
||||||
if (failed > 0) process.exit(1);
|
|
||||||
}
|
it('rejects Infinity pressure', async () => {
|
||||||
|
await assert.rejects(() => spa(new Date(), 40, -74, { pressure: Infinity }), RangeError);
|
||||||
run().catch((err) => {
|
});
|
||||||
console.error(err);
|
|
||||||
process.exit(1);
|
it('rejects NaN temperature', async () => {
|
||||||
|
await assert.rejects(() => spa(new Date(), 40, -74, { temperature: NaN }), RangeError);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts valid numeric options', async () => {
|
||||||
|
const result = await spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, {
|
||||||
|
timezone: -4,
|
||||||
|
elevation: 100,
|
||||||
|
pressure: 1000,
|
||||||
|
temperature: 25,
|
||||||
|
});
|
||||||
|
assert.equal(result.error_code, 0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
499
test.mjs
499
test.mjs
|
|
@ -1,258 +1,271 @@
|
||||||
|
import { describe, it } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
import { spa, spaFormatted, formatTime, init, SPA_ZA, SPA_ZA_INC, SPA_ZA_RTS, SPA_ALL } from './dist/index.mjs';
|
import { spa, spaFormatted, formatTime, init, SPA_ZA, SPA_ZA_INC, SPA_ZA_RTS, SPA_ALL } from './dist/index.mjs';
|
||||||
|
|
||||||
let passed = 0;
|
|
||||||
let failed = 0;
|
|
||||||
|
|
||||||
function assert(condition, message) {
|
|
||||||
if (condition) {
|
|
||||||
passed++;
|
|
||||||
} else {
|
|
||||||
failed++;
|
|
||||||
console.error(' FAIL: ' + message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function approx(actual, expected, tolerance, label) {
|
function approx(actual, expected, tolerance, label) {
|
||||||
const diff = Math.abs(actual - expected);
|
const diff = Math.abs(actual - expected);
|
||||||
assert(diff <= tolerance, label + ': expected ' + expected + ', got ' + actual + ' (diff: ' + diff.toFixed(6) + ')');
|
assert.ok(diff <= tolerance, `${label}: expected ${expected}, got ${actual} (diff: ${diff.toFixed(6)})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function assertThrows(fn, check, label) {
|
describe('spa()', () => {
|
||||||
try {
|
it('NYC, April 1 2023, midnight local (UTC-4)', async () => {
|
||||||
await fn();
|
const nyc = await spa(
|
||||||
assert(false, label + ': should have thrown');
|
new Date(2023, 3, 1, 0, 0, 0),
|
||||||
} catch (e) {
|
40.7128, -74.006,
|
||||||
if (check) {
|
{ timezone: -4, elevation: 10, temperature: 20, pressure: 1013.25 },
|
||||||
assert(check(e), label + ': ' + e.message);
|
);
|
||||||
} else {
|
approx(nyc.zenith, 132.82, 0.1, 'zenith');
|
||||||
passed++;
|
approx(nyc.azimuth, 339.38, 0.1, 'azimuth');
|
||||||
}
|
approx(nyc.sunrise, 6.665, 0.01, 'sunrise');
|
||||||
}
|
approx(nyc.sunset, 19.343, 0.01, 'sunset');
|
||||||
}
|
approx(nyc.suntransit, 12.998, 0.01, 'solar noon');
|
||||||
|
approx(nyc.sun_transit_alt, 53.916, 0.1, 'transit altitude');
|
||||||
|
assert.equal(nyc.error_code, 0);
|
||||||
|
});
|
||||||
|
|
||||||
async function run() {
|
it('London, June 21 2025, noon UTC', async () => {
|
||||||
console.log('solar-spa test suite\n');
|
const london = await spa(
|
||||||
|
new Date(2025, 5, 21, 12, 0, 0),
|
||||||
|
51.5074, -0.1278,
|
||||||
|
{ timezone: 0, elevation: 11, temperature: 18 },
|
||||||
|
);
|
||||||
|
assert.ok(london.zenith < 30, 'zenith near noon is below 30 degrees');
|
||||||
|
assert.ok(london.azimuth > 170 && london.azimuth < 200, 'azimuth roughly south at noon');
|
||||||
|
assert.ok(london.sunrise > 3 && london.sunrise < 6, 'sunrise between 3 and 6');
|
||||||
|
assert.ok(london.sunset > 19 && london.sunset < 23, 'sunset between 19 and 23');
|
||||||
|
assert.equal(london.error_code, 0);
|
||||||
|
});
|
||||||
|
|
||||||
// ── Test 1: New York City, April 1 2023 ──
|
it('Quito (equator), March 20 2025, noon UTC-5', async () => {
|
||||||
console.log('1. NYC, April 1 2023, midnight local (UTC-4)');
|
const quito = await spa(
|
||||||
const nyc = await spa(
|
new Date(2025, 2, 20, 12, 0, 0),
|
||||||
new Date(2023, 3, 1, 0, 0, 0),
|
-0.1807, -78.4678,
|
||||||
40.7128, -74.006,
|
{ timezone: -5, elevation: 2850 },
|
||||||
{ timezone: -4, elevation: 10, temperature: 20, pressure: 1013.25 },
|
);
|
||||||
);
|
assert.ok(quito.zenith < 20, 'near-overhead sun at equinox on equator');
|
||||||
approx(nyc.zenith, 132.82, 0.1, 'zenith');
|
assert.equal(quito.error_code, 0);
|
||||||
approx(nyc.azimuth, 339.38, 0.1, 'azimuth');
|
});
|
||||||
approx(nyc.sunrise, 6.665, 0.01, 'sunrise');
|
|
||||||
approx(nyc.sunset, 19.343, 0.01, 'sunset');
|
|
||||||
approx(nyc.suntransit, 12.998, 0.01, 'solar noon');
|
|
||||||
approx(nyc.sun_transit_alt, 53.916, 0.1, 'transit altitude');
|
|
||||||
assert(nyc.error_code === 0, 'error_code is 0');
|
|
||||||
|
|
||||||
// ── Test 2: London, Summer Solstice ──
|
it('Sydney, June 21 2025 (winter), noon AEST', async () => {
|
||||||
console.log('2. London, June 21 2025, noon UTC');
|
const sydney = await spa(
|
||||||
const london = await spa(
|
new Date(2025, 5, 21, 12, 0, 0),
|
||||||
new Date(2025, 5, 21, 12, 0, 0),
|
-33.8688, 151.2093,
|
||||||
51.5074, -0.1278,
|
{ timezone: 10 },
|
||||||
{ timezone: 0, elevation: 11, temperature: 18 },
|
);
|
||||||
);
|
assert.ok(sydney.zenith > 50, 'low sun in southern winter');
|
||||||
assert(london.zenith < 30, 'zenith near noon is below 30 degrees');
|
assert.ok(sydney.sunrise > 6 && sydney.sunrise < 8, 'winter sunrise after 6');
|
||||||
assert(london.azimuth > 170 && london.azimuth < 200, 'azimuth roughly south at noon');
|
assert.equal(sydney.error_code, 0);
|
||||||
assert(london.sunrise > 3 && london.sunrise < 6, 'sunrise between 3 and 6');
|
});
|
||||||
assert(london.sunset > 19 && london.sunset < 23, 'sunset between 19 and 23');
|
|
||||||
assert(london.error_code === 0, 'error_code is 0');
|
|
||||||
|
|
||||||
// ── Test 3: Equator, Equinox ──
|
it('repeated calls produce different results', async () => {
|
||||||
console.log('3. Quito (equator), March 20 2025, noon UTC-5');
|
const a = await spa(new Date(2023, 0, 1, 12, 0, 0), 40, -74, { timezone: -5 });
|
||||||
const quito = await spa(
|
const b = await spa(new Date(2023, 6, 1, 12, 0, 0), 40, -74, { timezone: -4 });
|
||||||
new Date(2025, 2, 20, 12, 0, 0),
|
assert.notEqual(a.zenith, b.zenith);
|
||||||
-0.1807, -78.4678,
|
assert.equal(a.error_code, 0);
|
||||||
{ timezone: -5, elevation: 2850 },
|
assert.equal(b.error_code, 0);
|
||||||
);
|
});
|
||||||
assert(quito.zenith < 20, 'near-overhead sun at equinox on equator');
|
|
||||||
assert(quito.error_code === 0, 'error_code is 0');
|
|
||||||
|
|
||||||
// ── Test 4: Sydney, Winter ──
|
it('concurrent calls all succeed', async () => {
|
||||||
console.log('4. Sydney, June 21 2025 (winter), noon AEST');
|
const [c1, c2, c3] = await Promise.all([
|
||||||
const sydney = await spa(
|
spa(new Date(2023, 0, 1, 12, 0, 0), 40, -74, { timezone: -5 }),
|
||||||
new Date(2025, 5, 21, 12, 0, 0),
|
spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, { timezone: -4 }),
|
||||||
-33.8688, 151.2093,
|
spa(new Date(2023, 6, 1, 12, 0, 0), 40, -74, { timezone: -4 }),
|
||||||
{ timezone: 10 },
|
]);
|
||||||
);
|
assert.equal(c1.error_code, 0);
|
||||||
assert(sydney.zenith > 50, 'low sun in southern winter');
|
assert.equal(c2.error_code, 0);
|
||||||
assert(sydney.sunrise > 6 && sydney.sunrise < 8, 'winter sunrise after 6');
|
assert.equal(c3.error_code, 0);
|
||||||
assert(sydney.error_code === 0, 'error_code is 0');
|
assert.notEqual(c1.zenith, c2.zenith);
|
||||||
|
});
|
||||||
|
|
||||||
// ── Test 5: Formatted output ──
|
it('boundary coordinates (poles and date line)', async () => {
|
||||||
console.log('5. Formatted output (NYC)');
|
const northPole = await spa(new Date(2025, 5, 21, 12, 0, 0), 90, 0, { timezone: 0 });
|
||||||
const fmt = await spaFormatted(
|
assert.equal(northPole.error_code, 0);
|
||||||
new Date(2023, 3, 1, 0, 0, 0),
|
const southPole = await spa(new Date(2025, 5, 21, 12, 0, 0), -90, 0, { timezone: 0 });
|
||||||
40.7128, -74.006,
|
assert.equal(southPole.error_code, 0);
|
||||||
{ timezone: -4, elevation: 10, temperature: 20, pressure: 1013.25 },
|
const dateLine = await spa(new Date(2025, 5, 21, 12, 0, 0), 0, 180, { timezone: 12 });
|
||||||
);
|
assert.equal(dateLine.error_code, 0);
|
||||||
assert(typeof fmt.sunrise === 'string', 'sunrise is a string');
|
const dateLineNeg = await spa(new Date(2025, 5, 21, 12, 0, 0), 0, -180, { timezone: -12 });
|
||||||
assert(typeof fmt.sunset === 'string', 'sunset is a string');
|
assert.equal(dateLineNeg.error_code, 0);
|
||||||
assert(typeof fmt.suntransit === 'string', 'suntransit is a string');
|
});
|
||||||
assert(/^\d{2}:\d{2}:\d{2}$/.test(fmt.sunrise), 'sunrise matches HH:MM:SS');
|
|
||||||
assert(typeof fmt.zenith === 'number', 'zenith remains numeric');
|
|
||||||
assert(typeof fmt.error_code === 'number', 'error_code is present in formatted result');
|
|
||||||
|
|
||||||
// ── Test 6: formatTime utility ──
|
it('arctic polar day', async () => {
|
||||||
console.log('6. formatTime utility');
|
const tromso = await spa(
|
||||||
assert(formatTime(0) === '00:00:00', 'midnight');
|
new Date(2025, 5, 21, 12, 0, 0),
|
||||||
assert(formatTime(12) === '12:00:00', 'noon');
|
69.6496, 18.9560,
|
||||||
assert(formatTime(6.5) === '06:30:00', '6.5 hours');
|
{ timezone: 2 },
|
||||||
assert(formatTime(23.9997) === '23:59:59', 'end of day');
|
);
|
||||||
assert(formatTime(Infinity) === 'N/A', 'Infinity returns N/A');
|
assert.equal(tromso.error_code, 0);
|
||||||
assert(formatTime(-Infinity) === 'N/A', '-Infinity returns N/A');
|
assert.ok(tromso.zenith < 50, 'sun is high at Tromso in summer');
|
||||||
assert(formatTime(NaN) === 'N/A', 'NaN returns N/A');
|
});
|
||||||
assert(formatTime(-1) === 'N/A', 'negative returns N/A');
|
|
||||||
assert(formatTime(-0.5) === 'N/A', 'negative fractional returns N/A');
|
|
||||||
assert(formatTime(24.0) === '00:00:00', '24h wraps to midnight');
|
|
||||||
assert(formatTime(24.5) === '00:30:00', '24.5h wraps to 00:30');
|
|
||||||
|
|
||||||
// ── Test 7: SPA error handling ──
|
it('historical date (year 1000)', async () => {
|
||||||
console.log('7. SPA error handling');
|
const historical = await spa(
|
||||||
await assertThrows(
|
new Date(1000, 5, 21, 12, 0, 0),
|
||||||
() => spa(new Date(2023, 0, 1), 40, -74, { timezone: 100 }),
|
40.7128, -74.006,
|
||||||
(e) => e.message.includes('error code'),
|
{ timezone: -5, delta_t: 1574 },
|
||||||
'invalid timezone throws with error code',
|
);
|
||||||
);
|
assert.equal(historical.error_code, 0);
|
||||||
|
assert.ok(historical.zenith > 0 && historical.zenith < 90, 'historical zenith is reasonable');
|
||||||
// ── Test 8: Input validation ──
|
});
|
||||||
console.log('8. Input validation');
|
});
|
||||||
await assertThrows(
|
|
||||||
() => spa(null, 40, -74),
|
describe('function codes', () => {
|
||||||
(e) => e instanceof TypeError,
|
it('SPA_ZA computes zenith and azimuth', async () => {
|
||||||
'null date throws TypeError',
|
const res = await spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, { timezone: -4, function: SPA_ZA });
|
||||||
);
|
assert.ok(res.zenith > 0);
|
||||||
await assertThrows(
|
assert.ok(res.azimuth > 0);
|
||||||
() => spa(new Date('invalid'), 40, -74),
|
assert.equal(res.error_code, 0);
|
||||||
(e) => e instanceof TypeError,
|
});
|
||||||
'invalid date throws TypeError',
|
|
||||||
);
|
it('all function codes succeed with consistent zenith', async () => {
|
||||||
await assertThrows(
|
const args = [new Date(2023, 3, 1, 12, 0, 0), 40, -74];
|
||||||
() => spa(new Date(), 'forty', -74),
|
const opts = { timezone: -4 };
|
||||||
(e) => e instanceof TypeError,
|
const zaRes = await spa(...args, { ...opts, function: SPA_ZA });
|
||||||
'string latitude throws TypeError',
|
const zaIncRes = await spa(...args, { ...opts, function: SPA_ZA_INC });
|
||||||
);
|
const zaRtsRes = await spa(...args, { ...opts, function: SPA_ZA_RTS });
|
||||||
await assertThrows(
|
const allRes = await spa(...args, { ...opts, function: SPA_ALL });
|
||||||
() => spa(new Date(), 40, undefined),
|
assert.equal(zaRes.error_code, 0);
|
||||||
(e) => e instanceof TypeError,
|
assert.equal(zaIncRes.error_code, 0);
|
||||||
'undefined longitude throws TypeError',
|
assert.equal(zaRtsRes.error_code, 0);
|
||||||
);
|
assert.equal(allRes.error_code, 0);
|
||||||
await assertThrows(
|
approx(zaRes.zenith, allRes.zenith, 0.001, 'zenith consistent across function codes');
|
||||||
() => spa(new Date(), 91, -74),
|
});
|
||||||
(e) => e instanceof RangeError,
|
});
|
||||||
'latitude > 90 throws RangeError',
|
|
||||||
);
|
describe('spaFormatted()', () => {
|
||||||
await assertThrows(
|
it('returns formatted time strings', async () => {
|
||||||
() => spa(new Date(), -91, -74),
|
const fmt = await spaFormatted(
|
||||||
(e) => e instanceof RangeError,
|
new Date(2023, 3, 1, 0, 0, 0),
|
||||||
'latitude < -90 throws RangeError',
|
40.7128, -74.006,
|
||||||
);
|
{ timezone: -4, elevation: 10, temperature: 20, pressure: 1013.25 },
|
||||||
await assertThrows(
|
);
|
||||||
() => spa(new Date(), 40, 181),
|
assert.equal(typeof fmt.sunrise, 'string');
|
||||||
(e) => e instanceof RangeError,
|
assert.equal(typeof fmt.sunset, 'string');
|
||||||
'longitude > 180 throws RangeError',
|
assert.equal(typeof fmt.suntransit, 'string');
|
||||||
);
|
assert.match(fmt.sunrise, /^\d{2}:\d{2}:\d{2}$/);
|
||||||
await assertThrows(
|
assert.equal(typeof fmt.zenith, 'number');
|
||||||
() => spa(new Date(), 40, -181),
|
assert.equal(typeof fmt.error_code, 'number');
|
||||||
(e) => e instanceof RangeError,
|
});
|
||||||
'longitude < -180 throws RangeError',
|
});
|
||||||
);
|
|
||||||
|
describe('formatTime()', () => {
|
||||||
// ── Test 9: Function code selection ──
|
it('formats standard values', () => {
|
||||||
console.log('9. Function code SPA_ZA (zenith/azimuth only)');
|
assert.equal(formatTime(0), '00:00:00');
|
||||||
const za = await spa(
|
assert.equal(formatTime(12), '12:00:00');
|
||||||
new Date(2023, 3, 1, 12, 0, 0),
|
assert.equal(formatTime(6.5), '06:30:00');
|
||||||
40.7128, -74.006,
|
assert.equal(formatTime(23.9997), '23:59:59');
|
||||||
{ timezone: -4, function: SPA_ZA },
|
});
|
||||||
);
|
|
||||||
assert(za.zenith > 0, 'zenith computed');
|
it('wraps at 24h', () => {
|
||||||
assert(za.azimuth > 0, 'azimuth computed');
|
assert.equal(formatTime(24.0), '00:00:00');
|
||||||
assert(za.error_code === 0, 'error_code is 0');
|
assert.equal(formatTime(24.5), '00:30:00');
|
||||||
|
});
|
||||||
// ── Test 10: Repeated calls (verify singleton init) ──
|
|
||||||
console.log('10. Repeated calls');
|
it('returns N/A for invalid inputs', () => {
|
||||||
const a = await spa(new Date(2023, 0, 1, 12, 0, 0), 40, -74, { timezone: -5 });
|
assert.equal(formatTime(Infinity), 'N/A');
|
||||||
const b = await spa(new Date(2023, 6, 1, 12, 0, 0), 40, -74, { timezone: -4 });
|
assert.equal(formatTime(-Infinity), 'N/A');
|
||||||
assert(a.zenith !== b.zenith, 'different dates produce different results');
|
assert.equal(formatTime(NaN), 'N/A');
|
||||||
assert(a.error_code === 0 && b.error_code === 0, 'both succeed');
|
assert.equal(formatTime(-1), 'N/A');
|
||||||
|
assert.equal(formatTime(-0.5), 'N/A');
|
||||||
// ── Test 11: Concurrent calls (verify init dedup) ──
|
});
|
||||||
console.log('11. Concurrent calls');
|
});
|
||||||
const [c1, c2, c3] = await Promise.all([
|
|
||||||
spa(new Date(2023, 0, 1, 12, 0, 0), 40, -74, { timezone: -5 }),
|
describe('input validation', () => {
|
||||||
spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, { timezone: -4 }),
|
it('rejects null date', async () => {
|
||||||
spa(new Date(2023, 6, 1, 12, 0, 0), 40, -74, { timezone: -4 }),
|
await assert.rejects(() => spa(null, 40, -74), TypeError);
|
||||||
]);
|
});
|
||||||
assert(c1.error_code === 0 && c2.error_code === 0 && c3.error_code === 0, 'all three concurrent calls succeed');
|
|
||||||
assert(c1.zenith !== c2.zenith, 'concurrent results differ by date');
|
it('rejects invalid date', async () => {
|
||||||
|
await assert.rejects(() => spa(new Date('invalid'), 40, -74), TypeError);
|
||||||
// ── Test 12: Boundary coordinates ──
|
});
|
||||||
console.log('12. Boundary coordinates');
|
|
||||||
const northPole = await spa(new Date(2025, 5, 21, 12, 0, 0), 90, 0, { timezone: 0 });
|
it('rejects string latitude', async () => {
|
||||||
assert(northPole.error_code === 0, 'north pole succeeds');
|
await assert.rejects(() => spa(new Date(), 'forty', -74), TypeError);
|
||||||
const southPole = await spa(new Date(2025, 5, 21, 12, 0, 0), -90, 0, { timezone: 0 });
|
});
|
||||||
assert(southPole.error_code === 0, 'south pole succeeds');
|
|
||||||
const dateLine = await spa(new Date(2025, 5, 21, 12, 0, 0), 0, 180, { timezone: 12 });
|
it('rejects undefined longitude', async () => {
|
||||||
assert(dateLine.error_code === 0, 'date line (180) succeeds');
|
await assert.rejects(() => spa(new Date(), 40, undefined), TypeError);
|
||||||
const dateLineNeg = await spa(new Date(2025, 5, 21, 12, 0, 0), 0, -180, { timezone: -12 });
|
});
|
||||||
assert(dateLineNeg.error_code === 0, 'date line (-180) succeeds');
|
|
||||||
|
it('rejects latitude > 90', async () => {
|
||||||
// ── Test 13: Arctic polar day (sun never sets) ──
|
await assert.rejects(() => spa(new Date(), 91, -74), RangeError);
|
||||||
console.log('13. Arctic polar day');
|
});
|
||||||
const tromso = await spa(
|
|
||||||
new Date(2025, 5, 21, 12, 0, 0),
|
it('rejects latitude < -90', async () => {
|
||||||
69.6496, 18.9560,
|
await assert.rejects(() => spa(new Date(), -91, -74), RangeError);
|
||||||
{ timezone: 2 },
|
});
|
||||||
);
|
|
||||||
assert(tromso.error_code === 0, 'Tromso summer succeeds');
|
it('rejects longitude > 180', async () => {
|
||||||
// During polar day, sunrise/sunset values from SPA may be non-standard
|
await assert.rejects(() => spa(new Date(), 40, 181), RangeError);
|
||||||
// The key is that the computation succeeds and zenith is low (sun is up)
|
});
|
||||||
assert(tromso.zenith < 50, 'sun is high at Tromso in summer');
|
|
||||||
|
it('rejects longitude < -180', async () => {
|
||||||
// ── Test 14: Explicit init() call ──
|
await assert.rejects(() => spa(new Date(), 40, -181), RangeError);
|
||||||
console.log('14. Explicit init()');
|
});
|
||||||
await init(); // should be a no-op since module is already loaded
|
|
||||||
const afterInit = await spa(new Date(2023, 0, 1, 12, 0, 0), 40, -74, { timezone: -5 });
|
it('rejects invalid timezone in SPA engine', async () => {
|
||||||
assert(afterInit.error_code === 0, 'spa works after explicit init');
|
await assert.rejects(
|
||||||
|
() => spa(new Date(2023, 0, 1), 40, -74, { timezone: 100 }),
|
||||||
// ── Test 15: Constants are correct ──
|
(err) => err.message.includes('error code'),
|
||||||
console.log('15. Constants');
|
);
|
||||||
assert(SPA_ZA === 0, 'SPA_ZA is 0');
|
});
|
||||||
assert(SPA_ZA_INC === 1, 'SPA_ZA_INC is 1');
|
});
|
||||||
assert(SPA_ZA_RTS === 2, 'SPA_ZA_RTS is 2');
|
|
||||||
assert(SPA_ALL === 3, 'SPA_ALL is 3');
|
describe('option validation', () => {
|
||||||
|
it('rejects non-number elevation', async () => {
|
||||||
// ── Test 16: Historical date ──
|
await assert.rejects(() => spa(new Date(), 40, -74, { elevation: 'high' }), TypeError);
|
||||||
console.log('16. Historical date (year 1000)');
|
});
|
||||||
const historical = await spa(
|
|
||||||
new Date(1000, 5, 21, 12, 0, 0),
|
it('rejects Infinity pressure', async () => {
|
||||||
40.7128, -74.006,
|
await assert.rejects(() => spa(new Date(), 40, -74, { pressure: Infinity }), RangeError);
|
||||||
{ timezone: -5, delta_t: 1574 },
|
});
|
||||||
);
|
|
||||||
assert(historical.error_code === 0, 'historical date succeeds');
|
it('rejects NaN temperature', async () => {
|
||||||
assert(historical.zenith > 0 && historical.zenith < 90, 'historical zenith is reasonable');
|
await assert.rejects(() => spa(new Date(), 40, -74, { temperature: NaN }), RangeError);
|
||||||
|
});
|
||||||
// ── Test 17: All function codes ──
|
|
||||||
console.log('17. All function codes');
|
it('rejects non-number delta_t', async () => {
|
||||||
const zaRes = await spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, { timezone: -4, function: SPA_ZA });
|
await assert.rejects(() => spa(new Date(), 40, -74, { delta_t: true }), TypeError);
|
||||||
const zaIncRes = await spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, { timezone: -4, function: SPA_ZA_INC });
|
});
|
||||||
const zaRtsRes = await spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, { timezone: -4, function: SPA_ZA_RTS });
|
|
||||||
const allRes = await spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, { timezone: -4, function: SPA_ALL });
|
it('rejects non-number slope', async () => {
|
||||||
assert(zaRes.error_code === 0, 'SPA_ZA succeeds');
|
await assert.rejects(() => spa(new Date(), 40, -74, { slope: null }), TypeError);
|
||||||
assert(zaIncRes.error_code === 0, 'SPA_ZA_INC succeeds');
|
});
|
||||||
assert(zaRtsRes.error_code === 0, 'SPA_ZA_RTS succeeds');
|
|
||||||
assert(allRes.error_code === 0, 'SPA_ALL succeeds');
|
it('rejects Infinity azm_rotation', async () => {
|
||||||
approx(zaRes.zenith, allRes.zenith, 0.001, 'zenith consistent across function codes');
|
await assert.rejects(() => spa(new Date(), 40, -74, { azm_rotation: -Infinity }), RangeError);
|
||||||
|
});
|
||||||
// ── Results ──
|
|
||||||
console.log('\n' + passed + ' passed, ' + failed + ' failed');
|
it('rejects non-number atmos_refract', async () => {
|
||||||
if (failed > 0) process.exit(1);
|
await assert.rejects(() => spa(new Date(), 40, -74, { atmos_refract: '0.5667' }), TypeError);
|
||||||
}
|
});
|
||||||
|
|
||||||
run().catch(function (err) {
|
it('accepts valid numeric options', async () => {
|
||||||
console.error(err);
|
const result = await spa(new Date(2023, 3, 1, 12, 0, 0), 40, -74, {
|
||||||
process.exit(1);
|
timezone: -4,
|
||||||
|
elevation: 100,
|
||||||
|
pressure: 1000,
|
||||||
|
temperature: 25,
|
||||||
|
delta_t: 69,
|
||||||
|
slope: 10,
|
||||||
|
azm_rotation: 180,
|
||||||
|
atmos_refract: 0.5,
|
||||||
|
});
|
||||||
|
assert.equal(result.error_code, 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('init()', () => {
|
||||||
|
it('explicit init is a no-op after module is loaded', async () => {
|
||||||
|
await init();
|
||||||
|
const result = await spa(new Date(2023, 0, 1, 12, 0, 0), 40, -74, { timezone: -5 });
|
||||||
|
assert.equal(result.error_code, 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('constants', () => {
|
||||||
|
it('SPA_ZA is 0', () => assert.equal(SPA_ZA, 0));
|
||||||
|
it('SPA_ZA_INC is 1', () => assert.equal(SPA_ZA_INC, 1));
|
||||||
|
it('SPA_ZA_RTS is 2', () => assert.equal(SPA_ZA_RTS, 2));
|
||||||
|
it('SPA_ALL is 3', () => assert.equal(SPA_ALL, 3));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"declarationMap": true,
|
"declarationMap": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue