Compare commits

..

1 Commits

Author SHA1 Message Date
francisco aloi
517221fac5 new components for name manager dialog and fields
new text added to locale en_us

added name manager to toolbar

added model and worksheets as prop

UPDATE: API for defined names

NamedRange component changes

NameManager dialog component changes

new util formatting functions

UPDATE: API for defined names

new components for name manager dialog and fields

new text added to locale en_us

added name manager to toolbar

added model and worksheets as prop

UPDATE: API for defined names

NamedRange component changes

NameManager dialog component changes

new util formatting functions

UPDATE: API for defined names

last changes

corrected styling

updates to namedRange and nameManagerDialog
2024-12-26 18:28:48 +01:00
243 changed files with 3611 additions and 20412 deletions

View File

@@ -1,446 +0,0 @@
name: nodejs
env:
DEBUG: napi:*
APP_NAME: nodejs
MACOSX_DEPLOYMENT_TARGET: '10.13'
permissions:
contents: write
id-token: write
'on':
workflow_dispatch:
inputs:
publish:
description: "Publish to npm"
required: true
type: boolean
defaults:
run:
working-directory: ./bindings/nodejs
jobs:
build:
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
build: yarn build --target x86_64-apple-darwin
- host: windows-latest
build: yarn build --target x86_64-pc-windows-msvc
target: x86_64-pc-windows-msvc
- host: ubuntu-latest
target: x86_64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian
build: yarn build --target x86_64-unknown-linux-gnu
- host: ubuntu-latest
target: x86_64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: yarn build --target x86_64-unknown-linux-musl
- host: macos-latest
target: aarch64-apple-darwin
build: yarn build --target aarch64-apple-darwin
- host: ubuntu-latest
target: aarch64-unknown-linux-gnu
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64
build: yarn build --target aarch64-unknown-linux-gnu
- host: ubuntu-latest
target: armv7-unknown-linux-gnueabihf
setup: |
sudo apt-get update
sudo apt-get install gcc-arm-linux-gnueabihf -y
build: yarn build --target armv7-unknown-linux-gnueabihf
- host: ubuntu-latest
target: armv7-unknown-linux-musleabihf
build: yarn build --target armv7-unknown-linux-musleabihf
- host: ubuntu-latest
target: aarch64-linux-android
build: yarn build --target aarch64-linux-android
- host: ubuntu-latest
target: armv7-linux-androideabi
build: yarn build --target armv7-linux-androideabi
- host: ubuntu-latest
target: aarch64-unknown-linux-musl
docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine
build: |-
set -e &&
rustup target add aarch64-unknown-linux-musl &&
yarn build --target aarch64-unknown-linux-musl
- host: windows-latest
target: aarch64-pc-windows-msvc
build: yarn build --target aarch64-pc-windows-msvc
- host: ubuntu-latest
target: riscv64gc-unknown-linux-gnu
setup: |
sudo apt-get update
sudo apt-get install gcc-riscv64-linux-gnu -y
build: yarn build --target riscv64gc-unknown-linux-gnu
name: stable - ${{ matrix.settings.target }} - node@20
runs-on: ${{ matrix.settings.host }}
defaults:
run:
working-directory: ./bindings/nodejs
steps:
- uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v4
if: ${{ !matrix.settings.docker }}
with:
node-version: 20
cache: yarn
cache-dependency-path: "bindings/nodejs"
- name: Install
uses: dtolnay/rust-toolchain@stable
if: ${{ !matrix.settings.docker }}
with:
toolchain: stable
targets: ${{ matrix.settings.target }}
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
.cargo-cache
target/
key: ${{ matrix.settings.target }}-cargo-${{ matrix.settings.host }}
- uses: goto-bus-stop/setup-zig@v2
if: ${{ matrix.settings.target == 'armv7-unknown-linux-gnueabihf' || matrix.settings.target == 'armv7-unknown-linux-musleabihf' }}
with:
version: 0.13.0
- name: Setup toolchain
run: ${{ matrix.settings.setup }}
if: ${{ matrix.settings.setup }}
shell: bash
- name: Install dependencies
run: yarn install
- name: Build in docker
uses: addnab/docker-run-action@v3
if: ${{ matrix.settings.docker }}
with:
image: ${{ matrix.settings.docker }}
options: '--user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/usr/local/cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/usr/local/cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/usr/local/cargo/registry/index -v ${{ github.workspace }}:/build -w /build/bindings/nodejs'
run: ${{ matrix.settings.build }}
- name: Build
run: ${{ matrix.settings.build }}
if: ${{ !matrix.settings.docker }}
shell: bash
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: bindings/nodejs/${{ env.APP_NAME }}.*.node
if-no-files-found: error
test-macOS-windows-binding:
name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
settings:
- host: macos-latest
target: x86_64-apple-darwin
- host: windows-latest
target: x86_64-pc-windows-msvc
node:
- '18'
- '20'
runs-on: ${{ matrix.settings.host }}
defaults:
run:
working-directory: ./bindings/nodejs
steps:
- uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: yarn
cache-dependency-path: "bindings/nodejs"
architecture: x64
- name: Install dependencies
run: yarn install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-${{ matrix.settings.target }}
path: bindings/nodejs/
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
run: yarn test
test-linux-x64-gnu-binding:
name: Test bindings on Linux-x64-gnu - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- '18'
- '20'
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./bindings/nodejs
steps:
- uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: yarn
cache-dependency-path: "bindings/nodejs"
- name: Install dependencies
run: yarn install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-x86_64-unknown-linux-gnu
path: bindings/nodejs/
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
run: docker run --rm -v $(pwd):/build -w /build/bindings/nodejs node:${{ matrix.node }}-slim yarn test
test-linux-x64-musl-binding:
name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- '18'
- '20'
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./bindings/nodejs
steps:
- uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: yarn
cache-dependency-path: "bindings/nodejs"
- name: Install dependencies
run: |
yarn config set supportedArchitectures.libc "musl"
yarn install
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-x86_64-unknown-linux-musl
path: bindings/nodejs/
- name: List packages
run: ls -R .
shell: bash
- name: Test bindings
run: docker run --rm -v $(pwd):/build -w /build/bindings/nodejs node:${{ matrix.node }}-alpine yarn test
test-linux-aarch64-gnu-binding:
name: Test bindings on aarch64-unknown-linux-gnu - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- '18'
- '20'
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./bindings/nodejs
steps:
- uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-aarch64-unknown-linux-gnu
path: bindings/nodejs/
- name: List packages
run: ls -R .
shell: bash
- name: Install dependencies
run: |
yarn config set supportedArchitectures.cpu "arm64"
yarn config set supportedArchitectures.libc "glibc"
yarn install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:${{ matrix.node }}-slim
options: '--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build/bindings/nodejs'
run: |
set -e
yarn test
ls -la
test-linux-aarch64-musl-binding:
name: Test bindings on aarch64-unknown-linux-musl - node@${{ matrix.node }}
needs:
- build
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./bindings/nodejs
steps:
- uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-aarch64-unknown-linux-musl
path: bindings/nodejs/
- name: List packages
run: ls -R .
shell: bash
- name: Install dependencies
run: |
yarn config set supportedArchitectures.cpu "arm64"
yarn config set supportedArchitectures.libc "musl"
yarn install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:lts-alpine
options: '--platform linux/arm64 -v ${{ github.workspace }}:/build -w /build/bindings/nodejs'
run: |
set -e
yarn test
test-linux-arm-gnueabihf-binding:
name: Test bindings on armv7-unknown-linux-gnueabihf - node@${{ matrix.node }}
needs:
- build
strategy:
fail-fast: false
matrix:
node:
- '18'
- '20'
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./bindings/nodejs
steps:
- uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: bindings-armv7-unknown-linux-gnueabihf
path: bindings/nodejs/
- name: List packages
run: ls -R .
shell: bash
- name: Install dependencies
run: |
yarn config set supportedArchitectures.cpu "arm"
yarn install
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm
- run: docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
- name: Setup and run tests
uses: addnab/docker-run-action@v3
with:
image: node:${{ matrix.node }}-bullseye-slim
options: '--platform linux/arm/v7 -v ${{ github.workspace }}:/build -w /build/bindings/nodejs'
run: |
set -e
yarn test
ls -la
universal-macOS:
name: Build universal macOS binary
needs:
- build
runs-on: macos-latest
defaults:
run:
working-directory: ./bindings/nodejs
steps:
- uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
cache-dependency-path: "bindings/nodejs"
- name: Install dependencies
run: yarn install
- name: Download macOS x64 artifact
uses: actions/download-artifact@v4
with:
name: bindings-x86_64-apple-darwin
path: bindings/nodejs/artifacts
- name: Download macOS arm64 artifact
uses: actions/download-artifact@v4
with:
name: bindings-aarch64-apple-darwin
path: bindings/nodejs/artifacts
- name: Combine binaries
run: yarn universal
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: bindings-universal-apple-darwin
path: bindings/nodejs/${{ env.APP_NAME }}.*.node
if-no-files-found: error
publish:
name: Publish
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./bindings/nodejs
needs:
- test-macOS-windows-binding
- test-linux-x64-gnu-binding
- test-linux-x64-musl-binding
- test-linux-aarch64-gnu-binding
- test-linux-aarch64-musl-binding
- test-linux-arm-gnueabihf-binding
- universal-macOS
steps:
- uses: actions/checkout@v4
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: 20
cache: yarn
cache-dependency-path: "bindings/nodejs"
- name: Install dependencies
run: yarn install
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: bindings/nodejs/artifacts
- name: Move artifacts
run: yarn artifacts
- name: List packages
run: ls -R ./npm
shell: bash
- name: Publish
run: |
echo "${{ github.event.inputs.publish }}"
if [ "${{ github.event.inputs.publish }}" = "true" ]; then
echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
npm publish --access public
echo "Published to npm"
else
echo "Not a release, skipping publish"
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

3
.gitignore vendored
View File

