Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API fix #687

Merged
merged 27 commits into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Breaking change**: Changed API of many sheet-related methods to take sheetId instead of sheetName as an argument. (#645)
- **Breaking change**: Removed support for matrix formulas (`{=FORMULA}`) notation. Engine now supports formulas returning array of values (instead of only scalars). (#652)
- **Breaking change**: Removed numeric matrix detection along with matrixDetection and matrixDetectionThreshold config options. (#669)
- **Breaking change**: Changed API of the following methods to take `SimpleCellRange` type argument: `copy`, `cut`, `getCellDependents`, `getCellPrecedents`, `getFillRangeData`, `getRangeFormulas`, `getRangeSerialized`, `getRangeValues`, `isItPossibleToMoveCells`, `isItPossibleToSetCellContents`, `moveCells`. (#687)
- Changed SWITCH function so it takes array as its first argument.

### Added
Expand Down
43 changes: 35 additions & 8 deletions src/AbsoluteCellRange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,38 @@
* Copyright (c) 2021 Handsoncode. All rights reserved.
*/

import {CellRange, simpleCellAddress, SimpleCellAddress, SimpleColumnAddress, SimpleRowAddress} from './Cell'
import {
CellRange, isSimpleCellAddress,
simpleCellAddress,
SimpleCellAddress,
SimpleColumnAddress,
SimpleRowAddress
} from './Cell'
import {DependencyGraph} from './DependencyGraph'
import {SheetsNotEqual} from './errors'
import {Maybe} from './Maybe'
import {AstNodeType, CellAddress, CellRangeAst} from './parser'
import {ColumnRangeAst, RowRangeAst} from './parser/Ast'
import {RowsSpan, Span} from './Span'

export const DIFFERENT_SHEETS_ERROR = 'AbsoluteCellRange: Start and end are in different sheets'
export const WRONG_RANGE_SIZE = 'AbsoluteCellRange: Wrong range size'

export class AbsoluteCellRange {
export interface SimpleCellRange {
start: SimpleCellAddress,
end: SimpleCellAddress,
}

export function isSimpleCellRange(obj: any): obj is SimpleCellRange {
if( obj && (typeof obj === 'object' || typeof obj === 'function')) {
return 'start' in obj && isSimpleCellAddress(obj.start) && 'end' in obj && isSimpleCellAddress(obj.end)
} else {
return false
}
}

export const simpleCellRange = (start: SimpleCellAddress, end: SimpleCellAddress) => ({start, end})

export class AbsoluteCellRange implements SimpleCellRange {
public readonly start: SimpleCellAddress
public readonly end: SimpleCellAddress

Expand All @@ -27,7 +48,7 @@ export class AbsoluteCellRange {
} else if (ast.type === AstNodeType.COLUMN_RANGE) {
return AbsoluteColumnRange.fromColumnRange(ast, baseAddress)
} else {
return AbsoluteRowRange.fromRowRange(ast, baseAddress)
return AbsoluteRowRange.fromRowRangeAst(ast, baseAddress)
}
}

Expand All @@ -51,8 +72,14 @@ export class AbsoluteCellRange {

public static spanFrom(topLeftCorner: SimpleCellAddress, width: number, height: number): AbsoluteCellRange {
if (!Number.isFinite(width) && Number.isFinite(height)) {
if(topLeftCorner.col !== 0) {
throw new Error(WRONG_RANGE_SIZE)
}
return new AbsoluteRowRange(topLeftCorner.sheet, topLeftCorner.row, topLeftCorner.row + height - 1)
} else if (!Number.isFinite(height) && Number.isFinite(width)) {
if(topLeftCorner.row !== 0) {
throw new Error(WRONG_RANGE_SIZE)
}
return new AbsoluteColumnRange(topLeftCorner.sheet, topLeftCorner.col, topLeftCorner.col + width - 1)
} else if (Number.isFinite(height) && Number.isFinite(width)) {
return new AbsoluteCellRange(
Expand All @@ -77,7 +104,7 @@ export class AbsoluteCellRange {
end: SimpleCellAddress,
) {
if (start.sheet !== end.sheet) {
throw new Error(DIFFERENT_SHEETS_ERROR)
throw new SheetsNotEqual(start.sheet, end.sheet)
}
this.start = simpleCellAddress(start.sheet, start.col, start.row)
this.end = simpleCellAddress(end.sheet, end.col, end.row)
Expand Down Expand Up @@ -375,7 +402,7 @@ export class AbsoluteColumnRange extends AbsoluteCellRange {
const start = x.start.toSimpleColumnAddress(baseAddress)
const end = x.end.toSimpleColumnAddress(baseAddress)
if (start.sheet !== end.sheet) {
throw new Error(DIFFERENT_SHEETS_ERROR)
throw new SheetsNotEqual(start.sheet, end.sheet)
}
return new AbsoluteColumnRange(start.sheet, start.col, end.col)
}
Expand Down Expand Up @@ -422,11 +449,11 @@ export class AbsoluteColumnRange extends AbsoluteCellRange {
}

export class AbsoluteRowRange extends AbsoluteCellRange {
public static fromRowRange(x: RowRangeAst, baseAddress: SimpleCellAddress): AbsoluteRowRange {
public static fromRowRangeAst(x: RowRangeAst, baseAddress: SimpleCellAddress): AbsoluteRowRange {
const start = x.start.toSimpleRowAddress(baseAddress)
const end = x.end.toSimpleRowAddress(baseAddress)
if (start.sheet !== end.sheet) {
throw new Error(DIFFERENT_SHEETS_ERROR)
throw new SheetsNotEqual(start.sheet, end.sheet)
}
return new AbsoluteRowRange(start.sheet, start.row, end.row)
}
Expand Down
8 changes: 8 additions & 0 deletions src/Cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,14 @@ export const movedSimpleCellAddress = (address: SimpleCellAddress, toSheet: numb
return simpleCellAddress(toSheet, address.col + toRight, address.row + toBottom)
}

export function isSimpleCellAddress(obj: any): obj is SimpleCellAddress {
if( obj && (typeof obj === 'object' || typeof obj === 'function')) {
return 'col' in obj && typeof obj.col === 'number' && 'row' in obj && typeof obj.row === 'number' && 'sheet' in obj && typeof obj.sheet === 'number'
} else {
return false
}
}

export const absoluteSheetReference = (address: AddressWithSheet, baseAddress: SimpleCellAddress): number => {
return address.sheet === null ? baseAddress.sheet : address.sheet
}
Expand Down
25 changes: 13 additions & 12 deletions src/DependencyGraph/DependencyGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* Copyright (c) 2021 Handsoncode. All rights reserved.
*/

import {AbsoluteCellRange} from '../AbsoluteCellRange'
import {AbsoluteCellRange, SimpleCellRange, simpleCellRange} from '../AbsoluteCellRange'
import {absolutizeDependencies} from '../absolutizeDependencies'
import {CellError, ErrorType, simpleCellAddress, SimpleCellAddress} from '../Cell'
import {CellError, ErrorType, isSimpleCellAddress, simpleCellAddress, SimpleCellAddress} from '../Cell'
import {RawCellContent} from '../CellContentParser'
import {CellDependency} from '../CellDependency'
import {Config} from '../Config'
Expand Down Expand Up @@ -653,7 +653,7 @@ export class DependencyGraph {
}
}

public dependencyQueryAddresses: (vertex: Vertex) => Maybe<(SimpleCellAddress | AbsoluteCellRange)[]> = (vertex: Vertex) => {
public dependencyQueryAddresses: (vertex: Vertex) => (SimpleCellAddress | SimpleCellRange)[] = (vertex: Vertex) => {
if (vertex instanceof RangeVertex) {
return this.rangeDependencyQuery(vertex).map(([address, _]) => address)
} else {
Expand All @@ -662,19 +662,20 @@ export class DependencyGraph {
const [address, dependencies] = dependenciesResult
return dependencies.map((dependency: CellDependency) => {
if (dependency instanceof NamedExpressionDependency) {
const namedExpression = this.namedExpressions.namedExpressionOrPlaceholder(dependency.name, address.sheet)
return namedExpression.address
} else {
return this.namedExpressions.namedExpressionOrPlaceholder(dependency.name, address.sheet).address
} else if (isSimpleCellAddress(dependency)) {
return dependency
} else {
return simpleCellRange(dependency.start, dependency.end)
}
})
} else {
return undefined
return []
}
}
}

public dependencyQueryVertices: (vertex: Vertex) => Maybe<Vertex[]> = (vertex: Vertex) => {
public dependencyQueryVertices: (vertex: Vertex) => Vertex[] = (vertex: Vertex) => {
if (vertex instanceof RangeVertex) {
return this.rangeDependencyQuery(vertex).map(([_, v]) => v)
} else {
Expand All @@ -692,7 +693,7 @@ export class DependencyGraph {
}
})
} else {
return undefined
return []
}
}
}
Expand Down Expand Up @@ -881,13 +882,13 @@ export class DependencyGraph {
}
}

public getAdjacentNodesAddresses(inputVertex: Vertex): (AbsoluteCellRange | SimpleCellAddress)[] {
public getAdjacentNodesAddresses(inputVertex: Vertex): (SimpleCellRange | SimpleCellAddress)[] {
const deps = this.graph.adjacentNodes(inputVertex)
const ret: (AbsoluteCellRange | SimpleCellAddress)[] = []
const ret: (SimpleCellRange | SimpleCellAddress)[] = []
deps.forEach((vertex: Vertex) => {
const castVertex = vertex as RangeVertex | FormulaCellVertex | MatrixVertex
if (castVertex instanceof RangeVertex) {
ret.push(new AbsoluteCellRange(castVertex.start, castVertex.end))
ret.push(simpleCellRange(castVertex.start, castVertex.end))
} else {
ret.push(castVertex.getAddress(this.lazilyTransformingAstService))
}
Expand Down
5 changes: 1 addition & 4 deletions src/DependencyGraph/Graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import {Maybe} from '../Maybe'

export type DependencyQuery<T> = (vertex: T) => Maybe<T[]>
export type DependencyQuery<T> = (vertex: T) => T[]

export interface TopSortResult<T> {
sorted: T[], cycled: T[],
Expand Down Expand Up @@ -320,9 +320,6 @@ export class Graph<T> {

private removeDependencies(node: T): T[] {
const dependencies = this.dependencyQuery(node)
if (!dependencies) {
return []
}
for (const dependency of dependencies) {
this.softRemoveEdge(dependency, node)
}
Expand Down
Loading