Skip to content

Commit

Permalink
Merge branch 'develop' into feature/issue-1300
Browse files Browse the repository at this point in the history
  • Loading branch information
sequba authored Nov 13, 2024
2 parents ed8c31e + 4ca2f87 commit 9144ac2
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 29 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

### Changed

- **Breaking change**: Change ES module build to use `mjs` files and `exports` property in `package.json` to make importing language files possible in Node environment. [#1344](https://github.com/handsontable/hyperformula/issues/1344)
- **Breaking change**: Removed the `binarySearchThreshold` configuration option. [#1439](https://github.com/handsontable/hyperformula/issues/1439)
- **Breaking change**: Changed ES module build to use `mjs` files and `exports` property in `package.json` to make importing language files possible in Node environment. [#1344](https://github.com/handsontable/hyperformula/issues/1344)
- **Breaking change**: Changed the default value of the `precisionRounding` configuration option to `10`. [#1300](https://github.com/handsontable/hyperformula/issues/1300)
- Make methods `simpleCellAddressToString` and `simpleCellRangeToString` more logical and easier to use. [#1151](https://github.com/handsontable/hyperformula/issues/1151)

### Removed

- **Breaking change**: Removed the `binarySearchThreshold` configuration option. [#1439](https://github.com/handsontable/hyperformula/issues/1439)

## [2.7.1] - 2024-07-18

Expand Down
89 changes: 62 additions & 27 deletions src/HyperFormula.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import {NamedExpression, NamedExpressionOptions, NamedExpressions} from './Named
import {normalizeAddedIndexes, normalizeRemovedIndexes} from './Operations'
import {
Ast,
AstNodeType, NamedExpressionDependency,
NamedExpressionDependency,
ParserWithCaching,
RelativeDependency,
simpleCellAddressFromString,
Expand Down Expand Up @@ -2791,10 +2791,10 @@ export class HyperFormula implements TypedEmitter {
/**
* Computes the simple (absolute) address of a cell address, based on its string representation.
* - If a sheet name is present in the string representation but is not present in the engine, returns `undefined`.
* - If no sheet name is present in the string representation, returns `contextSheetId` as sheet number.
* - If no sheet name is present in the string representation, uses `contextSheetId` as a sheet id in the returned address.
*
* @param {string} cellAddress - string representation of cell address in A1 notation
* @param {number} contextSheetId - context used in case of missing sheet in the first argument
* @param {number} contextSheetId - sheet id used to construct the simple address in case of missing sheet name in `cellAddress` argument
*
* @throws [[ExpectedValueOfTypeError]] if any of its basic type argument is of wrong type
*
Expand All @@ -2803,17 +2803,17 @@ export class HyperFormula implements TypedEmitter {
* const hfInstance = HyperFormula.buildEmpty();
* hfInstance.addSheet('Sheet0'); //sheetId = 0
*
* // returns { sheet: 0, col: 0, row: 0 }
* const simpleCellAddress = hfInstance.simpleCellAddressFromString('A1', 0);
* // returns { sheet: 42, col: 0, row: 0 }
* const simpleCellAddress = hfInstance.simpleCellAddressFromString('A1', 42);
*
* // returns { sheet: 0, col: 0, row: 5 }
* const simpleCellAddress = hfInstance.simpleCellAddressFromString('Sheet1!A6');
* const simpleCellAddress = hfInstance.simpleCellAddressFromString('Sheet0!A6', 42);
*
* // returns { sheet: 0, col: 0, row: 5 }
* const simpleCellAddress = hfInstance.simpleCellAddressFromString('Sheet1!$A$6');
* const simpleCellAddress = hfInstance.simpleCellAddressFromString('Sheet0!$A$6', 42);
*
* // returns 'undefined', as there's no 'Sheet 2' in the HyperFormula instance
* const simpleCellAddress = hfInstance.simpleCellAddressFromString('Sheet2!A6');
* const simpleCellAddress = hfInstance.simpleCellAddressFromString('Sheet2!A6', 42);
* ```
*
* @category Helpers
Expand All @@ -2829,7 +2829,7 @@ export class HyperFormula implements TypedEmitter {
* If sheet name is present in string representation but not present in the engine, returns `undefined`.
*
* @param {string} cellRange - string representation of cell range in A1 notation
* @param {number} sheetId - context used in case of missing sheet in the first argument
* @param {number} contextSheetId - sheet id used to construct the simple address in case of missing sheet name in `cellRange` argument
*
* @throws [[NoSheetWithIdError]] when the given sheet ID does not exist
* @throws [[ExpectedValueOfTypeError]] if any of its basic type argument is of wrong type
Expand All @@ -2845,70 +2845,105 @@ export class HyperFormula implements TypedEmitter {
*
* @category Helpers
*/
public simpleCellRangeFromString(cellRange: string, sheetId: number): SimpleCellRange | undefined {
public simpleCellRangeFromString(cellRange: string, contextSheetId: number): SimpleCellRange | undefined {
validateArgToType(cellRange, 'string', 'cellRange')
validateArgToType(sheetId, 'number', 'sheetId')
return simpleCellRangeFromString(this.sheetMapping.get, cellRange, sheetId)
validateArgToType(contextSheetId, 'number', 'sheetId')
return simpleCellRangeFromString(this.sheetMapping.get, cellRange, contextSheetId)
}

/**
* Returns string representation of an absolute address in A1 notation or `undefined` if the sheet index is not present in the engine.
* Computes string representation of an absolute address in A1 notation. If `cellAddress.sheet` is not present in the engine, returns `undefined`.
*
* @param {SimpleCellAddress} cellAddress - object representation of an absolute address
* @param {number} sheetId - context used in case of missing sheet in the first argument
* @param {object | number} optionsOrContextSheetId - options object or number used as context sheet id to construct the string address (see examples)
*
* @throws [[ExpectedValueOfTypeError]] if its arguments are of wrong type
*
* @example
* ```js
* const hfInstance = HyperFormula.buildEmpty();
* hfInstance.addSheet('Sheet0'); //sheetId = 0
* const addr = { sheet: 0, col: 1, row: 1 };
*
* // should return 'B2'
* const A1Notation = hfInstance.simpleCellAddressToString({ sheet: 0, col: 1, row: 1 }, 0);
* const A1Notation = hfInstance.simpleCellAddressToString(addr);
*
* // should return 'B2'
* const A1Notation = hfInstance.simpleCellAddressToString(addr, { includeSheetName: false });
*
* // should return 'Sheet0!B2'
* const A1Notation = hfInstance.simpleCellAddressToString(addr, { includeSheetName: true });
*
* // should return 'B2' as context sheet id is the same as addr.sheet
* const A1Notation = hfInstance.simpleCellAddressToString(addr, 0);
*
* // should return 'Sheet0!B2' as context sheet id is different from addr.sheet
* const A1Notation = hfInstance.simpleCellAddressToString(addr, 42);
* ```
*
* @category Helpers
*/
public simpleCellAddressToString(cellAddress: SimpleCellAddress, sheetId: number): string | undefined {
public simpleCellAddressToString(cellAddress: SimpleCellAddress, optionsOrContextSheetId: { includeSheetName?: boolean } | number = {}) {
if (!isSimpleCellAddress(cellAddress)) {
throw new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress')
}
validateArgToType(sheetId, 'number', 'sheetId')
return simpleCellAddressToString(this.sheetMapping.fetchDisplayName, cellAddress, sheetId)

const contextSheetId = typeof optionsOrContextSheetId === 'number'
? optionsOrContextSheetId
: optionsOrContextSheetId.includeSheetName ? cellAddress.sheet+1 : cellAddress.sheet

return simpleCellAddressToString(this.sheetMapping.fetchDisplayName, cellAddress, contextSheetId)
}

/**
* Returns string representation of an absolute range in A1 notation or `undefined` if the sheet index is not present in the engine.
* Computes string representation of an absolute range in A1 notation.
* Returns `undefined` if:
* - `cellRange` is not a valid range,
* - `cellRange.start.sheet` and `cellRange.start.end` are different,
* - `cellRange.start.sheet` is not present in the engine,
* - `cellRange.start.end` is not present in the engine.
*
* Note: This method is useful only for cell ranges; does not work with column ranges and row ranges.
*
* @param {SimpleCellRange} cellRange - object representation of an absolute range
* @param {number} sheetId - context used in case of missing sheet in the first argument
* @param {object | number} optionsOrContextSheetId - options object or number used as context sheet id to construct the string address (see examples)
*
* @throws [[ExpectedValueOfTypeError]] if its arguments are of wrong type
*
* @example
* ```js
* const hfInstance = HyperFormula.buildEmpty();
* hfInstance.addSheet('Sheet0'); //sheetId = 0
* hfInstance.addSheet('Sheet1'); //sheetId = 1
* const range = { start: { sheet: 0, col: 1, row: 1 }, end: { sheet: 0, col: 2, row: 1 } };
*
* // should return 'B2:C2'
* const A1Notation = hfInstance.simpleCellRangeToString(range);
*
* // should return 'B2:C2'
* const A1Notation = hfInstance.simpleCellRangeToString({ start: { sheet: 0, col: 1, row: 1 }, end: { sheet: 0, col: 2, row: 1 } }, 0);
* const A1Notation = hfInstance.simpleCellRangeToString(range, { includeSheetName: false });
*
* // should return 'Sheet0!B2:C2'
* const A1Notation = hfInstance.simpleCellRangeToString(range, { includeSheetName: true });
*
* // should return 'Sheet1!B2:C2'
* const another = hfInstance.simpleCellRangeToString({ start: { sheet: 1, col: 1, row: 1 }, end: { sheet: 1, col: 2, row: 1 } }, 0);
* // should return 'B2:C2' as context sheet id is the same as range.start.sheet and range.end.sheet
* const A1Notation = hfInstance.simpleCellRangeToString(range, 0);
*
* // should return 'Sheet0!B2:C2' as context sheet id is different from range.start.sheet and range.end.sheet
* const A1Notation = hfInstance.simpleCellRangeToString(range, 42);
* ```
*
* @category Helpers
*/
public simpleCellRangeToString(cellRange: SimpleCellRange, sheetId: number): string | undefined {
public simpleCellRangeToString(cellRange: SimpleCellRange, optionsOrContextSheetId: { includeSheetName?: boolean } | number = {}): string | undefined {
if (!isSimpleCellRange(cellRange)) {
throw new ExpectedValueOfTypeError('SimpleCellRange', 'cellRange')
}
validateArgToType(sheetId, 'number', 'sheetId')
return simpleCellRangeToString(this.sheetMapping.fetchDisplayName, cellRange, sheetId)

const contextSheetId = typeof optionsOrContextSheetId === 'number'
? optionsOrContextSheetId
: optionsOrContextSheetId.includeSheetName ? cellRange.start.sheet+cellRange.end.sheet+1 : cellRange.start.sheet

return simpleCellRangeToString(this.sheetMapping.fetchDisplayName, cellRange, contextSheetId)
}

/**
Expand Down
151 changes: 151 additions & 0 deletions test/engine.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,66 @@ describe('#simpleCellRangeToString', () => {
engine.simpleCellRangeToString({} as SimpleCellRange, 0)
}).toThrow(new ExpectedValueOfTypeError('SimpleCellRange', 'cellRange'))
})

it('should work without second argument', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellRange = { start: { sheet: 0, row: 0, col: 0 }, end: { sheet: 0, row: 1, col: 1 }}
const stringRange = hf.simpleCellRangeToString(cellRange)

expect(stringRange).toEqual('A1:B2')
})

it('should work with second argument `undefined`', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellRange = { start: { sheet: 0, row: 0, col: 0 }, end: { sheet: 0, row: 1, col: 1 }}
const stringRange = hf.simpleCellRangeToString(cellRange, undefined)

expect(stringRange).toEqual('A1:B2')
})

it('should work with second argument `{}`', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellRange = { start: { sheet: 0, row: 0, col: 0 }, end: { sheet: 0, row: 1, col: 1 }}
const stringRange = hf.simpleCellRangeToString(cellRange, {})

expect(stringRange).toEqual('A1:B2')
})

it('should work with second argument `{ includeSheetName: false }`', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellRange = { start: { sheet: 0, row: 0, col: 0 }, end: { sheet: 0, row: 1, col: 1 }}
const stringRange = hf.simpleCellRangeToString(cellRange, { includeSheetName: false })

expect(stringRange).toEqual('A1:B2')
})

it('should work with second argument `{ includeSheetName: true }`', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellRange = { start: { sheet: 0, row: 0, col: 0 }, end: { sheet: 0, row: 1, col: 1 }}
const stringRange = hf.simpleCellRangeToString(cellRange, { includeSheetName: true })

expect(stringRange).toEqual('Sheet0!A1:B2')
})
})

describe('#simpleCellAddressToString', () => {
Expand All @@ -1061,6 +1121,66 @@ describe('#simpleCellAddressToString', () => {
engine.simpleCellAddressToString({} as SimpleCellAddress, 0)
}).toThrow(new ExpectedValueOfTypeError('SimpleCellAddress', 'cellAddress'))
})

it('should work without second argument', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellAddress = { sheet: 0, row: 0, col: 0 }
const stringAddress = hf.simpleCellAddressToString(cellAddress)

expect(stringAddress).toEqual('A1')
})

it('should work with second argument `undefined`', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellAddress = { sheet: 0, row: 0, col: 0 }
const stringAddress = hf.simpleCellAddressToString(cellAddress, undefined)

expect(stringAddress).toEqual('A1')
})

it('should work with second argument `{}`', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellAddress = { sheet: 0, row: 0, col: 0 }
const stringAddress = hf.simpleCellAddressToString(cellAddress, {})

expect(stringAddress).toEqual('A1')
})

it('should work with second argument `{ includeSheetName: false }`', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellAddress = { sheet: 0, row: 0, col: 0 }
const stringAddress = hf.simpleCellAddressToString(cellAddress, { includeSheetName: false })

expect(stringAddress).toEqual('A1')
})

it('should work with second argument `{ includeSheetName: true }`', () => {
const hf = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

const cellAddress = { sheet: 0, row: 0, col: 0 }
const stringAddress = hf.simpleCellAddressToString(cellAddress, { includeSheetName: true })

expect(stringAddress).toEqual('Sheet0!A1')
})
})

describe('#simpleCellAddressFromString', () => {
Expand Down Expand Up @@ -1098,4 +1218,35 @@ describe('#simpleCellRangeFromString', () => {
const engine = HyperFormula.buildEmpty()
expect(engine.simpleCellRangeFromString('A1:C1', 0)).toEqual(simpleCellRange(adr('A1'), adr('C1')))
})

it('should set sheetId to contestSheetId if there is no sheet name in the first argument', () => {
const engine = HyperFormula.buildEmpty()

expect(engine.simpleCellRangeFromString('A1:C1', 42)).toEqual(simpleCellRange(adr('A1', 42), adr('C1', 42)))
})

it('should set sheetId correctly if the sheet name is provided for the start of the range', () => {
const engine = HyperFormula.buildFromSheets({
Sheet0: []
})

expect(engine.simpleCellRangeFromString('Sheet0!A1:C1', 42)).toEqual(simpleCellRange(adr('A1', 0), adr('C1', 0)))
})

it('should set sheetId correctly if the same sheet name is provided for both ends of the range', () => {
const engine = HyperFormula.buildFromSheets({
Sheet0: []
})

expect(engine.simpleCellRangeFromString('Sheet0!A1:Sheet0!C1', 42)).toEqual(simpleCellRange(adr('A1', 0), adr('C1', 0)))
})

it('should return undefined if different sheet names are provided for the start and the end of the range', () => {
const engine = HyperFormula.buildFromSheets({
Sheet0: [],
Sheet1: []
})

expect(engine.simpleCellRangeFromString('Sheet0!A1:Sheet1!C1', 42)).toEqual(undefined)
})
})

0 comments on commit 9144ac2

Please sign in to comment.