@@ -1,3 +1,2 @@
target/*
**/node_modules/**
.DS_Store
.DS_Store

View File

@@ -7,7 +7,6 @@
- New function UNICODE ([#128](https://github.com/ironcalc/IronCalc/pull/128))
- New document server (Thanks Dani!)
- New function FORMULATEXT
- Name Manager ([#212](https://github.com/ironcalc/IronCalc/pull/212) [#220](https://github.com/ironcalc/IronCalc/pull/220))
### Fixed

145
Cargo.lock generated
View File

@@ -85,12 +85,6 @@ dependencies = [
"syn",
]
[[package]]
name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
[[package]]
name = "block-buffer"
version = "0.10.4"
@@ -216,15 +210,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "convert_case"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
@@ -286,16 +271,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "ctor"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "deranged"
version = "0.3.11"
@@ -414,7 +389,7 @@ dependencies = [
[[package]]
name = "ironcalc"
version = "0.3.0"
version = "0.2.0"
dependencies = [
"bitcode",
"chrono",
@@ -430,7 +405,7 @@ dependencies = [
[[package]]
name = "ironcalc_base"
version = "0.3.0"
version = "0.2.0"
dependencies = [
"bitcode",
"chrono",
@@ -446,17 +421,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "ironcalc_nodejs"
version = "0.3.1"
dependencies = [
"ironcalc",
"napi",
"napi-build",
"napi-derive",
"serde",
]
[[package]]
name = "itertools"
version = "0.12.1"
@@ -496,16 +460,6 @@ version = "0.2.153"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "libloading"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets",
]
[[package]]
name = "log"
version = "0.4.21"
@@ -536,65 +490,6 @@ dependencies = [
"adler",
]
[[package]]
name = "napi"
version = "2.16.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "214f07a80874bb96a8433b3cdfc84980d56c7b02e1a0d7ba4ba0db5cef785e2b"
dependencies = [
"bitflags",
"ctor",
"napi-derive",
"napi-sys",
"once_cell",
"serde",
"serde_json",
]
[[package]]
name = "napi-build"
version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db836caddef23662b94e16bf1f26c40eceb09d6aee5d5b06a7ac199320b69b19"
[[package]]
name = "napi-derive"
version = "2.16.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cbe2585d8ac223f7d34f13701434b9d5f4eb9c332cccce8dee57ea18ab8ab0c"
dependencies = [
"cfg-if",
"convert_case",
"napi-derive-backend",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "napi-derive-backend"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1639aaa9eeb76e91c6ae66da8ce3e89e921cd3885e99ec85f4abacae72fc91bf"
dependencies = [
"convert_case",
"once_cell",
"proc-macro2",
"quote",
"regex",
"semver",
"syn",
]
[[package]]
name = "napi-sys"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3"
dependencies = [
"libloading",
]
[[package]]
name = "num-conv"
version = "0.1.0"
@@ -721,9 +616,9 @@ dependencies = [
[[package]]
name = "pyo3"
version = "0.23.4"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57fe09249128b3173d092de9523eaa75136bf7ba85e0d69eca241c7939c933cc"
checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225"
dependencies = [
"cfg-if",
"indoc",
@@ -739,9 +634,9 @@ dependencies = [
[[package]]
name = "pyo3-build-config"
version = "0.23.4"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd3927b5a78757a0d71aa9dff669f903b1eb64b54142a9bd9f757f8fde65fd7"
checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3"
dependencies = [
"once_cell",
"target-lexicon",
@@ -749,9 +644,9 @@ dependencies = [
[[package]]
name = "pyo3-ffi"
version = "0.23.4"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dab6bb2102bd8f991e7749f130a70d05dd557613e39ed2deeee8e9ca0c4d548d"
checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c"
dependencies = [
"libc",
"pyo3-build-config",
@@ -759,9 +654,9 @@ dependencies = [
[[package]]
name = "pyo3-macros"
version = "0.23.4"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91871864b353fd5ffcb3f91f2f703a22a9797c91b9ab497b1acac7b07ae509c7"
checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
@@ -771,9 +666,9 @@ dependencies = [
[[package]]
name = "pyo3-macros-backend"
version = "0.23.4"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43abc3b80bc20f3facd86cd3c60beed58c3e2aa26213f3cda368de39c60a27e4"
checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1"
dependencies = [
"heck",
"proc-macro2",
@@ -784,7 +679,7 @@ dependencies = [
[[package]]
name = "pyroncalc"
version = "0.3.0"
version = "0.1.2"
dependencies = [
"ironcalc",
"pyo3",
@@ -884,12 +779,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "semver"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
[[package]]
name = "serde"
version = "1.0.197"
@@ -1034,12 +923,6 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unindent"
version = "0.2.3"
@@ -1070,7 +953,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm"
version = "0.3.0"
version = "0.1.3"
dependencies = [
"ironcalc_base",
"serde",

View File

@@ -6,12 +6,10 @@ members = [
"xlsx",
"bindings/wasm",
"bindings/python",
"bindings/nodejs",
]
exclude = [
"generate_locale",
"webapp/app.ironcalc.com/server",
]
[profile.release]

View File

@@ -2,8 +2,7 @@
lint:
cargo fmt -- --check
cargo clippy --all-targets --all-features -- -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic -D warnings
cd webapp/IronCalc/ && npm install && npm run check
cd webapp/app.ironcalc.com/frontend/ && npm install && npm run check
cd webapp && npm install && npm run check
.PHONY: format
format:
@@ -16,7 +15,7 @@ tests: lint
# Regretabbly we need to build the wasm twice, once for the nodejs tests
# and a second one for the vitest.
cd bindings/wasm/ && wasm-pack build --target nodejs && node tests/test.mjs && make
cd webapp/IronCalc/ && npm run test
cd webapp && npm run test
cd bindings/python && ./run_tests.sh && ./run_examples.sh
.PHONY: remove-artifacts

View File

@@ -1,11 +1,11 @@
[package]
name = "ironcalc_base"
version = "0.3.0"
version = "0.2.0"
authors = ["Nicolás Hatcher <nicolas@theuniverse.today>"]
edition = "2021"
homepage = "https://www.ironcalc.com"
repository = "https://github.com/ironcalc/ironcalc/"
description = "Open source spreadsheet engine"
description = "The democratization of spreadsheets"
license = "MIT OR Apache-2.0"
readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@@ -16,10 +16,3 @@ pub(crate) const LAST_ROW: i32 = 1_048_576;
// NaiveDate::from_ymd(1900, 1, 1).num_days_from_ce() - 2
// The 2 days offset is because of Excel 1900 bug
pub(crate) const EXCEL_DATE_BASE: i32 = 693_594;
// We do not support dates before 1899-12-31.
pub(crate) const MINIMUM_DATE_SERIAL_NUMBER: i32 = 1;
// Excel can handle dates until the year 9999-12-31
// 2958465 is the number of days from 1900-01-01 to 9999-12-31
pub(crate) const MAXIMUM_DATE_SERIAL_NUMBER: i32 = 2_958_465;

View File

@@ -642,38 +642,7 @@ impl Parser {
position: 0,
message: "Unexpected end of input.".to_string(),
},
TokenType::Boolean(value) => {
// Could be a function call "TRUE()"
let next_token = self.lexer.peek_token();
if next_token == TokenType::LeftParenthesis {
self.lexer.advance_token();
// We parse all the arguments, although technically this is moot
// But is has the upside of transforming `=TRUE( 4 )` into `=TRUE(4)`
let args = match self.parse_function_args() {
Ok(s) => s,
Err(e) => return e,
};
if let Err(err) = self.lexer.expect(TokenType::RightParenthesis) {
return Node::ParseErrorKind {
formula: self.lexer.get_formula(),
position: err.position,
message: err.message,
};
}
if value {
return Node::FunctionKind {
kind: Function::True,
args,
};
} else {
return Node::FunctionKind {
kind: Function::False,
args,
};
}
}
Node::BooleanKind(value)
}
TokenType::Boolean(value) => Node::BooleanKind(value),
TokenType::Compare(_) => {
// A primary Node cannot start with an operator
Node::ParseErrorKind {

View File

@@ -1,158 +1,18 @@
use chrono::Datelike;
use chrono::Days;
use chrono::Duration;
use chrono::Months;
use chrono::NaiveDate;
use crate::constants::EXCEL_DATE_BASE;
use crate::constants::MAXIMUM_DATE_SERIAL_NUMBER;
use crate::constants::MINIMUM_DATE_SERIAL_NUMBER;
#[inline]
fn convert_to_serial_number(date: NaiveDate) -> i32 {
date.num_days_from_ce() - EXCEL_DATE_BASE
}
fn is_date_within_range(date: NaiveDate) -> bool {
convert_to_serial_number(date) >= MINIMUM_DATE_SERIAL_NUMBER
&& convert_to_serial_number(date) <= MAXIMUM_DATE_SERIAL_NUMBER
}
pub fn from_excel_date(days: i64) -> Result<NaiveDate, String> {
if days < MINIMUM_DATE_SERIAL_NUMBER as i64 {
return Err(format!(
"Excel date must be greater than {}",
MINIMUM_DATE_SERIAL_NUMBER
));
};
if days > MAXIMUM_DATE_SERIAL_NUMBER as i64 {
return Err(format!(
"Excel date must be less than {}",
MAXIMUM_DATE_SERIAL_NUMBER
));
};
pub fn from_excel_date(days: i64) -> NaiveDate {
#[allow(clippy::expect_used)]
let dt = NaiveDate::from_ymd_opt(1900, 1, 1).expect("problem with chrono::NaiveDate");
Ok(dt + Duration::days(days - 2))
dt + Duration::days(days - 2)
}
pub fn date_to_serial_number(day: u32, month: u32, year: i32) -> Result<i32, String> {
match NaiveDate::from_ymd_opt(year, month, day) {
Some(native_date) => Ok(convert_to_serial_number(native_date)),
Some(native_date) => Ok(native_date.num_days_from_ce() - EXCEL_DATE_BASE),
None => Err("Out of range parameters for date".to_string()),
}
}
pub fn permissive_date_to_serial_number(day: i32, month: i32, year: i32) -> Result<i32, String> {
// Excel parses `DATE` very permissively. It allows not just for valid date values, but it
// allows for invalid dates as well. If you for example enter `DATE(1900, 1, 32)` it will
// return the date `1900-02-01`. Despite giving a day that is out of range it will just
// wrap the month and year around.
//
// This function applies that same logic to dates. And does it in the most compatible way as
// possible.
// Special case for the minimum date
if year == 1899 && month == 12 && day == 31 {
return Ok(MINIMUM_DATE_SERIAL_NUMBER);
}
let Some(mut date) = NaiveDate::from_ymd_opt(year, 1, 1) else {
return Err("Out of range parameters for date".to_string());
};
// One thing to note for example is that even if you started with a year out of range
// but tried to increment the months so that it wraps around into within range, excel
// would still return an error.
//
// I.E. DATE(0,13,-1) will return an error, despite it being equivalent to DATE(1,1,0) which
// is within range.
//
// As a result, we have to run range checks as we parse the date from the biggest unit to the
// smallest unit.
if !is_date_within_range(date) {
return Err("Out of range parameters for date".to_string());
}
date = {
let month_diff = month - 1;
let abs_month = month_diff.unsigned_abs();
if month_diff <= 0 {
date = date - Months::new(abs_month);
} else {
date = date + Months::new(abs_month);
}
if !is_date_within_range(date) {
return Err("Out of range parameters for date".to_string());
}
date
};
date = {
let day_diff = day - 1;
let abs_day = day_diff.unsigned_abs() as u64;
if day_diff <= 0 {
date = date - Days::new(abs_day);
} else {
date = date + Days::new(abs_day);
}
if !is_date_within_range(date) {
return Err("Out of range parameters for date".to_string());
}
date
};
Ok(convert_to_serial_number(date))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_permissive_date_to_serial_number() {
assert_eq!(
permissive_date_to_serial_number(42, 42, 2002),
date_to_serial_number(12, 7, 2005)
);
assert_eq!(
permissive_date_to_serial_number(1, 42, 2002),
date_to_serial_number(1, 6, 2005)
);
assert_eq!(
permissive_date_to_serial_number(1, 15, 2000),
date_to_serial_number(1, 3, 2001)
);
assert_eq!(
permissive_date_to_serial_number(1, 49, 2000),
date_to_serial_number(1, 1, 2004)
);
assert_eq!(
permissive_date_to_serial_number(1, 49, 2000),
date_to_serial_number(1, 1, 2004)
);
assert_eq!(
permissive_date_to_serial_number(31, 49, 2000),
date_to_serial_number(31, 1, 2004)
);
assert_eq!(
permissive_date_to_serial_number(256, 49, 2000),
date_to_serial_number(12, 9, 2004)
);
assert_eq!(
permissive_date_to_serial_number(256, 1, 2004),
date_to_serial_number(12, 9, 2004)
);
}
#[test]
fn test_max_and_min_dates() {
assert_eq!(
permissive_date_to_serial_number(31, 12, 9999),
Ok(MAXIMUM_DATE_SERIAL_NUMBER),
);
assert_eq!(
permissive_date_to_serial_number(31, 12, 1899),
Ok(MINIMUM_DATE_SERIAL_NUMBER),
);
}
}

View File

@@ -154,16 +154,15 @@ pub fn format_number(value_original: f64, format: &str, locale: &Locale) -> Form
ParsePart::Date(p) => {
let tokens = &p.tokens;
let mut text = "".to_string();
let date = match from_excel_date(value as i64) {
Ok(d) => d,
Err(e) => {
return Formatted {
text: "#VALUE!".to_owned(),
color: None,
error: Some(e),
}
}
};
if !(1.0..=2_958_465.0).contains(&value) {
// 2_958_465 is 31 December 9999
return Formatted {
text: "#VALUE!".to_owned(),
color: None,
error: Some("Date negative or too long".to_owned()),
};
}
let date = from_excel_date(value as i64);
for token in tokens {
match token {
TextToken::Literal(c) => {

View File

@@ -3,11 +3,8 @@ use chrono::Datelike;
use chrono::Months;
use chrono::Timelike;
use crate::constants::MAXIMUM_DATE_SERIAL_NUMBER;
use crate::constants::MINIMUM_DATE_SERIAL_NUMBER;
use crate::expressions::types::CellReferenceIndex;
use crate::formatter::dates::date_to_serial_number;
use crate::formatter::dates::permissive_date_to_serial_number;
use crate::model::get_milliseconds_since_epoch;
use crate::{
calc_result::CalcResult, constants::EXCEL_DATE_BASE, expressions::parser::Node,
@@ -21,19 +18,20 @@ impl Model {
return CalcResult::new_args_number_error(cell);
}
let serial_number = match self.get_number(&args[0], cell) {
Ok(c) => c.floor() as i64,
Ok(c) => {
let t = c.floor() as i64;
if t < 0 {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Function DAY parameter 1 value is negative. It should be positive or zero.".to_string(),
};
}
t
}
Err(s) => return s,
};
let date = match from_excel_date(serial_number) {
Ok(date) => date,
Err(_) => {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Out of range parameters for date".to_string(),
}
}
};
let date = from_excel_date(serial_number);
let day = date.day() as f64;
CalcResult::Number(day)
}
@@ -44,19 +42,20 @@ impl Model {
return CalcResult::new_args_number_error(cell);
}
let serial_number = match self.get_number(&args[0], cell) {
Ok(c) => c.floor() as i64,
Ok(c) => {
let t = c.floor() as i64;
if t < 0 {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Function MONTH parameter 1 value is negative. It should be positive or zero.".to_string(),
};
}
t
}
Err(s) => return s,
};
let date = match from_excel_date(serial_number) {
Ok(date) => date,
Err(_) => {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Out of range parameters for date".to_string(),
}
}
};
let date = from_excel_date(serial_number);
let month = date.month() as f64;
CalcResult::Number(month)
}
@@ -80,23 +79,6 @@ impl Model {
}
Err(s) => return s,
};
let date = match from_excel_date(serial_number) {
Ok(date) => date,
Err(_) => {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Out of range parameters for date".to_string(),
}
}
};
if serial_number > MAXIMUM_DATE_SERIAL_NUMBER as i64 {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Function DAY parameter 1 value is too large.".to_string(),
};
}
let months = match self.get_number_no_bools(&args[1], cell) {
Ok(c) => {
@@ -109,9 +91,9 @@ impl Model {
let months_abs = months.unsigned_abs();
let native_date = if months > 0 {
date + Months::new(months_abs)
from_excel_date(serial_number) + Months::new(months_abs)
} else {
date - Months::new(months_abs)
from_excel_date(serial_number) - Months::new(months_abs)
};
// Instead of calculating the end of month we compute the first day of the following month
@@ -155,18 +137,32 @@ impl Model {
let month = match self.get_number(&args[1], cell) {
Ok(c) => {
let t = c.floor();
t as i32
if t < 0.0 {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Out of range parameters for date".to_string(),
};
}
t as u32
}
Err(s) => return s,
};
let day = match self.get_number(&args[2], cell) {
Ok(c) => {
let t = c.floor();
t as i32
if t < 0.0 {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Out of range parameters for date".to_string(),
};
}
t as u32
}
Err(s) => return s,
};
match permissive_date_to_serial_number(day, month, year) {
match date_to_serial_number(day, month, year) {
Ok(serial_number) => CalcResult::Number(serial_number as f64),
Err(message) => CalcResult::Error {
error: Error::NUM,
@@ -182,19 +178,20 @@ impl Model {
return CalcResult::new_args_number_error(cell);
}
let serial_number = match self.get_number(&args[0], cell) {
Ok(c) => c.floor() as i64,
Ok(c) => {
let t = c.floor() as i64;
if t < 0 {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Function YEAR parameter 1 value is negative. It should be positive or zero.".to_string(),
};
}
t
}
Err(s) => return s,
};
let date = match from_excel_date(serial_number) {
Ok(date) => date,
Err(_) => {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Out of range parameters for date".to_string(),
}
}
};
let date = from_excel_date(serial_number);
let year = date.year() as f64;
CalcResult::Number(year)
}
@@ -206,18 +203,19 @@ impl Model {
return CalcResult::new_args_number_error(cell);
}
let serial_number = match self.get_number(&args[0], cell) {
Ok(c) => c.floor() as i64,
Err(s) => return s,
};
let date = match from_excel_date(serial_number) {
Ok(date) => date,
Err(_) => {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Out of range parameters for date".to_string(),
Ok(c) => {
let t = c.floor() as i64;
if t < 0 {
return CalcResult::Error {
error: Error::NUM,
origin: cell,
message: "Parameter 1 value is negative. It should be positive or zero."
.to_string(),
};
}
t
}
Err(s) => return s,
};
let months = match self.get_number(&args[1], cell) {
@@ -231,13 +229,13 @@ impl Model {
let months_abs = months.unsigned_abs();
let native_date = if months > 0 {
date + Months::new(months_abs)
from_excel_date(serial_number) + Months::new(months_abs)
} else {
date - Months::new(months_abs)
from_excel_date(serial_number) - Months::new(months_abs)
};
let serial_number = native_date.num_days_from_ce() - EXCEL_DATE_BASE;
if serial_number < MINIMUM_DATE_SERIAL_NUMBER {
if serial_number < 0 {
return CalcResult::Error {
error: Error::NUM,
origin: cell,

View File

@@ -188,7 +188,10 @@ impl Model {
node: &Node,
cell: CellReferenceIndex,
) -> Result<(f64, f64, Suffix), CalcResult> {
let value = self.get_string(node, cell)?;
let value = match self.get_string(node, cell) {
Ok(s) => s,
Err(s) => return Err(s),
};
if value.is_empty() {
return Ok((0.0, 0.0, Suffix::I));
}

View File

@@ -2,7 +2,7 @@ use chrono::Datelike;
use crate::{
calc_result::CalcResult,
constants::{LAST_COLUMN, LAST_ROW, MAXIMUM_DATE_SERIAL_NUMBER, MINIMUM_DATE_SERIAL_NUMBER},
constants::{LAST_COLUMN, LAST_ROW},
expressions::{parser::Node, token::Error, types::CellReferenceIndex},
formatter::dates::from_excel_date,
model::Model,
@@ -13,32 +13,37 @@ use super::financial_util::{compute_irr, compute_npv, compute_rate, compute_xirr
// See:
// https://github.com/apache/openoffice/blob/c014b5f2b55cff8d4b0c952d5c16d62ecde09ca1/main/scaddins/source/analysis/financial.cxx
fn is_less_than_one_year(start_date: i64, end_date: i64) -> Result<bool, String> {
let end = from_excel_date(end_date)?;
let start = from_excel_date(start_date)?;
// FIXME: Is this enough?
fn is_valid_date(date: f64) -> bool {
date > 0.0
}
fn is_less_than_one_year(start_date: i64, end_date: i64) -> bool {
if end_date - start_date < 365 {
return Ok(true);
return true;
}
let end = from_excel_date(end_date);
let start = from_excel_date(start_date);
let end_year = end.year();
let start_year = start.year();
if end_year == start_year {
return Ok(true);
return true;
}
if end_year != start_year + 1 {
return Ok(false);
return false;
}
let start_month = start.month();
let end_month = end.month();
if end_month < start_month {
return Ok(true);
return true;
}
if end_month > start_month {
return Ok(false);
return false;
}
// we are one year later same month
let start_day = start.day();
let end_day = end.day();
Ok(end_day <= start_day)
end_day <= start_day
}
fn compute_payment(
@@ -431,7 +436,7 @@ impl Model {
}
if rate == -1.0 {
return CalcResult::Error {
error: Error::DIV,
error: Error::NUM,
origin: cell,
message: "Rate must be != -1".to_string(),
};
@@ -918,9 +923,7 @@ impl Model {
}
let first_date = dates[0];
for date in &dates {
if *date < MINIMUM_DATE_SERIAL_NUMBER as f64
|| *date > MAXIMUM_DATE_SERIAL_NUMBER as f64
{
if !is_valid_date(*date) {
// Excel docs claim that if any number in dates is not a valid date,
// XNPV returns the #VALUE! error value, but it seems to return #VALUE!
return CalcResult::new_error(
@@ -986,9 +989,7 @@ impl Model {
}
let first_date = dates[0];
for date in &dates {
if *date < MINIMUM_DATE_SERIAL_NUMBER as f64
|| *date > MAXIMUM_DATE_SERIAL_NUMBER as f64
{
if !is_valid_date(*date) {
return CalcResult::new_error(
Error::NUM,
cell,
@@ -1372,10 +1373,9 @@ impl Model {
Ok(f) => f,
Err(s) => return s,
};
let less_than_one_year = match is_less_than_one_year(settlement as i64, maturity as i64) {
Ok(f) => f,
Err(_) => return CalcResult::new_error(Error::NUM, cell, "Invalid date".to_string()),
};
if !is_valid_date(settlement) || !is_valid_date(maturity) {
return CalcResult::new_error(Error::NUM, cell, "Invalid date".to_string());
}
if settlement > maturity {
return CalcResult::new_error(
Error::NUM,
@@ -1383,7 +1383,7 @@ impl Model {
"settlement should be <= maturity".to_string(),
);
}
if !less_than_one_year {
if !is_less_than_one_year(settlement as i64, maturity as i64) {
return CalcResult::new_error(
Error::NUM,
cell,
@@ -1437,10 +1437,9 @@ impl Model {
Ok(f) => f,
Err(s) => return s,
};
let less_than_one_year = match is_less_than_one_year(settlement as i64, maturity as i64) {
Ok(f) => f,
Err(_) => return CalcResult::new_error(Error::NUM, cell, "Invalid date".to_string()),
};
if !is_valid_date(settlement) || !is_valid_date(maturity) {
return CalcResult::new_error(Error::NUM, cell, "Invalid date".to_string());
}
if settlement > maturity {
return CalcResult::new_error(
Error::NUM,
@@ -1448,7 +1447,7 @@ impl Model {
"settlement should be <= maturity".to_string(),
);
}
if !less_than_one_year {
if !is_less_than_one_year(settlement as i64, maturity as i64) {
return CalcResult::new_error(
Error::NUM,
cell,
@@ -1488,10 +1487,9 @@ impl Model {
Ok(f) => f,
Err(s) => return s,
};
let less_than_one_year = match is_less_than_one_year(settlement as i64, maturity as i64) {
Ok(f) => f,
Err(_) => return CalcResult::new_error(Error::NUM, cell, "Invalid date".to_string()),
};
if !is_valid_date(settlement) || !is_valid_date(maturity) {
return CalcResult::new_error(Error::NUM, cell, "Invalid date".to_string());
}
if settlement > maturity {
return CalcResult::new_error(
Error::NUM,
@@ -1499,7 +1497,7 @@ impl Model {
"settlement should be <= maturity".to_string(),
);
}
if !less_than_one_year {
if !is_less_than_one_year(settlement as i64, maturity as i64) {
return CalcResult::new_error(
Error::NUM,
cell,

View File

@@ -7,22 +7,6 @@ use crate::{
use super::util::compare_values;
impl Model {
pub(crate) fn fn_true(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.is_empty() {
CalcResult::Boolean(true)
} else {
CalcResult::new_args_number_error(cell)
}
}
pub(crate) fn fn_false(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.is_empty() {
CalcResult::Boolean(false)
} else {
CalcResult::new_args_number_error(cell)
}
}
pub(crate) fn fn_if(&mut self, args: &[Node], cell: CellReferenceIndex) -> CalcResult {
if args.len() == 2 || args.len() == 3 {
let cond_result = self.get_boolean(&args[0], cell);

View File

@@ -949,7 +949,7 @@ impl Model {
match kind {
// Logical
Function::And => self.fn_and(args, cell),
Function::False => self.fn_false(args, cell),
Function::False => CalcResult::Boolean(false),
Function::If => self.fn_if(args, cell),
Function::Iferror => self.fn_iferror(args, cell),
Function::Ifna => self.fn_ifna(args, cell),
@@ -957,7 +957,7 @@ impl Model {
Function::Not => self.fn_not(args, cell),
Function::Or => self.fn_or(args, cell),
Function::Switch => self.fn_switch(args, cell),
Function::True => self.fn_true(args, cell),
Function::True => CalcResult::Boolean(true),
Function::Xor => self.fn_xor(args, cell),
// Math and trigonometry
Function::Sin => self.fn_sin(args, cell),

View File

@@ -960,7 +960,10 @@ impl Model {
}
}
}
let sheet = self.get_sheet_index_by_name(&sheet_name)?;
let sheet = match self.get_sheet_index_by_name(&sheet_name) {
Some(s) => s,
None => return None,
};
let row = match row.parse::<i32>() {
Ok(r) => r,
Err(_) => return None,

View File

@@ -13,7 +13,6 @@ mod test_fn_averageifs;
mod test_fn_choose;
mod test_fn_concatenate;
mod test_fn_count;
mod test_fn_day;
mod test_fn_exact;
mod test_fn_financial;
mod test_fn_formulatext;
@@ -42,7 +41,6 @@ mod test_sheet_markup;
mod test_sheets;
mod test_styles;
mod test_trigonometric;
mod test_true_false;
mod test_workbook;
mod test_worksheet;
pub(crate) mod util;

View File

@@ -37,12 +37,12 @@ fn test_fn_date_arguments() {
assert_eq!(model._get_text("A3"), *"#ERROR!");
assert_eq!(model._get_text("A4"), *"#ERROR!");
assert_eq!(model._get_text("A5"), *"10/10/1974");
assert_eq!(model._get_text("A6"), *"21/01/1975");
assert_eq!(model._get_text("A7"), *"10/02/1976");
assert_eq!(model._get_text("A8"), *"02/03/1975");
assert_eq!(model._get_text("A5"), *"#NUM!");
assert_eq!(model._get_text("A6"), *"#NUM!");
assert_eq!(model._get_text("A7"), *"#NUM!");
assert_eq!(model._get_text("A8"), *"#NUM!");
assert_eq!(model._get_text("A9"), *"01/03/1975");
assert_eq!(model._get_text("A9"), *"#NUM!");
assert_eq!(model._get_text("A10"), *"29/02/1976");
assert_eq!(
model.get_cell_value_by_ref("Sheet1!A10"),
@@ -64,18 +64,15 @@ fn test_date_out_of_range() {
// year (actually years < 1900 don't really make sense)
model._set("C1", "=DATE(-1, 5, 5)");
// excel is not compatible with years past 9999
model._set("C2", "=DATE(10000, 5, 5)");
model.evaluate();
assert_eq!(model._get_text("A1"), *"10/12/2021");
assert_eq!(model._get_text("A2"), *"10/01/2023");
assert_eq!(model._get_text("B1"), *"30/04/2042");
assert_eq!(model._get_text("B2"), *"01/06/2025");
assert_eq!(model._get_text("A1"), *"#NUM!");
assert_eq!(model._get_text("A2"), *"#NUM!");
assert_eq!(model._get_text("B1"), *"#NUM!");
assert_eq!(model._get_text("B2"), *"#NUM!");
assert_eq!(model._get_text("C1"), *"#NUM!");
assert_eq!(model._get_text("C2"), *"#NUM!");
}
#[test]
@@ -132,7 +129,8 @@ fn test_day_small_serial() {
model.evaluate();
assert_eq!(model._get_text("A1"), *"#NUM!");
assert_eq!(model._get_text("A2"), *"#NUM!");
// This agrees with Google Docs and disagrees with Excel
assert_eq!(model._get_text("A2"), *"30");
// Excel thinks is Feb 29, 1900
assert_eq!(model._get_text("A3"), *"28");
@@ -152,7 +150,8 @@ fn test_month_small_serial() {
model.evaluate();
assert_eq!(model._get_text("A1"), *"#NUM!");
assert_eq!(model._get_text("A2"), *"#NUM!");
// This agrees with Google Docs and disagrees with Excel
assert_eq!(model._get_text("A2"), *"12");
// We agree with Excel here (We are both in Feb)
assert_eq!(model._get_text("A3"), *"2");
@@ -172,7 +171,8 @@ fn test_year_small_serial() {
model.evaluate();
assert_eq!(model._get_text("A1"), *"#NUM!");
assert_eq!(model._get_text("A2"), *"#NUM!");
// This agrees with Google Docs and disagrees with Excel
assert_eq!(model._get_text("A2"), *"1899");
assert_eq!(model._get_text("A3"), *"1900");
@@ -204,10 +204,7 @@ fn test_date_early_dates() {
model.get_cell_value_by_ref("Sheet1!A2"),
Ok(CellValue::Number(60.0))
);
// This does not agree with Excel, instead of mistakenly allowing
// for Feb 29, it will auto-wrap to the next day after Feb 28.
assert_eq!(model._get_text("B2"), *"01/03/1900");
assert_eq!(model._get_text("B2"), *"#NUM!");
// This agrees with Excel from he onward
assert_eq!(model._get_text("A3"), *"01/03/1900");

View File

@@ -1,15 +0,0 @@
#![allow(clippy::unwrap_used)]
use crate::test::util::new_empty_model;
#[test]
fn test_fn_date_arguments() {
let mut model = new_empty_model();
model._set("A1", "=DAY(95051806)");
model._set("A2", "=DAY(2958465)");
model.evaluate();
assert_eq!(model._get_text("A1"), *"#NUM!");
assert_eq!(model._get_text("A2"), *"31");
}

View File

@@ -1,25 +0,0 @@
#![allow(clippy::unwrap_used)]
use crate::test::util::new_empty_model;
#[test]
fn true_false_arguments() {
let mut model = new_empty_model();
model._set("A1", "=TRUE( )");
model._set("A2", "=FALSE( )");
model._set("A3", "=TRUE( 4 )");
model._set("A4", "=FALSE( 4 )");
model.evaluate();
assert_eq!(model._get_text("A1"), *"TRUE");
assert_eq!(model._get_text("A2"), *"FALSE");
assert_eq!(model._get_formula("A1"), *"=TRUE()");
assert_eq!(model._get_formula("A2"), *"=FALSE()");
assert_eq!(model._get_text("A3"), *"#ERROR!");
assert_eq!(model._get_text("A4"), *"#ERROR!");
assert_eq!(model._get_formula("A3"), *"=TRUE(4)");
assert_eq!(model._get_formula("A4"), *"=FALSE(4)");
}

View File

@@ -29,7 +29,7 @@ impl Workbook {
}
/// Returns the a list of defined names in the workbook with their scope
pub fn get_defined_names_with_scope(&self) -> Vec<(String, Option<u32>, String)> {
pub(crate) fn get_defined_names_with_scope(&self) -> Vec<(String, Option<u32>, String)> {
let sheet_id_index: Vec<u32> = self.worksheets.iter().map(|s| s.sheet_id).collect();
let defined_names = self

View File

@@ -1,5 +0,0 @@
[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"
rustflags = ["-C", "target-feature=-crt-static"]
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]

View File

@@ -1,197 +0,0 @@
# Created by https://www.toptal.com/developers/gitignore/api/node
# Edit at https://www.toptal.com/developers/gitignore?templates=node
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# End of https://www.toptal.com/developers/gitignore/api/node
# Created by https://www.toptal.com/developers/gitignore/api/macos
# Edit at https://www.toptal.com/developers/gitignore?templates=macos
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
# End of https://www.toptal.com/developers/gitignore/api/macos
# Created by https://www.toptal.com/developers/gitignore/api/windows
# Edit at https://www.toptal.com/developers/gitignore?templates=windows
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/windows
#Added by cargo
/target
Cargo.lock
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
*.node

View File

@@ -1,13 +0,0 @@
target
Cargo.lock
.cargo
.github
npm
.eslintrc
.prettierignore
rustfmt.toml
yarn.lock
*.node
.yarn
__test__
renovate.json

View File

@@ -1 +0,0 @@
nodeLinker: node-modules

View File

@@ -1,18 +0,0 @@
[package]
edition = "2021"
name = "ironcalc_nodejs"
version = "0.3.1"
[lib]
crate-type = ["cdylib"]
[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.2", default-features = false, features = ["napi4", "serde-json"] }
napi-derive = "2.12.2"
ironcalc = { path = "../../xlsx", version = "0.3.0" }
serde = { version = "1.0", features = ["derive"] }
[build-dependencies]
napi-build = "2.0.1"

View File

@@ -1,18 +0,0 @@
# IronCalc nodejs bindingds
Example usage:
```javascript
import { Model } from '@ironcalc/wasm';
const model = new Model("Workbook1", "en", "UTC");
model.setUserInput(0, 1, 1, "=1+1");
const result1 = model.getFormattedCellValue(0, 1, 1);
console.log('Cell value', result1);
let result2 = model.getCellStyle(0, 1, 1);
console.log('Cell style', result2);
```

View File

@@ -1,20 +0,0 @@
import test from 'ava'
import { UserModel, Model } from '../index.js';
test('User Model smoke test', (t) => {
const model = new UserModel("Workbook1", "en", "UTC");
model.setUserInput(0, 1, 1, "=1+1");
t.is(model.getFormattedCellValue(0, 1, 1), '2');
});
test('Raw API smoke test', (t) => {
const model = new Model("Workbook1", "en", "UTC");
model.setUserInput(0, 1, 1, "=1+1");
model.evaluate();
t.is(model.getFormattedCellValue(0, 1, 1), '2');
});

View File

@@ -1,5 +0,0 @@
extern crate napi_build;
fn main() {
napi_build::setup();
}

Binary file not shown.

View File

@@ -1,115 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/* auto-generated by NAPI-RS */
export declare class Model {
constructor(name: string, locale: string, timezone: string)
static fromXlsx(filePath: string, locale: string, tz: string): Model
static fromIcalc(fileName: string): Model
saveToXlsx(file: string): void
saveToIcalc(file: string): void
evaluate(): void
setUserInput(sheet: number, row: number, column: number, value: string): void
clearCellContents(sheet: number, row: number, column: number): void
getCellContent(sheet: number, row: number, column: number): string
getCellType(sheet: number, row: number, column: number): number
getFormattedCellValue(sheet: number, row: number, column: number): string
setCellStyle(sheet: number, row: number, column: number, style: unknown): void
getCellStyle(sheet: number, row: number, column: number): unknown
insertRows(sheet: number, row: number, rowCount: number): void
insertColumns(sheet: number, column: number, columnCount: number): void
deleteRows(sheet: number, row: number, rowCount: number): void
deleteColumns(sheet: number, column: number, columnCount: number): void
getColumnWidth(sheet: number, column: number): number
getRowHeight(sheet: number, row: number): number
setColumnWidth(sheet: number, column: number, width: number): void
setRowHeight(sheet: number, row: number, height: number): void
getFrozenColumnsCount(sheet: number): number
getFrozenRowsCount(sheet: number): number
setFrozenColumnsCount(sheet: number, columnCount: number): void
setFrozenRowsCount(sheet: number, rowCount: number): void
getWorksheetsProperties(): unknown
setSheetColor(sheet: number, color: string): void
addSheet(sheetName: string): void
newSheet(): void
deleteSheet(sheet: number): void
renameSheet(sheet: number, newName: string): void
getDefinedNameList(): unknown
newDefinedName(name: string, scope: number | undefined | null, formula: string): void
updateDefinedName(name: string, scope: number | undefined | null, newName: string, newScope: number | undefined | null, newFormula: string): void
deleteDefinedName(name: string, scope?: number | undefined | null): void
testPanic(): void
}
export declare class UserModel {
constructor(name: string, locale: string, timezone: string)
static fromBytes(bytes: Uint8Array): UserModel
canUndo(): boolean
canRedo(): boolean
pauseEvaluation(): void
resumeEvaluation(): void
flushSendQueue(): Array<number>
applyExternalDiffs(diffs: Uint8Array): void
getCellContent(sheet: number, row: number, column: number): string
newSheet(): void
deleteSheet(sheet: number): void
hideSheet(sheet: number): void
unhideSheet(sheet: number): void
renameSheet(sheet: number, name: string): void
setSheetColor(sheet: number, color: string): void
rangeClearAll(sheet: number, startRow: number, startColumn: number, endRow: number, endColumn: number): void
rangeClearContents(sheet: number, startRow: number, startColumn: number, endRow: number, endColumn: number): void
insertRow(sheet: number, row: number): void
insertColumn(sheet: number, column: number): void
deleteRow(sheet: number, row: number): void
deleteColumn(sheet: number, column: number): void
setRowHeight(sheet: number, row: number, height: number): void
setColumnWidth(sheet: number, column: number, width: number): void
getRowHeight(sheet: number, row: number): number
getColumnWidth(sheet: number, column: number): number
setUserInput(sheet: number, row: number, column: number, input: string): void
getFormattedCellValue(sheet: number, row: number, column: number): string
getFrozenRowsCount(sheet: number): number
getFrozenColumnsCount(sheet: number): number
setFrozenRowsCount(sheet: number, count: number): void
setFrozenColumnsCount(sheet: number, count: number): void
updateRangeStyle(range: unknown, stylePath: string, value: string): void
getCellStyle(sheet: number, row: number, column: number): unknown
onPasteStyles(styles: unknown): void
getCellType(sheet: number, row: number, column: number): number
getWorksheetsProperties(): unknown
getSelectedSheet(): number
getSelectedCell(): Array<number>
getSelectedView(): unknown
setSelectedSheet(sheet: number): void
setSelectedCell(row: number, column: number): void
setSelectedRange(startRow: number, startColumn: number, endRow: number, endColumn: number): void
setTopLeftVisibleCell(topRow: number, topColumn: number): void
setShowGridLines(sheet: number, showGridLines: boolean): void
getShowGridLines(sheet: number): boolean
autoFillRows(sourceArea: unknown, toRow: number): void
autoFillColumns(sourceArea: unknown, toColumn: number): void
onArrowRight(): void
onArrowLeft(): void
onArrowUp(): void
onArrowDown(): void
onPageDown(): void
onPageUp(): void
setWindowWidth(windowWidth: number): void
setWindowHeight(windowHeight: number): void
getScrollX(): number
getScrollY(): number
onExpandSelectedRange(key: string): void
onAreaSelecting(targetRow: number, targetColumn: number): void
setAreaWithBorder(area: unknown, borderArea: unknown): void
toBytes(): Array<number>
getName(): string
setName(name: string): void
copyToClipboard(): unknown
pasteFromClipboard(sourceSheet: number, sourceRange: unknown, clipboard: unknown, isCut: boolean): void
pasteCsvText(area: unknown, csv: string): void
getDefinedNameList(): unknown
newDefinedName(name: string, scope: number | undefined | null, formula: string): void
updateDefinedName(name: string, scope: number | undefined | null, newName: string, newScope: number | undefined | null, newFormula: string): void
deleteDefinedName(name: string, scope?: number | undefined | null): void
}

