hyperformula
Version:
HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas
110 lines • 4.12 kB
JavaScript
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/
import { CellError, ErrorType } from "./Cell.mjs";
import { DetailedCellError } from "./CellValue.mjs";
import { ErrorMessage } from "./error-message.mjs";
import { EmptyValue, getRawValue, isExtendedNumber } from "./interpreter/InterpreterValue.mjs";
import { SimpleRangeValue } from "./SimpleRangeValue.mjs";
import { NamedExpressions } from "./NamedExpressions.mjs";
import { simpleCellAddressToString } from "./parser/addressRepresentationConverters.mjs";
/**
* A list of cells which values changed after the operation, their absolute addresses and new values.
*/
export class ExportedCellChange {
constructor(address, newValue) {
this.address = address;
this.newValue = newValue;
}
get col() {
return this.address.col;
}
get row() {
return this.address.row;
}
get sheet() {
return this.address.sheet;
}
get value() {
return this.newValue;
}
}
export class ExportedNamedExpressionChange {
constructor(name, newValue) {
this.name = name;
this.newValue = newValue;
}
}
export class Exporter {
constructor(config, namedExpressions, sheetMapping, lazilyTransformingService) {
this.config = config;
this.namedExpressions = namedExpressions;
this.sheetMapping = sheetMapping;
this.lazilyTransformingService = lazilyTransformingService;
}
exportChange(change) {
const value = change.value;
const address = change.address;
if (address.sheet === NamedExpressions.SHEET_FOR_WORKBOOK_EXPRESSIONS) {
const namedExpression = this.namedExpressions.namedExpressionInAddress(address.row);
if (!namedExpression) {
throw new Error('Missing named expression');
}
return new ExportedNamedExpressionChange(namedExpression.displayName, this.exportScalarOrRange(value));
} else if (value instanceof SimpleRangeValue) {
const result = [];
for (const [cellValue, cellAddress] of value.entriesFromTopLeftCorner(address)) {
result.push(new ExportedCellChange(cellAddress, this.exportValue(cellValue)));
}
return result;
} else {
return new ExportedCellChange(address, this.exportValue(value));
}
}
exportValue(value) {
if (value instanceof SimpleRangeValue) {
return this.detailedError(new CellError(ErrorType.VALUE, ErrorMessage.ScalarExpected));
} else if (this.config.smartRounding && isExtendedNumber(value)) {
return this.cellValueRounding(getRawValue(value));
} else if (value instanceof CellError) {
return this.detailedError(value);
} else if (value === EmptyValue) {
return null;
} else {
return getRawValue(value);
}
}
exportScalarOrRange(value) {
if (value instanceof SimpleRangeValue) {
return value.rawData().map(row => row.map(v => this.exportValue(v)));
} else {
return this.exportValue(value);
}
}
detailedError(error) {
var _a, _b;
let address = undefined;
const originAddress = (_a = error.root) === null || _a === void 0 ? void 0 : _a.getAddress(this.lazilyTransformingService);
if (originAddress !== undefined) {
if (originAddress.sheet === NamedExpressions.SHEET_FOR_WORKBOOK_EXPRESSIONS) {
address = (_b = this.namedExpressions.namedExpressionInAddress(originAddress.row)) === null || _b === void 0 ? void 0 : _b.displayName;
} else {
address = simpleCellAddressToString(this.sheetMapping.getSheetNameOrThrowError.bind(this.sheetMapping), originAddress, -1);
}
}
return new DetailedCellError(error, this.config.translationPackage.getErrorTranslation(error.type), address);
}
cellValueRounding(value) {
if (value === 0) {
return value;
}
const magnitudeMultiplierExponent = Math.floor(Math.log10(Math.abs(value)));
const placesMultiplier = Math.pow(10, this.config.precisionRounding - magnitudeMultiplierExponent);
if (value < 0) {
return -Math.round(-value * placesMultiplier) / placesMultiplier;
} else {
return Math.round(value * placesMultiplier) / placesMultiplier;
}
}
}