View File

@@ -1,316 +0,0 @@
/* tslint:disable */
/* eslint-disable */
/* prettier-ignore */
/* auto-generated by NAPI-RS */
const { existsSync, readFileSync } = require('fs')
const { join } = require('path')
const { platform, arch } = process
let nativeBinding = null
let localFileExisted = false
let loadError = null
function isMusl() {
// For Node 10
if (!process.report || typeof process.report.getReport !== 'function') {
try {
const lddPath = require('child_process').execSync('which ldd').toString().trim()
return readFileSync(lddPath, 'utf8').includes('musl')
} catch (e) {
return true
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header
return !glibcVersionRuntime
}
}
switch (platform) {
case 'android':
switch (arch) {
case 'arm64':
localFileExisted = existsSync(join(__dirname, 'nodejs.android-arm64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.android-arm64.node')
} else {
nativeBinding = require('@ironcalc/nodejs-android-arm64')
}
} catch (e) {
loadError = e
}
break
case 'arm':
localFileExisted = existsSync(join(__dirname, 'nodejs.android-arm-eabi.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.android-arm-eabi.node')
} else {
nativeBinding = require('@ironcalc/nodejs-android-arm-eabi')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Android ${arch}`)
}
break
case 'win32':
switch (arch) {
case 'x64':
localFileExisted = existsSync(
join(__dirname, 'nodejs.win32-x64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.win32-x64-msvc.node')
} else {
nativeBinding = require('@ironcalc/nodejs-win32-x64-msvc')
}
} catch (e) {
loadError = e
}
break
case 'ia32':
localFileExisted = existsSync(
join(__dirname, 'nodejs.win32-ia32-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.win32-ia32-msvc.node')
} else {
nativeBinding = require('@ironcalc/nodejs-win32-ia32-msvc')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'nodejs.win32-arm64-msvc.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.win32-arm64-msvc.node')
} else {
nativeBinding = require('@ironcalc/nodejs-win32-arm64-msvc')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`)
}
break
case 'darwin':
localFileExisted = existsSync(join(__dirname, 'nodejs.darwin-universal.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.darwin-universal.node')
} else {
nativeBinding = require('@ironcalc/nodejs-darwin-universal')
}
break
} catch {}
switch (arch) {
case 'x64':
localFileExisted = existsSync(join(__dirname, 'nodejs.darwin-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.darwin-x64.node')
} else {
nativeBinding = require('@ironcalc/nodejs-darwin-x64')
}
} catch (e) {
loadError = e
}
break
case 'arm64':
localFileExisted = existsSync(
join(__dirname, 'nodejs.darwin-arm64.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.darwin-arm64.node')
} else {
nativeBinding = require('@ironcalc/nodejs-darwin-arm64')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`)
}
break
case 'freebsd':
if (arch !== 'x64') {
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
}
localFileExisted = existsSync(join(__dirname, 'nodejs.freebsd-x64.node'))
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.freebsd-x64.node')
} else {
nativeBinding = require('@ironcalc/nodejs-freebsd-x64')
}
} catch (e) {
loadError = e
}
break
case 'linux':
switch (arch) {
case 'x64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-x64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-x64-musl.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-x64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-x64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-x64-gnu.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-x64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-arm64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-arm64-musl.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-arm64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-arm64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-arm64-gnu.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-arm64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 'arm':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-arm-musleabihf.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-arm-musleabihf.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-arm-musleabihf')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-arm-gnueabihf.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-arm-gnueabihf.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-arm-gnueabihf')
}
} catch (e) {
loadError = e
}
}
break
case 'riscv64':
if (isMusl()) {
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-riscv64-musl.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-riscv64-musl.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-riscv64-musl')
}
} catch (e) {
loadError = e
}
} else {
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-riscv64-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-riscv64-gnu.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-riscv64-gnu')
}
} catch (e) {
loadError = e
}
}
break
case 's390x':
localFileExisted = existsSync(
join(__dirname, 'nodejs.linux-s390x-gnu.node')
)
try {
if (localFileExisted) {
nativeBinding = require('./nodejs.linux-s390x-gnu.node')
} else {
nativeBinding = require('@ironcalc/nodejs-linux-s390x-gnu')
}
} catch (e) {
loadError = e
}
break
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`)
}
break
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
}
if (!nativeBinding) {
if (loadError) {
throw loadError
}
throw new Error(`Failed to load native binding`)
}
const { Model, UserModel } = nativeBinding
module.exports.Model = Model
module.exports.UserModel = UserModel

View File

@@ -1,28 +0,0 @@
import { UserModel, Model } from './index.js'
function testUserModel() {
const model = new UserModel("Workbook1", "en", "UTC");
model.setUserInput(0, 1, 1, "=1+1");
let t = model.getFormattedCellValue(0, 1, 1);
console.log('From native', t);
let t2 = model.getCellStyle(0, 1, 1);
console.log('From native', t2);
}
function testModel() {
const model = Model.fromXlsx("example.xlsx", "en", "UTC");
const style = model.getCellStyle(0, 1, 6);
console.log(style);
const quantum = model.getFormattedCellValue(0, 14, 4);
console.log(quantum);
}
testUserModel();
testModel();

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-android-arm-eabi`
This is the **armv7-linux-androideabi** binary for `@ironcalc/nodejs`

View File

@@ -1,18 +0,0 @@
{
"name": "@ironcalc/nodejs-android-arm-eabi",
"version": "0.2.0",
"os": [
"android"
],
"cpu": [
"arm"
],
"main": "nodejs.android-arm-eabi.node",
"files": [
"nodejs.android-arm-eabi.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-android-arm64`
This is the **aarch64-linux-android** binary for `@ironcalc/nodejs`

View File

@@ -1,18 +0,0 @@
{
"name": "@ironcalc/nodejs-android-arm64",
"version": "0.2.0",
"os": [
"android"
],
"cpu": [
"arm64"
],
"main": "nodejs.android-arm64.node",
"files": [
"nodejs.android-arm64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-darwin-arm64`
This is the **aarch64-apple-darwin** binary for `@ironcalc/nodejs`

View File

@@ -1,18 +0,0 @@
{
"name": "@ironcalc/nodejs-darwin-arm64",
"version": "0.2.0",
"os": [
"darwin"
],
"cpu": [
"arm64"
],
"main": "nodejs.darwin-arm64.node",
"files": [
"nodejs.darwin-arm64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-darwin-universal`
This is the **universal-apple-darwin** binary for `@ironcalc/nodejs`

View File

@@ -1,15 +0,0 @@
{
"name": "@ironcalc/nodejs-darwin-universal",
"version": "0.2.0",
"os": [
"darwin"
],
"main": "nodejs.darwin-universal.node",
"files": [
"nodejs.darwin-universal.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-darwin-x64`
This is the **x86_64-apple-darwin** binary for `@ironcalc/nodejs`

View File

@@ -1,18 +0,0 @@
{
"name": "@ironcalc/nodejs-darwin-x64",
"version": "0.2.0",
"os": [
"darwin"
],
"cpu": [
"x64"
],
"main": "nodejs.darwin-x64.node",
"files": [
"nodejs.darwin-x64.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-linux-arm-gnueabihf`
This is the **armv7-unknown-linux-gnueabihf** binary for `@ironcalc/nodejs`

View File

@@ -1,18 +0,0 @@
{
"name": "@ironcalc/nodejs-linux-arm-gnueabihf",
"version": "0.2.0",
"os": [
"linux"
],
"cpu": [
"arm"
],
"main": "nodejs.linux-arm-gnueabihf.node",
"files": [
"nodejs.linux-arm-gnueabihf.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-linux-arm-musleabihf`
This is the **armv7-unknown-linux-musleabihf** binary for `@ironcalc/nodejs`

View File

@@ -1,18 +0,0 @@
{
"name": "@ironcalc/nodejs-linux-arm-musleabihf",
"version": "0.2.0",
"os": [
"linux"
],
"cpu": [
"arm"
],
"main": "nodejs.linux-arm-musleabihf.node",
"files": [
"nodejs.linux-arm-musleabihf.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-linux-arm64-gnu`
This is the **aarch64-unknown-linux-gnu** binary for `@ironcalc/nodejs`

View File

@@ -1,21 +0,0 @@
{
"name": "@ironcalc/nodejs-linux-arm64-gnu",
"version": "0.2.0",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"main": "nodejs.linux-arm64-gnu.node",
"files": [
"nodejs.linux-arm64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-linux-arm64-musl`
This is the **aarch64-unknown-linux-musl** binary for `@ironcalc/nodejs`

View File

@@ -1,21 +0,0 @@
{
"name": "@ironcalc/nodejs-linux-arm64-musl",
"version": "0.2.0",
"os": [
"linux"
],
"cpu": [
"arm64"
],
"main": "nodejs.linux-arm64-musl.node",
"files": [
"nodejs.linux-arm64-musl.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"musl"
]
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-linux-riscv64-gnu`
This is the **riscv64gc-unknown-linux-gnu** binary for `@ironcalc/nodejs`

View File

@@ -1,21 +0,0 @@
{
"name": "@ironcalc/nodejs-linux-riscv64-gnu",
"version": "0.2.0",
"os": [
"linux"
],
"cpu": [
"riscv64"
],
"main": "nodejs.linux-riscv64-gnu.node",
"files": [
"nodejs.linux-riscv64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-linux-x64-gnu`
This is the **x86_64-unknown-linux-gnu** binary for `@ironcalc/nodejs`

View File

@@ -1,21 +0,0 @@
{
"name": "@ironcalc/nodejs-linux-x64-gnu",
"version": "0.2.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "nodejs.linux-x64-gnu.node",
"files": [
"nodejs.linux-x64-gnu.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"glibc"
]
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-linux-x64-musl`
This is the **x86_64-unknown-linux-musl** binary for `@ironcalc/nodejs`

View File

@@ -1,21 +0,0 @@
{
"name": "@ironcalc/nodejs-linux-x64-musl",
"version": "0.2.0",
"os": [
"linux"
],
"cpu": [
"x64"
],
"main": "nodejs.linux-x64-musl.node",
"files": [
"nodejs.linux-x64-musl.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
},
"libc": [
"musl"
]
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-win32-arm64-msvc`
This is the **aarch64-pc-windows-msvc** binary for `@ironcalc/nodejs`

View File

@@ -1,18 +0,0 @@
{
"name": "@ironcalc/nodejs-win32-arm64-msvc",
"version": "0.2.0",
"os": [
"win32"
],
"cpu": [
"arm64"
],
"main": "nodejs.win32-arm64-msvc.node",
"files": [
"nodejs.win32-arm64-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

View File

@@ -1,3 +0,0 @@
# `@ironcalc/nodejs-win32-x64-msvc`
This is the **x86_64-pc-windows-msvc** binary for `@ironcalc/nodejs`

View File

@@ -1,18 +0,0 @@
{
"name": "@ironcalc/nodejs-win32-x64-msvc",
"version": "0.2.0",
"os": [
"win32"
],
"cpu": [
"x64"
],
"main": "nodejs.win32-x64-msvc.node",
"files": [
"nodejs.win32-x64-msvc.node"
],
"license": "MIT",
"engines": {
"node": ">= 10"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,44 +0,0 @@
{
"name": "@ironcalc/nodejs",
"version": "0.3.1",
"main": "index.js",
"types": "index.d.ts",
"napi": {
"name": "nodejs",
"triples": {
"additional": [
"aarch64-apple-darwin",
"aarch64-linux-android",
"aarch64-unknown-linux-gnu",
"aarch64-unknown-linux-musl",
"aarch64-pc-windows-msvc",
"armv7-unknown-linux-gnueabihf",
"armv7-unknown-linux-musleabihf",
"x86_64-unknown-linux-musl",
"armv7-linux-androideabi",
"universal-apple-darwin",
"riscv64gc-unknown-linux-gnu"
]
}
},
"license": "MIT",
"devDependencies": {
"@napi-rs/cli": "^2.18.4",
"ava": "^6.0.1"
},
"ava": {
"timeout": "3m"
},
"engines": {
"node": ">= 10"
},
"scripts": {
"artifacts": "napi artifacts",
"build": "napi build --platform --release",
"build:debug": "napi build --platform",
"prepublishOnly": "napi prepublish -t npm",
"test": "ava",
"universal": "napi universal",
"version": "napi version"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +0,0 @@
tab_spaces = 2
edition = "2021"

View File

@@ -1,8 +0,0 @@
#[macro_use]
extern crate napi_derive;
mod model;
mod user_model;
pub use model::Model;
pub use user_model::UserModel;

View File

@@ -1,343 +0,0 @@
#![deny(clippy::all)]
use napi::{self, bindgen_prelude::*, JsUnknown, Result};
use serde::Serialize;
use ironcalc::{
base::{
types::{CellType, Style},
Model as BaseModel,
},
error::XlsxError,
export::{save_to_icalc, save_to_xlsx},
import::{load_from_icalc, load_from_xlsx},
};
#[derive(Serialize)]
struct DefinedName {
name: String,
scope: Option<u32>,
formula: String,
}
fn to_js_error(error: String) -> Error {
Error::new(Status::Unknown, error)
}
fn to_node_error(error: XlsxError) -> Error {
Error::new(Status::Unknown, error.to_string())
}
#[napi]
pub struct Model {
model: BaseModel,
}
#[napi]
impl Model {
#[napi(constructor)]
pub fn new(name: String, locale: String, timezone: String) -> Result<Self> {
let model = BaseModel::new_empty(&name, &locale, &timezone).map_err(to_js_error)?;
Ok(Self { model })
}
#[napi(factory)]
pub fn from_xlsx(file_path: String, locale: String, tz: String) -> Result<Model> {
let model = load_from_xlsx(&file_path, &locale, &tz)
.map_err(|error| Error::new(Status::Unknown, error.to_string()))?;
Ok(Self { model })
}
#[napi(factory)]
pub fn from_icalc(file_name: String) -> Result<Model> {
let model = load_from_icalc(&file_name)
.map_err(|error| Error::new(Status::Unknown, error.to_string()))?;
Ok(Self { model })
}
#[napi]
pub fn save_to_xlsx(&self, file: String) -> Result<()> {
save_to_xlsx(&self.model, &file).map_err(to_node_error)
}
#[napi]
pub fn save_to_icalc(&self, file: String) -> Result<()> {
save_to_icalc(&self.model, &file).map_err(to_node_error)
}
#[napi]
pub fn evaluate(&mut self) {
self.model.evaluate();
}
#[napi]
pub fn set_user_input(&mut self, sheet: u32, row: i32, column: i32, value: String) -> Result<()> {
self
.model
.set_user_input(sheet, row, column, value)
.map_err(to_js_error)
}
#[napi]
pub fn clear_cell_contents(&mut self, sheet: u32, row: i32, column: i32) -> Result<()> {
self
.model
.cell_clear_contents(sheet, row, column)
.map_err(to_js_error)
}
#[napi]
pub fn get_cell_content(&self, sheet: u32, row: i32, column: i32) -> Result<String> {
self
.model
.get_cell_content(sheet, row, column)
.map_err(to_js_error)
}
#[napi(js_name = "getCellType")]
pub fn get_cell_type(&self, sheet: u32, row: i32, column: i32) -> Result<i32> {
Ok(
match self
.model
.get_cell_type(sheet, row, column)
.map_err(to_js_error)?
{
CellType::Number => 1,
CellType::Text => 2,
CellType::LogicalValue => 4,
CellType::ErrorValue => 16,
CellType::Array => 64,
CellType::CompoundData => 128,
},
)
}
#[napi]
pub fn get_formatted_cell_value(&self, sheet: u32, row: i32, column: i32) -> Result<String> {
self
.model
.get_formatted_cell_value(sheet, row, column)
.map_err(to_js_error)
}
#[napi]
pub fn set_cell_style(
&mut self,
env: Env,
sheet: u32,
row: i32,
column: i32,
style: JsUnknown,
) -> Result<()> {
let style: Style = env
.from_js_value(style)
.map_err(|e| to_js_error(e.to_string()))?;
self
.model
.set_cell_style(sheet, row, column, &style)
.map_err(to_js_error)
}
#[napi(js_name = "getCellStyle")]
pub fn get_cell_style(
&mut self,
env: Env,
sheet: u32,
row: i32,
column: i32,
) -> Result<JsUnknown> {
let style = self
.model
.get_style_for_cell(sheet, row, column)
.map_err(to_js_error)?;
env
.to_js_value(&style)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi]
pub fn insert_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<()> {
self
.model
.insert_rows(sheet, row, row_count)
.map_err(to_js_error)
}
#[napi]
pub fn insert_columns(&mut self, sheet: u32, column: i32, column_count: i32) -> Result<()> {
self
.model
.insert_columns(sheet, column, column_count)
.map_err(to_js_error)
}
#[napi]
pub fn delete_rows(&mut self, sheet: u32, row: i32, row_count: i32) -> Result<()> {
self
.model
.delete_rows(sheet, row, row_count)
.map_err(to_js_error)
}
#[napi]
pub fn delete_columns(&mut self, sheet: u32, column: i32, column_count: i32) -> Result<()> {
self
.model
.delete_columns(sheet, column, column_count)
.map_err(to_js_error)
}
#[napi]
pub fn get_column_width(&self, sheet: u32, column: i32) -> Result<f64> {
self
.model
.get_column_width(sheet, column)
.map_err(to_js_error)
}
#[napi]
pub fn get_row_height(&self, sheet: u32, row: i32) -> Result<f64> {
self.model.get_row_height(sheet, row).map_err(to_js_error)
}
#[napi]
pub fn set_column_width(&mut self, sheet: u32, column: i32, width: f64) -> Result<()> {
self
.model
.set_column_width(sheet, column, width)
.map_err(to_js_error)
}
#[napi]
pub fn set_row_height(&mut self, sheet: u32, row: i32, height: f64) -> Result<()> {
self
.model
.set_row_height(sheet, row, height)
.map_err(to_js_error)
}
#[napi]
pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32> {
self
.model
.get_frozen_columns_count(sheet)
.map_err(to_js_error)
}
#[napi]
pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32> {
self.model.get_frozen_rows_count(sheet).map_err(to_js_error)
}
#[napi]
pub fn set_frozen_columns_count(&mut self, sheet: u32, column_count: i32) -> Result<()> {
self
.model
.set_frozen_columns(sheet, column_count)
.map_err(to_js_error)
}
#[napi]
pub fn set_frozen_rows_count(&mut self, sheet: u32, row_count: i32) -> Result<()> {
self
.model
.set_frozen_rows(sheet, row_count)
.map_err(to_js_error)
}
// I don't _think_ serializing to JsUnknown can't fail
// FIXME: Remove this clippy directive
#[napi(js_name = "getWorksheetsProperties")]
#[allow(clippy::unwrap_used)]
pub fn get_worksheets_properties(&self, env: Env) -> JsUnknown {
env
.to_js_value(&self.model.get_worksheets_properties())
.unwrap()
}
#[napi]
pub fn set_sheet_color(&mut self, sheet: u32, color: String) -> Result<()> {
self
.model
.set_sheet_color(sheet, &color)
.map_err(to_js_error)
}
#[napi]
pub fn add_sheet(&mut self, sheet_name: String) -> Result<()> {
self.model.add_sheet(&sheet_name).map_err(to_js_error)
}
#[napi]
pub fn new_sheet(&mut self) {
self.model.new_sheet();
}
#[napi]
pub fn delete_sheet(&mut self, sheet: u32) -> Result<()> {
self.model.delete_sheet(sheet).map_err(to_js_error)
}
#[napi]
pub fn rename_sheet(&mut self, sheet: u32, new_name: String) -> Result<()> {
self
.model
.rename_sheet_by_index(sheet, &new_name)
.map_err(to_js_error)
}
#[napi(js_name = "getDefinedNameList")]
pub fn get_defined_name_list(&self, env: Env) -> Result<JsUnknown> {
let data: Vec<DefinedName> = self
.model
.workbook
.get_defined_names_with_scope()
.iter()
.map(|s| DefinedName {
name: s.0.to_owned(),
scope: s.1,
formula: s.2.to_owned(),
})
.collect();
env
.to_js_value(&data)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "newDefinedName")]
pub fn new_defined_name(
&mut self,
name: String,
scope: Option<u32>,
formula: String,
) -> Result<()> {
self
.model
.new_defined_name(&name, scope, &formula)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "updateDefinedName")]
pub fn update_defined_name(
&mut self,
name: String,
scope: Option<u32>,
new_name: String,
new_scope: Option<u32>,
new_formula: String,
) -> Result<()> {
self
.model
.update_defined_name(&name, scope, &new_name, new_scope, &new_formula)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "deleteDefinedName")]
pub fn delete_definedname(&mut self, name: String, scope: Option<u32>) -> Result<()> {
self
.model
.delete_defined_name(&name, scope)
.map_err(|e| to_js_error(e.to_string()))
}
}

View File

@@ -1,620 +0,0 @@
#![deny(clippy::all)]
use serde::Serialize;
use napi::{self, bindgen_prelude::*, JsUnknown, Result};
use ironcalc::base::{
expressions::types::Area,
types::{CellType, Style},
BorderArea, ClipboardData, UserModel as BaseModel,
};
#[derive(Serialize)]
struct DefinedName {
name: String,
scope: Option<u32>,
formula: String,
}
fn to_js_error(error: String) -> Error {
Error::new(Status::Unknown, error)
}
#[napi]
pub struct UserModel {
model: BaseModel,
}
#[napi]
impl UserModel {
#[napi(constructor)]
pub fn new(name: String, locale: String, timezone: String) -> Result<Self> {
let model = BaseModel::new_empty(&name, &locale, &timezone).map_err(to_js_error)?;
Ok(Self { model })
}
#[napi(factory)]
pub fn from_bytes(bytes: &[u8]) -> Result<UserModel> {
let model = BaseModel::from_bytes(bytes).map_err(to_js_error)?;
Ok(UserModel { model })
}
pub fn undo(&mut self) -> Result<()> {
self.model.undo().map_err(to_js_error)
}
pub fn redo(&mut self) -> Result<()> {
self.model.redo().map_err(to_js_error)
}
#[napi(js_name = "canUndo")]
pub fn can_undo(&self) -> bool {
self.model.can_undo()
}
#[napi(js_name = "canRedo")]
pub fn can_redo(&self) -> bool {
self.model.can_redo()
}
#[napi(js_name = "pauseEvaluation")]
pub fn pause_evaluation(&mut self) {
self.model.pause_evaluation()
}
#[napi(js_name = "resumeEvaluation")]
pub fn resume_evaluation(&mut self) {
self.model.resume_evaluation()
}
pub fn evaluate(&mut self) {
self.model.evaluate();
}
#[napi(js_name = "flushSendQueue")]
pub fn flush_send_queue(&mut self) -> Vec<u8> {
self.model.flush_send_queue()
}
#[napi(js_name = "applyExternalDiffs")]
pub fn apply_external_diffs(&mut self, diffs: &[u8]) -> Result<()> {
self.model.apply_external_diffs(diffs).map_err(to_js_error)
}
#[napi(js_name = "getCellContent")]
pub fn get_cell_content(&self, sheet: u32, row: i32, column: i32) -> Result<String> {
self
.model
.get_cell_content(sheet, row, column)
.map_err(to_js_error)
}
#[napi(js_name = "newSheet")]
pub fn new_sheet(&mut self) -> Result<()> {
self.model.new_sheet().map_err(to_js_error)
}
#[napi(js_name = "deleteSheet")]
pub fn delete_sheet(&mut self, sheet: u32) -> Result<()> {
self.model.delete_sheet(sheet).map_err(to_js_error)
}
#[napi(js_name = "hideSheet")]
pub fn hide_sheet(&mut self, sheet: u32) -> Result<()> {
self.model.hide_sheet(sheet).map_err(to_js_error)
}
#[napi(js_name = "unhideSheet")]
pub fn unhide_sheet(&mut self, sheet: u32) -> Result<()> {
self.model.unhide_sheet(sheet).map_err(to_js_error)
}
#[napi(js_name = "renameSheet")]
pub fn rename_sheet(&mut self, sheet: u32, name: String) -> Result<()> {
self.model.rename_sheet(sheet, &name).map_err(to_js_error)
}
#[napi(js_name = "setSheetColor")]
pub fn set_sheet_color(&mut self, sheet: u32, color: String) -> Result<()> {
self
.model
.set_sheet_color(sheet, &color)
.map_err(to_js_error)
}
#[napi(js_name = "rangeClearAll")]
pub fn range_clear_all(
&mut self,
sheet: u32,
start_row: i32,
start_column: i32,
end_row: i32,
end_column: i32,
) -> Result<()> {
let range = Area {
sheet,
row: start_row,
column: start_column,
width: end_column - start_column + 1,
height: end_row - start_row + 1,
};
self.model.range_clear_all(&range).map_err(to_js_error)
}
#[napi(js_name = "rangeClearContents")]
pub fn range_clear_contents(
&mut self,
sheet: u32,
start_row: i32,
start_column: i32,
end_row: i32,
end_column: i32,
) -> Result<()> {
let range = Area {
sheet,
row: start_row,
column: start_column,
width: end_column - start_column + 1,
height: end_row - start_row + 1,
};
self.model.range_clear_contents(&range).map_err(to_js_error)
}
#[napi(js_name = "insertRow")]
pub fn insert_row(&mut self, sheet: u32, row: i32) -> Result<()> {
self.model.insert_row(sheet, row).map_err(to_js_error)
}
#[napi(js_name = "insertColumn")]
pub fn insert_column(&mut self, sheet: u32, column: i32) -> Result<()> {
self.model.insert_column(sheet, column).map_err(to_js_error)
}
#[napi(js_name = "deleteRow")]
pub fn delete_row(&mut self, sheet: u32, row: i32) -> Result<()> {
self.model.delete_row(sheet, row).map_err(to_js_error)
}
#[napi(js_name = "deleteColumn")]
pub fn delete_column(&mut self, sheet: u32, column: i32) -> Result<()> {
self.model.delete_column(sheet, column).map_err(to_js_error)
}
#[napi(js_name = "setRowHeight")]
pub fn set_row_height(&mut self, sheet: u32, row: i32, height: f64) -> Result<()> {
self
.model
.set_row_height(sheet, row, height)
.map_err(to_js_error)
}
#[napi(js_name = "setColumnWidth")]
pub fn set_column_width(&mut self, sheet: u32, column: i32, width: f64) -> Result<()> {
self
.model
.set_column_width(sheet, column, width)
.map_err(to_js_error)
}
#[napi(js_name = "getRowHeight")]
pub fn get_row_height(&mut self, sheet: u32, row: i32) -> Result<f64> {
self.model.get_row_height(sheet, row).map_err(to_js_error)
}
#[napi(js_name = "getColumnWidth")]
pub fn get_column_width(&mut self, sheet: u32, column: i32) -> Result<f64> {
self
.model
.get_column_width(sheet, column)
.map_err(to_js_error)
}
#[napi(js_name = "setUserInput")]
pub fn set_user_input(&mut self, sheet: u32, row: i32, column: i32, input: String) -> Result<()> {
self
.model
.set_user_input(sheet, row, column, &input)
.map_err(to_js_error)
}
#[napi(js_name = "getFormattedCellValue")]
pub fn get_formatted_cell_value(&self, sheet: u32, row: i32, column: i32) -> Result<String> {
self
.model
.get_formatted_cell_value(sheet, row, column)
.map_err(to_js_error)
}
#[napi(js_name = "getFrozenRowsCount")]
pub fn get_frozen_rows_count(&self, sheet: u32) -> Result<i32> {
self.model.get_frozen_rows_count(sheet).map_err(to_js_error)
}
#[napi(js_name = "getFrozenColumnsCount")]
pub fn get_frozen_columns_count(&self, sheet: u32) -> Result<i32> {
self
.model
.get_frozen_columns_count(sheet)
.map_err(to_js_error)
}
#[napi(js_name = "setFrozenRowsCount")]
pub fn set_frozen_rows_count(&mut self, sheet: u32, count: i32) -> Result<()> {
self
.model
.set_frozen_rows_count(sheet, count)
.map_err(to_js_error)
}
#[napi(js_name = "setFrozenColumnsCount")]
pub fn set_frozen_columns_count(&mut self, sheet: u32, count: i32) -> Result<()> {
self
.model
.set_frozen_columns_count(sheet, count)
.map_err(to_js_error)
}
#[napi(js_name = "updateRangeStyle")]
pub fn update_range_style(
&mut self,
env: Env,
range: JsUnknown,
style_path: String,
value: String,
) -> Result<()> {
let range: Area = env
.from_js_value(range)
.map_err(|e| to_js_error(e.to_string()))?;
self
.model
.update_range_style(&range, &style_path, &value)
.map_err(to_js_error)
}
#[napi(js_name = "getCellStyle")]
pub fn get_cell_style(
&mut self,
env: Env,
sheet: u32,
row: i32,
column: i32,
) -> Result<JsUnknown> {
let style = self
.model
.get_cell_style(sheet, row, column)
.map_err(to_js_error)?;
env
.to_js_value(&style)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "onPasteStyles")]
pub fn on_paste_styles(&mut self, env: Env, styles: JsUnknown) -> Result<()> {
let styles: &Vec<Vec<Style>> = &env
.from_js_value(styles)
.map_err(|e| to_js_error(e.to_string()))?;
self.model.on_paste_styles(styles).map_err(to_js_error)
}
#[napi(js_name = "getCellType")]
pub fn get_cell_type(&self, sheet: u32, row: i32, column: i32) -> Result<i32> {
Ok(
match self
.model
.get_cell_type(sheet, row, column)
.map_err(to_js_error)?
{
CellType::Number => 1,
CellType::Text => 2,
CellType::LogicalValue => 4,
CellType::ErrorValue => 16,
CellType::Array => 64,
CellType::CompoundData => 128,
},
)
}
// I don't _think_ serializing to JsUnknown can't fail
// FIXME: Remove this clippy directive
#[napi(js_name = "getWorksheetsProperties")]
#[allow(clippy::unwrap_used)]
pub fn get_worksheets_properties(&self, env: Env) -> JsUnknown {
env
.to_js_value(&self.model.get_worksheets_properties())
.unwrap()
}
#[napi(js_name = "getSelectedSheet")]
pub fn get_selected_sheet(&self) -> u32 {
self.model.get_selected_sheet()
}
#[napi(js_name = "getSelectedCell")]
pub fn get_selected_cell(&self) -> Vec<i32> {
let (sheet, row, column) = self.model.get_selected_cell();
vec![sheet as i32, row, column]
}
// I don't _think_ serializing to JsUnknown can't fail
// FIXME: Remove this clippy directive
#[napi(js_name = "getSelectedView")]
#[allow(clippy::unwrap_used)]
pub fn get_selected_view(&self, env: Env) -> JsUnknown {
env.to_js_value(&self.model.get_selected_view()).unwrap()
}
#[napi(js_name = "setSelectedSheet")]
pub fn set_selected_sheet(&mut self, sheet: u32) -> Result<()> {
self.model.set_selected_sheet(sheet).map_err(to_js_error)
}
#[napi(js_name = "setSelectedCell")]
pub fn set_selected_cell(&mut self, row: i32, column: i32) -> Result<()> {
self
.model
.set_selected_cell(row, column)
.map_err(to_js_error)
}
#[napi(js_name = "setSelectedRange")]
pub fn set_selected_range(
&mut self,
start_row: i32,
start_column: i32,
end_row: i32,
end_column: i32,
) -> Result<()> {
self
.model
.set_selected_range(start_row, start_column, end_row, end_column)
.map_err(to_js_error)
}
#[napi(js_name = "setTopLeftVisibleCell")]
pub fn set_top_left_visible_cell(&mut self, top_row: i32, top_column: i32) -> Result<()> {
self
.model
.set_top_left_visible_cell(top_row, top_column)
.map_err(to_js_error)
}
#[napi(js_name = "setShowGridLines")]
pub fn set_show_grid_lines(&mut self, sheet: u32, show_grid_lines: bool) -> Result<()> {
self
.model
.set_show_grid_lines(sheet, show_grid_lines)
.map_err(to_js_error)
}
#[napi(js_name = "getShowGridLines")]
pub fn get_show_grid_lines(&mut self, sheet: u32) -> Result<bool> {
self.model.get_show_grid_lines(sheet).map_err(to_js_error)
}
#[napi(js_name = "autoFillRows")]
pub fn auto_fill_rows(&mut self, env: Env, source_area: JsUnknown, to_row: i32) -> Result<()> {
let area: Area = env
.from_js_value(source_area)
.map_err(|e| to_js_error(e.to_string()))?;
self
.model
.auto_fill_rows(&area, to_row)
.map_err(to_js_error)
}
#[napi(js_name = "autoFillColumns")]
pub fn auto_fill_columns(
&mut self,
env: Env,
source_area: JsUnknown,
to_column: i32,
) -> Result<()> {
let area: Area = env
.from_js_value(source_area)
.map_err(|e| to_js_error(e.to_string()))?;
self
.model
.auto_fill_columns(&area, to_column)
.map_err(to_js_error)
}
#[napi(js_name = "onArrowRight")]
pub fn on_arrow_right(&mut self) -> Result<()> {
self.model.on_arrow_right().map_err(to_js_error)
}
#[napi(js_name = "onArrowLeft")]
pub fn on_arrow_left(&mut self) -> Result<()> {
self.model.on_arrow_left().map_err(to_js_error)
}
#[napi(js_name = "onArrowUp")]
pub fn on_arrow_up(&mut self) -> Result<()> {
self.model.on_arrow_up().map_err(to_js_error)
}
#[napi(js_name = "onArrowDown")]
pub fn on_arrow_down(&mut self) -> Result<()> {
self.model.on_arrow_down().map_err(to_js_error)
}
#[napi(js_name = "onPageDown")]
pub fn on_page_down(&mut self) -> Result<()> {
self.model.on_page_down().map_err(to_js_error)
}
#[napi(js_name = "onPageUp")]
pub fn on_page_up(&mut self) -> Result<()> {
self.model.on_page_up().map_err(to_js_error)
}
#[napi(js_name = "setWindowWidth")]
pub fn set_window_width(&mut self, window_width: f64) {
self.model.set_window_width(window_width);
}
#[napi(js_name = "setWindowHeight")]
pub fn set_window_height(&mut self, window_height: f64) {
self.model.set_window_height(window_height);
}
#[napi(js_name = "getScrollX")]
pub fn get_scroll_x(&self) -> Result<f64> {
self.model.get_scroll_x().map_err(to_js_error)
}
#[napi(js_name = "getScrollY")]
pub fn get_scroll_y(&self) -> Result<f64> {
self.model.get_scroll_y().map_err(to_js_error)
}
#[napi(js_name = "onExpandSelectedRange")]
pub fn on_expand_selected_range(&mut self, key: String) -> Result<()> {
self
.model
.on_expand_selected_range(&key)
.map_err(to_js_error)
}
#[napi(js_name = "onAreaSelecting")]
pub fn on_area_selecting(&mut self, target_row: i32, target_column: i32) -> Result<()> {
self
.model
.on_area_selecting(target_row, target_column)
.map_err(to_js_error)
}
#[napi(js_name = "setAreaWithBorder")]
pub fn set_area_with_border(
&mut self,
env: Env,
area: JsUnknown,
border_area: JsUnknown,
) -> Result<()> {
let range: Area = env
.from_js_value(area)
.map_err(|e| to_js_error(e.to_string()))?;
let border: BorderArea = env
.from_js_value(border_area)
.map_err(|e| to_js_error(e.to_string()))?;
self
.model
.set_area_with_border(&range, &border)
.map_err(|e| to_js_error(e.to_string()))?;
Ok(())
}
#[napi(js_name = "toBytes")]
pub fn to_bytes(&self) -> Vec<u8> {
self.model.to_bytes()
}
#[napi(js_name = "getName")]
pub fn get_name(&self) -> String {
self.model.get_name()
}
#[napi(js_name = "setName")]
pub fn set_name(&mut self, name: String) {
self.model.set_name(&name);
}
#[napi(js_name = "copyToClipboard")]
pub fn copy_to_clipboard(&self, env: Env) -> Result<JsUnknown> {
let data = self
.model
.copy_to_clipboard()
.map_err(|e| to_js_error(e.to_string()))?;
env
.to_js_value(&data)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "pasteFromClipboard")]
pub fn paste_from_clipboard(
&mut self,
env: Env,
source_sheet: u32,
source_range: JsUnknown,
clipboard: JsUnknown,
is_cut: bool,
) -> Result<()> {
let source_range: (i32, i32, i32, i32) = env
.from_js_value(source_range)
.map_err(|e| to_js_error(e.to_string()))?;
let clipboard: ClipboardData = env
.from_js_value(clipboard)
.map_err(|e| to_js_error(e.to_string()))?;
self
.model
.paste_from_clipboard(source_sheet, source_range, &clipboard, is_cut)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "pasteCsvText")]
pub fn paste_csv_string(&mut self, env: Env, area: JsUnknown, csv: String) -> Result<()> {
let range: Area = env
.from_js_value(area)
.map_err(|e| to_js_error(e.to_string()))?;
self
.model
.paste_csv_string(&range, &csv)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "getDefinedNameList")]
pub fn get_defined_name_list(&self, env: Env) -> Result<JsUnknown> {
let data: Vec<DefinedName> = self
.model
.get_defined_name_list()
.iter()
.map(|s| DefinedName {
name: s.0.to_owned(),
scope: s.1,
formula: s.2.to_owned(),
})
.collect();
env
.to_js_value(&data)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "newDefinedName")]
pub fn new_defined_name(
&mut self,
name: String,
scope: Option<u32>,
formula: String,
) -> Result<()> {
self
.model
.new_defined_name(&name, scope, &formula)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "updateDefinedName")]
pub fn update_defined_name(
&mut self,
name: String,
scope: Option<u32>,
new_name: String,
new_scope: Option<u32>,
new_formula: String,
) -> Result<()> {
self
.model
.update_defined_name(&name, scope, &new_name, new_scope, &new_formula)
.map_err(|e| to_js_error(e.to_string()))
}
#[napi(js_name = "deleteDefinedName")]
pub fn delete_definedname(&mut self, name: String, scope: Option<u32>) -> Result<()> {
self
.model
.delete_defined_name(&name, scope)
.map_err(|e| to_js_error(e.to_string()))
}
}

File diff suppressed because it is too large Load Diff

884
bindings/python/Cargo.lock generated Normal file
View File

@@ -0,0 +1,884 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bzip2"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2-sys"
version = "0.1.11+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "chrono-tz"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbc529705a6e0028189c83f0a5dd9fb214105116f7e3c0eeab7ff0369766b0d1"
dependencies = [
"chrono",
"chrono-tz-build",
"phf",
]
[[package]]
name = "chrono-tz-build"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9998fb9f7e9b2111641485bf8beb32f92945f97f92a3d061f744cfef335f751"
dependencies = [
"parse-zoneinfo",
"phf",
"phf_codegen",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "flate2"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "getrandom"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [
"cfg-if",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "iana-time-zone"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "indoc"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306"
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "ironcalc"
version = "0.1.0"
dependencies = [
"chrono",
"ironcalc_base",
"itertools",
"roxmltree",
"serde",
"serde_json",
"thiserror",
"zip",
]
[[package]]
name = "ironcalc_base"
version = "0.1.0"
dependencies = [
"chrono",
"chrono-tz",
"js-sys",
"once_cell",
"rand",
"regex",
"ryu",
"serde",
"serde_json",
"serde_repr",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "js-sys"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "lock_api"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "parking_lot"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
dependencies = [
"instant",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
dependencies = [
"cfg-if",
"instant",
"libc",
"redox_syscall",
"smallvec",
"winapi",
]
[[package]]
name = "parse-zoneinfo"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41"
dependencies = [
"regex",
]
[[package]]
name = "phf"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [
"phf_shared",
]
[[package]]
name = "phf_codegen"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a"
dependencies = [
"phf_generator",
"phf_shared",
]
[[package]]
name = "phf_generator"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [
"phf_shared",
"rand",
]
[[package]]
name = "phf_shared"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [
"siphasher",
]
[[package]]
name = "pkg-config"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "pyo3"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e681a6cfdc4adcc93b4d3cf993749a4552018ee0a9b65fc0ccfad74352c72a38"
dependencies = [
"cfg-if",
"indoc",
"libc",
"memoffset",
"parking_lot",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-build-config"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076c73d0bc438f7a4ef6fdd0c3bb4732149136abd952b110ac93e4edb13a6ba5"
dependencies = [
"once_cell",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e53cee42e77ebe256066ba8aa77eff722b3bb91f3419177cf4cd0f304d3284d9"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfeb4c99597e136528c6dd7d5e3de5434d1ceaf487436a3f03b2d56b6fc9efd1"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 1.0.109",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "947dc12175c254889edc0c02e399476c2f652b4b9ebd123aa655c224de259536"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "pyroncalc"
version = "0.1.0"
dependencies = [
"ironcalc",
"pyo3",
"serde",
"serde_json",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "roxmltree"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf7d7b1ea646d380d0e8153158063a6da7efe30ddbf3184042848e3f8a6f671"
dependencies = [
"xmlparser",
]
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "serde_json"
version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_repr"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "siphasher"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "smallvec"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "target-lexicon"
version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
[[package]]
name = "thiserror"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unindent"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c"
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.39",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "xmlparser"
version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4"
[[package]]
name = "zip"
version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815"
dependencies = [
"byteorder",
"bzip2",
"crc32fast",
"flate2",
"thiserror",
"time",
]

View File

@@ -1,6 +1,6 @@
[package]
name = "pyroncalc"
version = "0.3.0"
version = "0.1.2"
edition = "2021"
@@ -12,8 +12,8 @@ crate-type = ["cdylib"]
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
xlsx = { package= "ironcalc", path = "../../xlsx", version = "0.3.0" }
pyo3 = { version = "0.23", features = ["extension-module"] }
xlsx = { package= "ironcalc", path = "../../xlsx", version = "0.2.0" }
pyo3 = { version = "0.22.3", features = ["extension-module"] }
[features]

View File

@@ -1,6 +1,6 @@
[project]
name = "ironcalc"
version = "0.3.0"
version = "0.1.2"
description = "Create, edit and evaluate Excel spreadsheets"
requires-python = ">=3.10"
keywords = [

View File

@@ -1,10 +1,10 @@
[package]
name = "wasm"
version = "0.3.0"
version = "0.1.3"
authors = ["Nicolas Hatcher <nicolas@theuniverse.today>"]
description = "IronCalc Web bindings"
license = "MIT/Apache-2.0"
repository = "https://github.com/ironcalc/ironcalc"
repository = "https://github.com/ironcalc/web-bindings"
edition = "2021"
[lib]
@@ -14,7 +14,7 @@ crate-type = ["cdylib"]
# Uses `../ironcalc/base` when used locally, and uses
# the inicated version from crates.io when published.
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations
ironcalc_base = { path = "../../base", version = "0.3", features = ["use_regex_lite"] }
ironcalc_base = { path = "../../base", version = "0.2", features = ["use_regex_lite"] }
serde = { version = "1.0", features = ["derive"] }
wasm-bindgen = "0.2.92"
serde-wasm-bindgen = "0.4"

View File

@@ -1,17 +1,8 @@
# In some platforms, python is called python3
PYTHON := $(shell command -v python 2>/dev/null || command -v python3 2>/dev/null)
# If neither is found, fail immediately
ifeq ($(PYTHON),)
$(error No python found. Please install python.)
endif
all:
wasm-pack build --target web --scope ironcalc --release
cp README.pkg.md pkg/README.md
tsc types.ts --target esnext --module esnext
$(PYTHON) fix_types.py
rm -f types.js
python fix_types.py
tests:
wasm-pack build --target nodejs && node tests/test.mjs

View File

@@ -45,10 +45,6 @@ export default defineConfig({
{ text: "About the web application", link: "/web-application/about" },
{ text: "Importing Files", link: "/web-application/importing-files" },
{ text: "Sharing Files", link: "/web-application/sharing-files" },
{
text: "Name Manager",
link: "/web-application/name-manager",
}
],
},
{
@@ -74,10 +70,6 @@ export default defineConfig({
text: "Units",
link: "/features/units",
},
{
text: "Serial Numbers",
link: "/features/serial-numbers",
},
{
text: "Unsupported Features",
link: "/features/unsupported-features",
@@ -588,7 +580,7 @@ export default defineConfig({
},
{
text: "ERF.PRECISE",
link: "/functions/engineering/erf-precise",
link: "/functions/engineering/erf.precise",
},
{
text: "ERFC",
@@ -596,7 +588,7 @@ export default defineConfig({
},
{
text: "ERFC.PRECISE",
link: "/functions/engineering/erfc-precise",
link: "/functions/engineering/erfc.precise",
},
{
text: "GESTEP",

View File

@@ -1,33 +0,0 @@
---
layout: doc
outline: deep
lang: en-US
---
# Serial Numbers
::: warning
**Note:** This draft page is under construction 🚧
:::
**Note**: For convenience, dates presented on this page are formatted in accordance with the ISO 8601 international standard. IronCalc can recognize and display dates in other formats.
IronCalc stores dates and times as positive numbers, referred to as *serial numbers*. Serial numbers can be formatted to display the date and time.
The integer part of a serial number represents the date, as a count of the days since the fixed starting date of 1899-12-30. Hence dates are represented by a unique, sequential integer value, for example:
* 1 corresponds to 1899-12-31.
* 2 corresponds to 1900-01-01.
* 36,526 corresponds to 2000-01-01.
* 45,658 corresponds to 2025-01-01.
* 2,958,465 corresponds to 9999-12-31.
To illustrate the concept, type the value 2 into an empty cell that is initially formatted as a number. When you subsequently change the cell to a date format, it will update to show the date 1900-01-01.
The fractional part of a serial number represents time, as a fraction of the day. For example:
* 0.0 corresponds to 00:00:00 (midnight)
* 0.041666667 corresponds to 01:00:00.
* 0.5 corresponds to 12:00:00 (noon)
* 0.75 corresponds to 18:00:00.
* 0.99 corresponds to 23:45:36.
Since date-times are stored as numbers, they can be used for arithmetic operations in formulas. For example, it is possible to determine the difference between two dates by subtracting one serial number from the other.
**Note**: A #VALUE! error is reported if a date-formatted cell contains a number less than 1, or greater than or equal to 2,958,466.

View File

@@ -14,7 +14,7 @@ You can track the progress in this [GitHub issue](https://github.com/ironcalc/Ir
| DATE | <Badge type="tip" text="Available" /> | |
| DATEDIF | <Badge type="info" text="Not implemented yet" /> | |
| DATEVALUE | <Badge type="info" text="Not implemented yet" /> | |
| DAY | <Badge type="tip" text="Available" /> | [DAY](date_and_time/day) |
| DAY | <Badge type="tip" text="Available" /> | |
| DAYS | <Badge type="info" text="Not implemented yet" /> | |
| DAYS360 | <Badge type="info" text="Not implemented yet" /> | |
| EDATE | <Badge type="tip" text="Available" /> | |
@@ -22,7 +22,7 @@ You can track the progress in this [GitHub issue](https://github.com/ironcalc/Ir
| HOUR | <Badge type="info" text="Not implemented yet" /> | |
| ISOWEEKNUM | <Badge type="info" text="Not implemented yet" /> | |
| MINUTE | <Badge type="info" text="Not implemented yet" /> | |
| MONTH | <Badge type="tip" text="Available" /> | [MONTH](date_and_time/month) |
| MONTH | <Badge type="tip" text="Available" /> | |
| NETWORKDAYS | <Badge type="info" text="Not implemented yet" /> | |
| NETWORKDAYS.INTL | <Badge type="info" text="Not implemented yet" /> | |
| NOW | <Badge type="tip" text="Available" /> | |
@@ -34,5 +34,5 @@ You can track the progress in this [GitHub issue](https://github.com/ironcalc/Ir
| WEEKNUM | <Badge type="info" text="Not implemented yet" /> | |
| WORKDAY | <Badge type="info" text="Not implemented yet" /> | |
| WORKDAY.INTL | <Badge type="info" text="Not implemented yet" /> | |
| YEAR | <Badge type="tip" text="Available" /> | [YEAR](date_and_time/year) |
| YEAR | <Badge type="tip" text="Available" /> | |
| YEARFRAC | <Badge type="info" text="Not implemented yet" /> | |

View File

@@ -3,35 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# DAY function
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
DAY is a function of the Date and Time category that extracts the day of the month from a valid date [serial number](/features/serial-numbers.md), returning a number in the range [1, 31].
## Usage
### Syntax
**DAY(<span title="Number" style="color:#1E88E5">date</span>) => <span title="Number" style="color:#1E88E5">day</span>**
### Argument descriptions
* *date* ([number](/features/value-types#numbers), required). The date for which the day of the month is to be calculated, expressed as a [serial number](/features/serial-numbers.md) in the range [1, 2958466). The value 1 corresponds to the date 1899-12-31, while 2958465 corresponds to 9999-12-31.
### Additional guidance
If the supplied _date_ argument has a fractional part, DAY uses its [floor value](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions).
### Returned value
DAY returns an integer [number](/features/value-types#numbers) in the range [1, 31], that is the day of the month according to the [Gregorian calendar](https://en.wikipedia.org/wiki/Gregorian_calendar).
### Error conditions
* In common with many other IronCalc functions, DAY propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then DAY returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of the *date* argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then DAY returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, DAY may return the [`#DIV/0!`](/features/error-types.md#div-0) error.
* If date is less than 1, or greater than 2,958,465, then DAY returns the [`#NUM!`](/features/error-types.md#num) error.
* At present, DAY does not accept a string representation of a date literal as an argument. For example, the formula `=DAY("2024-12-31")` returns the [`#VALUE!`](/features/error-types.md#value) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
IronCalc utilizes Rust's [chrono](https://docs.rs/chrono/latest/chrono/) crate to implement the DAY function.
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=day).
## Links
* See also IronCalc's [MONTH](/functions/date_and_time/month.md) and [YEAR](/functions/date_and_time/year.md) functions.
* Visit Microsoft Excel's [DAY function](https://support.microsoft.com/en-gb/office/day-function-8a7d1cbb-6c7d-4ba1-8aea-25c134d03101) page.
* Both [Google Sheets](https://support.google.com/docs/answer/3093040) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/DAY) provide versions of the DAY function.
# DAY
::: warning
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -3,35 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# MONTH function
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
MONTH is a function of the Date and Time category that extracts the month from a valid date [serial number](/features/serial-numbers.md), returning a number in the range [1, 12].
## Usage
### Syntax
**MONTH(<span title="Number" style="color:#1E88E5">date</span>) => <span title="Number" style="color:#1E88E5">month</span>**
### Argument descriptions
* *date* ([number](/features/value-types#numbers), required). The date for which the month is to be calculated, expressed as a [serial number](/features/serial-numbers.md) in the range [1, 2958466). The value 1 corresponds to the date 1899-12-31, while 2958465 corresponds to 9999-12-31.
### Additional guidance
If the supplied _date_ argument has a fractional part, MONTH uses its [floor value](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions).
### Returned value
MONTH returns an integer [number](/features/value-types#numbers) in the range [1, 12], that is the month according to the [Gregorian calendar](https://en.wikipedia.org/wiki/Gregorian_calendar). The value 1 corresponds to January, 2 corresponds to February and so on.
### Error conditions
* In common with many other IronCalc functions, MONTH propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then MONTH returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of the *date* argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then MONTH returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, MONTH may return the [`#DIV/0!`](/features/error-types.md#div-0) error.
* If date is less than 1, or greater than or equal to 2,958,466, then MONTH returns the [`#NUM!`](/features/error-types.md#num) error.
* At present, MONTH does not accept a string representation of a date literal as an argument. For example, the formula `=MONTH("2024-12-31")` returns the [`#VALUE!`](/features/error-types.md#value) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
IronCalc utilizes Rust's [chrono](https://docs.rs/chrono/latest/chrono/) crate to implement the MONTH function.
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=month).
## Links
* See also IronCalc's [DAY](/functions/date_and_time/day.md) and [YEAR](/functions/date_and_time/year.md) functions.
* Visit Microsoft Excel's [MONTH function](https://support.microsoft.com/en-gb/office/month-function-579a2881-199b-48b2-ab90-ddba0eba86e8) page.
* Both [Google Sheets](https://support.google.com/docs/answer/3093052) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/MONTH) provide versions of the MONTH function.
# MONTH
::: warning
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -3,35 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# YEAR function
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
YEAR is a function of the Date and Time category that extracts the year from a valid date [serial number](/features/serial-numbers.md), returning a number in the range [1899, 9999].
## Usage
### Syntax
**YEAR(<span title="Number" style="color:#1E88E5">date</span>) => <span title="Number" style="color:#1E88E5">year</span>**
### Argument descriptions
* *date* ([number](/features/value-types#numbers), required). The date for which the year is to be calculated, expressed as a [serial number](/features/serial-numbers.md) in the range [1, 2958466). The value 1 corresponds to the date 1899-12-31, while 2958465 corresponds to 9999-12-31.
### Additional guidance
If the supplied _date_ argument has a fractional part, YEAR uses its [floor value](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions).
### Returned value
YEAR returns an integer [number](/features/value-types#numbers) in the range [1899, 9999], that is the year according to the [Gregorian calendar](https://en.wikipedia.org/wiki/Gregorian_calendar).
### Error conditions
* In common with many other IronCalc functions, YEAR propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then YEAR returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of the *date* argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then YEAR returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, YEAR may return the [`#DIV/0!`](/features/error-types.md#div-0) error.
* If date is less than 1, or greater than or equal to 2,958,466, then YEAR returns the [`#NUM!`](/features/error-types.md#num) error.
* At present, YEAR does not accept a string representation of a date literal as an argument. For example, the formula `=YEAR("2024-12-31")` returns the [`#VALUE!`](/features/error-types.md#value) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
IronCalc utilizes Rust's [chrono](https://docs.rs/chrono/latest/chrono/) crate to implement the YEAR function.
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=year).
## Links
* See also IronCalc's [DAY](/functions/date_and_time/day.md) and [MONTH](/functions/date_and_time/month.md) functions.
* Visit Microsoft Excel's [YEAR function](https://support.microsoft.com/en-gb/office/year-function-c64f017a-1354-490d-981f-578e8ec8d3b9) page.
* Both [Google Sheets](https://support.google.com/docs/answer/3093061) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/YEAR) provide versions of the YEAR function.
# YEAR
::: warning
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -27,10 +27,10 @@ All Engineering functions are already supported in IronCalc.
| DEC2BIN | <Badge type="tip" text="Available" /> | |
| DEC2HEX | <Badge type="tip" text="Available" /> | |
| DEC2OCT | <Badge type="tip" text="Available" /> | |
| ERF | <Badge type="tip" text="Available" /> | [ERF](engineering/erf) |
| ERF.PRECISE | <Badge type="tip" text="Available" /> | [ERF.PRECISE](engineering/erf-precise) |
| ERFC | <Badge type="tip" text="Available" /> | [ERFC](engineering/erfc) |
| ERFC.PRECISE | <Badge type="tip" text="Available" /> | [ERFC.PRECISE](engineering/erfc-precise) |
| ERF | <Badge type="tip" text="Available" /> | |
| ERF.PRECISE | <Badge type="tip" text="Available" /> | |
| ERFC | <Badge type="tip" text="Available" /> | |
| ERFC.PRECISE | <Badge type="tip" text="Available" /> | |
| GESTEP | <Badge type="tip" text="Available" /> | |
| HEX2BIN | <Badge type="tip" text="Available" /> | |
| HEX2DEC | <Badge type="tip" text="Available" /> | |

View File

@@ -1,52 +0,0 @@
---
layout: doc
outline: deep
lang: en-US
---
# ERF.PRECISE function
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
ERF.PRECISE (<u>ER</u>ror <u>F</u>unction) is a function of the Engineering category that calculates a value for the _error function_. Also known as the _Gauss error function_, the error function represents the probability of a random variable falling within a certain range, given that it follows a specified normal distribution.
ERF.PRECISE is provided for compatibility with other spreadsheets. For all real values of $x$, $\text{ERF.PRECISE}(x)=\text{ERF}(x)$.
## Usage
### Syntax
**ERF.PRECISE(<span title="Number" style="color:#1E88E5">X</span>) => <span title="Number" style="color:#1E88E5">erf.precise</span>**
### Argument descriptions
* *X* ([number](/features/value-types#numbers), required). Integration limit. ERF.PRECISE integrates over the range [0, _X_].
### Additional guidance
None.
### Returned value
ERF.PRECISE returns a [number](/features/value-types#numbers) that is the error function probability for the specified argument. The returned value has a magnitude in the range [0, 1] but may be either positive (integration limit > 0) or negative (integration limit < 0).
### Error conditions
* In common with many other IronCalc functions, ERF.PRECISE propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then ERF.PRECISE returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of the argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then ERF.PRECISE returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, ERF.PRECISE may return the [`#DIV/0!`](/features/error-types.md#div-0) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
* The error function arises in many scientific, engineering, and mathematical fields and is commonly defined by the following equation (applicable for any real number $x$):
$$
\text{erf}(x) = \frac{2}{\sqrt{\pi} }\: \int_{0}^{x} e^{-t^2}\:dt
$$
* The figure below illustrates the output of the ERF.PRECISE function for values of $x$ in the range -3 to +3.
<center><img src="/functions/images/error-function-curve.png" width="350" alt="Graph showing erf(x) for x between -3 and +3."></center>
* This figure illustrates some of the key characteristics of the error function:
* $\text{erf}(0) = 0$
* $\text{erf}(x) = -\text{erf}(x)$
* As $x \rightarrow \infty$, $\text{erf}(x) \rightarrow 1$
* As $x \rightarrow -\infty$, $\text{erf}(x) \rightarrow -1$
* The error function is a [transcendental](https://en.wikipedia.org/wiki/Transcendental_function), non-algebraic mathematical function. IronCalc implements the ERF.PRECISE function by numerical approximation using a power series.
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=erf-precise).
## Links
* See also IronCalc's [ERF](/functions/engineering/erf.md), [ERFC](/functions/engineering/erfc.md) and [ERFC.PRECISE](/functions/engineering/erfc-precise.md) functions.
* Visit Microsoft Excel's [ERF.PRECISE function](https://support.microsoft.com/en-gb/office/erf-precise-function-9a349593-705c-4278-9a98-e4122831a8e0) page.
* Both [Google Sheets](https://support.google.com/docs/answer/9386210) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/ERF.PRECISE) provide versions of the ERF.PROCESS function.

View File

@@ -3,49 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# ERF function
# ERF
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
ERF (<u>ER</u>ror <u>F</u>unction) is a function of the Engineering category that calculates a value for the _error function_. Also known as the _Gauss error function_, the error function represents the probability of a random variable falling within a certain range, given that it follows a specified normal distribution.
## Usage
### Syntax
**ERF(<span title="Number" style="color:#1E88E5">X</span>, <span title="Number" style="color:#1E88E5">Y</span>) => <span title="Number" style="color:#1E88E5">erf</span>**
### Argument descriptions
* *X* ([number](/features/value-types#numbers), required). Integration limit. If no value is supplied for the _Y_ argument, ERF integrates over the range [0, _X_].
* *Y* ([number](/features/value-types#numbers), [optional](/features/optional-arguments)). Upper integration limit. When a value is supplied for this argument, ERF integrates over the range [_X_, _Y_].
### Additional guidance
None.
### Returned value
ERF returns a [number](/features/value-types#numbers) that is the error function probability for the specified arguments. The returned value has a magnitude in the range [0, 1] but may be either positive (upper integration limit > lower integration limit) or negative (upper integration limit < lower integration limit).
### Error conditions
* In common with many other IronCalc functions, ERF propagates errors that are found in its arguments.
* If no argument, or more than two arguments, are supplied, then ERF returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of any argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then ERF returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, ERF may return the [`#DIV/0!`](/features/error-types.md#div-0) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
* The error function arises in many scientific, engineering, and mathematical fields and is commonly defined by the following equation (applicable for any real number $x$):
$$
\text{erf}(x) = \frac{2}{\sqrt{\pi} }\: \int_{0}^{x} e^{-t^2}\:dt
$$
* The figure below illustrates the output of the ERF function for values of $x$ in the range -3 to +3.
<center><img src="/functions/images/error-function-curve.png" width="350" alt="Graph showing erf(x) for x between -3 and +3."></center>
* This figure illustrates some of the key characteristics of the error function:
* $\text{erf}(0) = 0$
* $\text{erf}(x) = -\text{erf}(x)$
* As $x \rightarrow \infty$, $\text{erf}(x) \rightarrow 1$
* As $x \rightarrow -\infty$, $\text{erf}(x) \rightarrow -1$
* The error function is a [transcendental](https://en.wikipedia.org/wiki/Transcendental_function), non-algebraic mathematical function. IronCalc implements the ERF function by numerical approximation using a power series.
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=erf).
## Links
* See also IronCalc's [ERFC](/functions/engineering/erfc.md), [ERF.PRECISE](/functions/engineering/erf-precise.md) and [ERFC.PRECISE](/functions/engineering/erfc-precise.md) functions.
* Visit Microsoft Excel's [ERF function](https://support.microsoft.com/en-gb/office/erf-function-c53c7e7b-5482-4b6c-883e-56df3c9af349) page.
* Both [Google Sheets](https://support.google.com/docs/answer/9116267) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/ERF) provide versions of the ERF function.
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -0,0 +1,11 @@
---
layout: doc
outline: deep
lang: en-US
---
# ERF.PRECISE
::: warning
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -1,52 +0,0 @@
---
layout: doc
outline: deep
lang: en-US
---
# ERFC.PRECISE function
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
ERFC.PRECISE (<u>ER</u>ror <u>F</u>unction <u>C</u>omplementary) is a function of the Engineering category that calculates a value for the _complementary error function_, defined by $\text{erfc}(x) = 1 - \text{erf}(x)$. Also known as the _complementary Gauss error function_, the complementary error function represents the probability of a random variable falling outside a certain range, given that it follows a specified normal distribution.
ERFC.PRECISE is provided for compatibility with other spreadsheets. For all real values of $x$, $\text{ERFC.PRECISE}(x)=\text{ERFC}(x)$.
## Usage
### Syntax
**ERFC.PRECISE(<span title="Number" style="color:#1E88E5">X</span>) => <span title="Number" style="color:#1E88E5">erfc.precise</span>**
### Argument descriptions
* *X* ([number](/features/value-types#numbers), required). The lower integration limit to be used to calculate the complementary error function. ERFC.PRECISE integrates over the range [X, $\infty$).
### Additional guidance
None.
### Returned value
ERFC.PRECISE returns a [number](/features/value-types#numbers) that is the complementary error function probability for the specified argument. The returned value lies in range [0, 2].
### Error conditions
* In common with many other IronCalc functions, ERFC.PRECISE propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then ERFC.PRECISE returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of any argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then ERFC.PRECISE returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, ERFC.PRECISE may return the [`#DIV/0!`](/features/error-types.md#div-0) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
* The complementary error function arises in many scientific, engineering, and mathematical fields and is commonly defined by the following equation (applicable for any real number $x$):
$$
\text{erfc}(x) = \frac{2}{\sqrt{\pi} }\: \int_{x}^{\infty} e^{-t^2}\:dt
$$
* The figure below illustrates the output of the ERFC.PRECISE function for values of $x$ in the range -3 to +3.
<center><img src="/functions/images/complementary-error-function-curve.png" width="350" alt="Graph showing erfc(x) for x between -3 and +3."></center>
* This figure illustrates some of the key characteristics of the complementary error function:
* $\text{erfc}(0) = 1$
* $\text{erfc}(-x) = 2-\text{erfc}(x)$
* As $x \rightarrow \infty$, $\text{erfc}(x) \rightarrow 0$
* As $x \rightarrow -\infty$, $\text{erfc}(x) \rightarrow 2$
* The complementary error function is a [transcendental](https://en.wikipedia.org/wiki/Transcendental_function), non-algebraic mathematical function. IronCalc implements the ERFC.PRECISE function by numerical approximation using a power series.
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=erfc-precise).
## Links
* See also IronCalc's [ERF](/functions/engineering/erf.md), [ERFC](/functions/engineering/erfc.md) and [ERF.PRECISE](/functions/engineering/erf-precise.md) functions.
* Visit Microsoft Excel's [ERFC.PRECISE function](https://support.microsoft.com/en-gb/office/erfc-precise-function-e90e6bab-f45e-45df-b2ac-cd2eb4d4a273) page.
* Both [Google Sheets](https://support.google.com/docs/answer/9386303) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/ERFC.PRECISE) provide versions of the ERFC.PRECISE function.

View File

@@ -3,48 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# ERFC function
# ERFC
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
ERFC (<u>ER</u>ror <u>F</u>unction <u>C</u>omplementary) is a function of the Engineering category that calculates a value for the _complementary error function_, defined by $\text{erfc}(x) = 1 - \text{erf}(x)$. Also known as the _complementary Gauss error function_, the complementary error function represents the probability of a random variable falling outside a certain range, given that it follows a specified normal distribution.
## Usage
### Syntax
**ERFC(<span title="Number" style="color:#1E88E5">X</span>) => <span title="Number" style="color:#1E88E5">erfc</span>**
### Argument descriptions
* *X* ([number](/features/value-types#numbers), required). The lower integration limit to be used to calculate the complementary error function. ERFC integrates over the range [X, $\infty$).
### Additional guidance
None.
### Returned value
ERFC returns a [number](/features/value-types#numbers) that is the complementary error function probability for the specified argument. The returned value lies in range [0, 2].
### Error conditions
* In common with many other IronCalc functions, ERFC propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then ERFC returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of any argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then ERFC returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, ERFC may return the [`#DIV/0!`](/features/error-types.md#div-0) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
* The complementary error function arises in many scientific, engineering, and mathematical fields and is commonly defined by the following equation (applicable for any real number $x$):
$$
\text{erfc}(x) = \frac{2}{\sqrt{\pi} }\: \int_{x}^{\infty} e^{-t^2}\:dt
$$
* The figure below illustrates the output of the ERFC function for values of $x$ in the range -3 to +3.
<center><img src="/functions/images/complementary-error-function-curve.png" width="350" alt="Graph showing erfc(x) for x between -3 and +3."></center>
* This figure illustrates some of the key characteristics of the complementary error function:
* $\text{erfc}(0) = 1$
* $\text{erfc}(-x) = 2-\text{erfc}(x)$
* As $x \rightarrow \infty$, $\text{erfc}(x) \rightarrow 0$
* As $x \rightarrow -\infty$, $\text{erfc}(x) \rightarrow 2$
* The complementary error function is a [transcendental](https://en.wikipedia.org/wiki/Transcendental_function), non-algebraic mathematical function. IronCalc implements the ERFC function by numerical approximation using a power series.
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=erfc).
## Links
* See also IronCalc's [ERF](/functions/engineering/erf.md), [ERF.PRECISE](/functions/engineering/erf-precise.md) and [ERFC.PRECISE](/functions/engineering/erfc-precise.md) functions.
* Visit Microsoft Excel's [ERFC function](https://support.microsoft.com/en-gb/office/erfc-function-736e0318-70ba-4e8b-8d08-461fe68b71b3) page.
* Both [Google Sheets](https://support.google.com/docs/answer/3093407) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/ERFC) provide versions of the ERFC function.
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -0,0 +1,11 @@
---
layout: doc
outline: deep
lang: en-US
---
# ERFC.PRECISE
::: warning
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -51,7 +51,7 @@ You can track the progress in this [GitHub issue](https://github.com/ironcalc/Ir
| PRICE | <Badge type="info" text="Not implemented yet" /> | |
| PRICEDISC | <Badge type="info" text="Not implemented yet" /> | |
| PRICEMAT | <Badge type="info" text="Not implemented yet" /> | |
| PV | <Badge type="tip" text="Available" /> | [PV](financial/pv) |
| PV | <Badge type="tip" text="Available" /> | |
| RATE | <Badge type="tip" text="Available" /> | |
| RECEIVED | <Badge type="info" text="Not implemented yet" /> | |
| RRI | <Badge type="tip" text="Available" /> | - |

View File

@@ -21,18 +21,18 @@ If your interest rate varies between periods, use the [FVSCHEDULE](/functions/fi
* *nper* ([number](/features/value-types#numbers), required). "nper" stands for <u>n</u>umber of <u>per</u>iods, in this case the number of compounding periods to be taken into account. While this will often be an integer, non-integer values are accepted and processed.
* *pmt* ([number](/features/value-types#numbers), required). "pmt" stands for <u>p</u>ay<u>m</u>en<u>t</u>, in this case the fixed amount paid or deposited each compounding period.
* *pv* ([number](/features/value-types#numbers), [optional](/features/optional-arguments.md)). "pv" is the <u>p</u>resent <u>v</u>alue or starting amount of the asset (default 0).
* *type* ([Boolean](/features/value-types#booleans), [optional](/features/optional-arguments.md)). A logical value indicating whether the payment due dates are at the end (FALSE or 0) of the compounding periods or at the beginning (TRUE or any non-zero value). The default is FALSE when omitted.
* *type* ([boolean](/features/value-types/#booleans), [optional](/features/optional-arguments.md)). A logical value indicating whether the payment due dates are at the end (FALSE or 0) of the compounding periods or at the beginning (TRUE or any non-zero value). The default is FALSE when omitted.
### Additional guidance
* Make sure that the *rate* argument specifies the interest rate or yield applicable to the compounding period, based on the value chosen for *nper*.
* The *pmt* and *pv* arguments should be expressed in the same currency unit.
* To ensure a worthwhile result, one of the *pmt* and *pv* arguments should be non-zero.
* The setting of the *type* argument only affects the calculation for non-zero values of the *pmt* argument.
### Returned value
FV returns a [number](/features/value-types#numbers) representing the future value expressed in the same [currency unit](/features/units) that was used for the *pmt* and *pv* arguments.
FV returns a [number](/features/value-types/#numbers) representing the future value expressed in the same [currency unit](/features/units) that was used for the *pmt* and *pv* arguments.
### Error conditions
* In common with many other IronCalc functions, FV propagates errors that are found in any of its arguments.
* If too few or too many arguments are supplied, FV returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of any of the *rate*, *nper*, *pmt* or *pv* arguments is not (or cannot be converted to) a [number](/features/value-types#numbers), then FV returns the [`#VALUE!`](/features/error-types.md#value) error.
* If the value of any of the *rate*, *nper*, *pmt* or *pv* arguments is not (or cannot be converted to) a [number](/features/value-types#value), then FV returns the [`#VALUE!`](/features/error-types.md#value) error.
* If the value of the *type* argument is not (or cannot be converted to) a [Boolean](/features/value-types#booleans), then FV again returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some combinations of valid argument values, FV may return a [`#NUM!`](/features/error-types.md#num) error or a [`#DIV/0!`](/features/error-types.md#div-0) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->

View File

@@ -3,57 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# PV function
# PV
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
PV (<u>P</u>resent <u>V</u>alue) is a function of the Financial category that can be used to calculate the present value of a series of future cash flows.
PV can be used to calculate present value over a specified number of compounding periods. A fixed interest rate or yield is assumed over all periods, and a fixed payment or deposit can be applied at the start or end of every period.
## Usage
### Syntax
**PV(<span title="Number" style="color:#1E88E5">rate</span>, <span title="Number" style="color:#1E88E5">nper</span>, <span title="Number" style="color:#1E88E5">pmt</span>, <span title="Number" style="color:#1E88E5">fv</span>=0, <span title="Boolean" style="color:#43A047">type</span>=FALSE) => <span title="Number" style="color:#1E88E5">pv</span>**
### Argument descriptions
* *rate* ([number](/features/value-types#numbers), required). The fixed percentage interest rate or yield per period.
* *nper* ([number](/features/value-types#numbers), required). "nper" stands for <u>n</u>umber of <u>per</u>iods, in this case the number of compounding periods to be taken into account. While this will often be an integer, non-integer values are accepted and processed.
* *pmt* ([number](/features/value-types#numbers), required). "pmt" stands for <u>p</u>ay<u>m</u>en<u>t</u>, in this case the fixed amount paid or deposited each compounding period.
* *fv* ([number](/features/value-types#numbers), [optional](/features/optional-arguments.md)). "fv" is the <u>f</u>uture <u>v</u>alue at the end of the final compounding period (default 0).
* *type* ([Boolean](/features/value-types#booleans), [optional](/features/optional-arguments.md)). A logical value indicating whether the payment due dates are at the end (FALSE or 0) of the compounding periods or at the beginning (TRUE or any non-zero value). The default is FALSE when omitted.
### Additional guidance
* Make sure that the *rate* argument specifies the interest rate or yield applicable to the compounding period, based on the value chosen for *nper*.
* The *pmt* and *fv* arguments should be expressed in the same currency unit.
* To ensure a worthwhile result, one of the *pmt* and *fv* arguments should be non-zero.
* The setting of the *type* argument only affects the calculation for non-zero values of the *pmt* argument.
### Returned value
PV returns a [number](/features/value-types#numbers) representing the present value expressed in the same [currency unit](/features/units) that was used for the *pmt* and *fv* arguments.
### Error conditions
* In common with many other IronCalc functions, PV propagates errors that are found in any of its arguments.
* If too few or too many arguments are supplied, PV returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of any of the *rate*, *nper*, *pmt* or *fv* arguments is not (or cannot be converted to) a [number](/features/value-types#numbers), then PV returns the [`#VALUE!`](/features/error-types.md#value) error.
* If the value of the *type* argument is not (or cannot be converted to) a [Boolean](/features/value-types#booleans), then PV again returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some combinations of valid argument values, PV may return a [`#NUM!`](/features/error-types.md#num) error or a [`#DIV/0!`](/features/error-types.md#div-0) error.
In paticular, PV always returns a [`#DIV/0!`](/features/error-types.md#div-0) error if the value of the *rate* argument is set to -1.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
* If $\text{type} \neq 0$, $\text{pv}$ is given by the equation:
$$ \text{pv} = - \Biggl(\dfrac{(\text{fv} \times \text{rate}) + \bigl(\text{pmt} \times (1+\text{rate})\times \bigl({(1+\text{rate})^{\text{nper}}-1\bigr)\bigr)}}{\text{rate} \times (1+\text{rate})^{\text{nper}}}\Biggl)
$$
* If $\text{type} = 0$, $\text{pv}$ is given by the equation:
$$ \text{pv} = - \Biggl(\dfrac{(\text{fv} \times \text{rate}) + \bigl(\text{pmt}\times \bigl({(1+\text{rate})^{\text{nper}}-1\bigr)\bigr)}}{\text{rate} \times (1+\text{rate})^\text{{nper}}}\Biggl)
$$
* For any $\text{type}$, in the special case of $\text{rate} = 0$, $\text{pv}$ is given by the equation:
$$
\text{pv} = -\text{fv} - (\text{pmt} \times \text{nper})
$$
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=pv).
## Links
* For more information about the concept of "present value" in finance, visit Wikipedia's [Present value](https://en.wikipedia.org/wiki/present_value) page.
* See also IronCalc's [FV](/functions/financial/fv), [NPER](/functions/financial/nper), [PMT](/functions/financial/pmt) and [RATE](/functions/financial/rate) functions.
* Visit Microsoft Excel's [PV function](https://support.microsoft.com/en-gb/office/pv-function-23879d31-0e02-4321-be01-da16e8168cbd) page.
* Both [Google Sheets](https://support.google.com/docs/answer/3093243) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/PV) provide versions of the PV function.
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

View File

@@ -29,7 +29,7 @@ You can track the progress in this [GitHub issue](https://github.com/ironcalc/Ir
| CEILING.PRECISE | <Badge type="info" text="Not implemented yet" /> | |
| COMBIN | <Badge type="info" text="Not implemented yet" /> | |
| COMBINA | <Badge type="info" text="Not implemented yet" /> | |
| COS | <Badge type="tip" text="Available" /> | [COS](math_and_trigonometry/cos) |
| COS | <Badge type="tip" text="Available" /> | |
| COSH | <Badge type="tip" text="Available" /> | |
| COT | <Badge type="info" text="Not implemented yet" /> | |
| COTH | <Badge type="info" text="Not implemented yet" /> | |
@@ -77,7 +77,7 @@ You can track the progress in this [GitHub issue](https://github.com/ironcalc/Ir
| SERIESSUM | <Badge type="info" text="Not implemented yet" /> | |
| SEQUENCE | <Badge type="info" text="Not implemented yet" /> | |
| SIGN | <Badge type="info" text="Not implemented yet" /> | |
| SIN | <Badge type="tip" text="Available" /> | [SIN](math_and_trigonometry/sin) |
| SIN | <Badge type="tip" text="Available" /> | |
| SINH | <Badge type="tip" text="Available" /> | |
| SQRT | <Badge type="tip" text="Available" /> | |
| SQRTPI | <Badge type="info" text="Not implemented yet" /> | |
@@ -90,6 +90,6 @@ You can track the progress in this [GitHub issue](https://github.com/ironcalc/Ir
| SUMX2MY2 | <Badge type="info" text="Not implemented yet" /> | |
| SUMX2PY2 | <Badge type="info" text="Not implemented yet" /> | |
| SUMXMY2 | <Badge type="info" text="Not implemented yet" /> | |
| TAN | <Badge type="tip" text="Available" /> | [TAN](math_and_trigonometry/tan) |
| TAN | <Badge type="tip" text="Available" /> | |
| TANH | <Badge type="tip" text="Available" /> | |
| TRUNC | <Badge type="info" text="Not implemented yet" /> | |

View File

@@ -3,41 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# COS function
# COS
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
COS is a function of the Math and Trigonometry category that calculates the trigonometric cosine of an angle, returning a value in the range [-1, +1].
## Usage
### Syntax
**COS(<span title="Number" style="color:#1E88E5">angle</span>) => <span title="Number" style="color:#1E88E5">cos</span>**
### Argument descriptions
* *angle* ([number](/features/value-types#numbers), required). The angle whose cosine is to be calculated, expressed in radians. To convert between degrees and radians, use the relation below. Alternatively, use the [DEGREES](/functions/math_and_trigonometry/degrees) or [RADIANS](/functions/math_and_trigonometry/radians) functions.
$$
1~\:~\text{degree} = \dfrac{\pi}{180} = 0.01745329252~\text{radians}
$$
### Additional guidance
None.
### Returned value
COS returns a unitless [number](/features/value-types#numbers) that is the trigonometric cosine of the specified angle.
### Error conditions
* In common with many other IronCalc functions, COS propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then COS returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of the *angle* argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then COS returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, COS may return a [`#DIV/0!`](/features/error-types.md#div-0) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
* The COS function utilizes the *cos()* method provided by the [Rust Standard Library](https://doc.rust-lang.org/std/).
* The figure below illustrates the output of the COS function for angles $x$ in the range -2$\pi$ to +2$\pi$ radians.
<center><img src="/functions/images/cosine-curve.png" width="350" alt="Graph showing cos(x) for x between -2π and +2π radians."></center>
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=cos).
## Links
* For more information about trigonometric cosine, visit Wikipedia's [Sine and cosine](https://en.wikipedia.org/wiki/Sine_and_cosine) page.
* See also IronCalc's [ACOS](/functions/math_and_trigonometry/acos), [SIN](/functions/math_and_trigonometry/sin) and [TAN](/functions/math_and_trigonometry/tan) functions.
* Visit Microsoft Excel's [COS function](https://support.microsoft.com/en-gb/office/cos-function-0fb808a5-95d6-4553-8148-22aebdce5f05) page.
* Both [Google Sheets](https://support.google.com/docs/answer/3093476) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/COS) provide versions of the COS function.
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -3,41 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# SIN function
# SIN
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
SIN is a function of the Math and Trigonometry category that calculates the trigonometric sine of an angle, returning a value in the range [-1, +1].
## Usage
### Syntax
**SIN(<span title="Number" style="color:#1E88E5">angle</span>) => <span title="Number" style="color:#1E88E5">sin</span>**
### Argument descriptions
* *angle* ([number](/features/value-types#numbers), required). The angle whose sine is to be calculated, expressed in radians. To convert between degrees and radians, use the relation below. Alternatively, use the [DEGREES](/functions/math_and_trigonometry/degrees) or [RADIANS](/functions/math_and_trigonometry/radians) functions.
$$
1~\:~\text{degree} = \dfrac{\pi}{180} = 0.01745329252~\text{radians}
$$
### Additional guidance
None.
### Returned value
SIN returns a unitless [number](/features/value-types#numbers) that is the trigonometric sine of the specified angle.
### Error conditions
* In common with many other IronCalc functions, SIN propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then SIN returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of the *angle* argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then SIN returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, SIN may return a [`#DIV/0!`](/features/error-types.md#div-0) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
* The SIN function utilizes the *sin()* method provided by the [Rust Standard Library](https://doc.rust-lang.org/std/).
* The figure below illustrates the output of the SIN function for angles $x$ in the range -2$\pi$ to +2$\pi$ radians.
<center><img src="/functions/images/sine-curve.png" width="350" alt="Graph showing sin(x) for x between -2π and +2π."></center>
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=sin).
## Links
* For more information about trigonometric sine, visit Wikipedia's [Sine and cosine](https://en.wikipedia.org/wiki/Sine_and_cosine) page.
* See also IronCalc's [ASIN](/functions/math_and_trigonometry/asin), [COS](/functions/math_and_trigonometry/cos) and [TAN](/functions/math_and_trigonometry/tan) functions.
* Visit Microsoft Excel's [SIN function](https://support.microsoft.com/en-gb/office/sin-function-cf0e3432-8b9e-483c-bc55-a76651c95602) page.
* Both [Google Sheets](https://support.google.com/docs/answer/3093447) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/SIN) provide versions of the SIN function.
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

View File

@@ -3,42 +3,9 @@ layout: doc
outline: deep
lang: en-US
---
# TAN function
# TAN
::: warning
**Note:** This draft page is under construction 🚧
:::
## Overview
TAN is a function of the Math and Trigonometry category that calculates the trigonometric tangent of an angle, returning a value in the range (-$\infty$, +$\infty$).
## Usage
### Syntax
**TAN(<span title="Number" style="color:#1E88E5">angle</span>) => <span title="Number" style="color:#1E88E5">tan</span>**
### Argument descriptions
* *angle* ([number](/features/value-types#numbers), required). The angle whose tangent is to be calculated, expressed in radians. To convert between degrees and radians, use the relation below. Alternatively, use the [DEGREES](/functions/math_and_trigonometry/degrees) or [RADIANS](/functions/math_and_trigonometry/radians) functions.
$$
1~\:~\text{degree} = \dfrac{\pi}{180} = 0.01745329252~\text{radians}
$$
### Additional guidance
None.
### Returned value
TAN returns a unitless [number](/features/value-types#numbers) that is the trigonometric tangent of the specified angle.
### Error conditions
* In common with many other IronCalc functions, TAN propagates errors that are found in its argument.
* If no argument, or more than one argument, is supplied, then TAN returns the [`#ERROR!`](/features/error-types.md#error) error.
* If the value of the *angle* argument is not (or cannot be converted to) a [number](/features/value-types#numbers), then TAN returns the [`#VALUE!`](/features/error-types.md#value) error.
* For some argument values, TAN may return a [`#DIV/0!`](/features/error-types.md#div-0) error.
<!--@include: ../markdown-snippets/error-type-details.txt-->
## Details
* The TAN function utilizes the *tan()* method provided by the [Rust Standard Library](https://doc.rust-lang.org/std/).
* The figure below illustrates the output of the TAN function for angles $x$ in the range -2$π$ to +2$π$.
<center><img src="/functions/images/tangent-curve.png" width="350" alt="Graph showing tan(x) for x between -2π and +2π."></center>
* Theoretically, $\text{tan}(x)$ is undefined for any critical $x$ that satisfies $x = \frac{\pi}{2} + k\pi$ (where $k$ is any integer). However, an exact representation of the mathmatical constant $\pi$ requires infinite precision, which cannot be achieved with the floating-point representation available. Hence, TAN will return very large or very small values close to critical $x$ values.
## Examples
[See some examples in IronCalc](https://app.ironcalc.com/?example=tan).
## Links
* For more information about trigonometric tangent, visit Wikipedia's [Trigonometric functions](https://en.wikipedia.org/wiki/Trigonometric_functions) page.
* See also IronCalc's [ATAN](/functions/math_and_trigonometry/atan), [COS](/functions/math_and_trigonometry/cos) and [SIN](/functions/math_and_trigonometry/sin) functions.
* Visit Microsoft Excel's [TAN function](https://support.microsoft.com/en-gb/office/tan-function-08851a40-179f-4052-b789-d7f699447401) page.
* Both [Google Sheets](https://support.google.com/docs/answer/3093586) and [LibreOffice Calc](https://wiki.documentfoundation.org/Documentation/Calc_Functions/TAN) provide versions of the TAN function.
🚧 This function is implemented but currently lacks detailed documentation. For guidance, you may refer to the equivalent functionality in [Microsoft Excel documentation](https://support.microsoft.com/en-us/office/excel-functions-by-category-5f91f4e9-7b42-46d2-9bd1-63f26a86c0eb).
:::

Some files were not shown because too many files have changed in this diff Show More