hyperformula
Version:
HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas
231 lines • 9.9 kB
JavaScript
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/
import { configCheckIfParametersNotInConflict, configValueFromParam, configValueFromParamCheck, validateNumberToBeAtLeast, validateNumberToBeAtMost } from "./ArgumentSanitization.mjs";
import { defaultParseToDateTime } from "./DateTimeDefault.mjs";
import { instanceOfSimpleDate } from "./DateTimeHelper.mjs";
import { AlwaysDense } from "./DependencyGraph/AddressMapping/ChooseAddressMappingPolicy.mjs";
import { ConfigValueEmpty, ExpectedValueOfTypeError } from "./errors.mjs";
import { defaultStringifyDateTime, defaultStringifyDuration } from "./format/format.mjs";
import { checkLicenseKeyValidity } from "./helpers/licenseKeyValidator.mjs";
import { HyperFormula } from "./HyperFormula.mjs";
const privatePool = new WeakMap();
export class Config {
constructor(options = {}, showDeprecatedWarns = true) {
const {
accentSensitive,
caseSensitive,
caseFirst,
chooseAddressMappingPolicy,
context,
currencySymbol,
dateFormats,
decimalSeparator,
evaluateNullToZero,
functionArgSeparator,
functionPlugins,
ignorePunctuation,
leapYear1900,
localeLang,
language,
ignoreWhiteSpace,
licenseKey,
matchWholeCell,
arrayColumnSeparator,
arrayRowSeparator,
maxRows,
maxColumns,
nullYear,
nullDate,
parseDateTime,
precisionEpsilon,
precisionRounding,
stringifyDateTime,
stringifyDuration,
smartRounding,
timeFormats,
thousandSeparator,
useArrayArithmetic,
useStats,
undoLimit,
useColumnIndex,
useRegularExpressions,
useWildcards
} = options;
if (showDeprecatedWarns) {
Config.warnDeprecatedOptions(options);
}
this.useArrayArithmetic = configValueFromParam(useArrayArithmetic, 'boolean', 'useArrayArithmetic');
this.accentSensitive = configValueFromParam(accentSensitive, 'boolean', 'accentSensitive');
this.caseSensitive = configValueFromParam(caseSensitive, 'boolean', 'caseSensitive');
this.caseFirst = configValueFromParam(caseFirst, ['upper', 'lower', 'false'], 'caseFirst');
this.ignorePunctuation = configValueFromParam(ignorePunctuation, 'boolean', 'ignorePunctuation');
this.chooseAddressMappingPolicy = chooseAddressMappingPolicy !== null && chooseAddressMappingPolicy !== void 0 ? chooseAddressMappingPolicy : Config.defaultConfig.chooseAddressMappingPolicy;
this.dateFormats = [...configValueFromParamCheck(dateFormats, Array.isArray, 'array', 'dateFormats')];
this.timeFormats = [...configValueFromParamCheck(timeFormats, Array.isArray, 'array', 'timeFormats')];
this.functionArgSeparator = configValueFromParam(functionArgSeparator, 'string', 'functionArgSeparator');
this.decimalSeparator = configValueFromParam(decimalSeparator, ['.', ','], 'decimalSeparator');
this.language = configValueFromParam(language, 'string', 'language');
this.ignoreWhiteSpace = configValueFromParam(ignoreWhiteSpace, ['standard', 'any'], 'ignoreWhiteSpace');
this.licenseKey = configValueFromParam(licenseKey, 'string', 'licenseKey');
this.thousandSeparator = configValueFromParam(thousandSeparator, ['', ',', ' ', '.'], 'thousandSeparator');
this.arrayColumnSeparator = configValueFromParam(arrayColumnSeparator, [',', ';'], 'arrayColumnSeparator');
this.arrayRowSeparator = configValueFromParam(arrayRowSeparator, [';', '|'], 'arrayRowSeparator');
this.localeLang = configValueFromParam(localeLang, 'string', 'localeLang');
this.functionPlugins = [...(functionPlugins !== null && functionPlugins !== void 0 ? functionPlugins : Config.defaultConfig.functionPlugins)];
this.smartRounding = configValueFromParam(smartRounding, 'boolean', 'smartRounding');
this.evaluateNullToZero = configValueFromParam(evaluateNullToZero, 'boolean', 'evaluateNullToZero');
this.nullYear = configValueFromParam(nullYear, 'number', 'nullYear');
validateNumberToBeAtLeast(this.nullYear, 'nullYear', 0);
validateNumberToBeAtMost(this.nullYear, 'nullYear', 100);
this.precisionRounding = configValueFromParam(precisionRounding, 'number', 'precisionRounding');
validateNumberToBeAtLeast(this.precisionRounding, 'precisionRounding', 0);
this.precisionEpsilon = configValueFromParam(precisionEpsilon, 'number', 'precisionEpsilon');
validateNumberToBeAtLeast(this.precisionEpsilon, 'precisionEpsilon', 0);
this.useColumnIndex = configValueFromParam(useColumnIndex, 'boolean', 'useColumnIndex');
this.useStats = configValueFromParam(useStats, 'boolean', 'useStats');
this.parseDateTime = configValueFromParam(parseDateTime, 'function', 'parseDateTime');
this.stringifyDateTime = configValueFromParam(stringifyDateTime, 'function', 'stringifyDateTime');
this.stringifyDuration = configValueFromParam(stringifyDuration, 'function', 'stringifyDuration');
this.translationPackage = HyperFormula.getLanguage(this.language);
this.errorMapping = this.translationPackage.buildErrorMapping();
this.nullDate = configValueFromParamCheck(nullDate, instanceOfSimpleDate, 'IDate', 'nullDate');
this.leapYear1900 = configValueFromParam(leapYear1900, 'boolean', 'leapYear1900');
this.undoLimit = configValueFromParam(undoLimit, 'number', 'undoLimit');
this.useRegularExpressions = configValueFromParam(useRegularExpressions, 'boolean', 'useRegularExpressions');
this.useWildcards = configValueFromParam(useWildcards, 'boolean', 'useWildcards');
this.matchWholeCell = configValueFromParam(matchWholeCell, 'boolean', 'matchWholeCell');
validateNumberToBeAtLeast(this.undoLimit, 'undoLimit', 0);
this.maxRows = configValueFromParam(maxRows, 'number', 'maxRows');
validateNumberToBeAtLeast(this.maxRows, 'maxRows', 1);
this.maxColumns = configValueFromParam(maxColumns, 'number', 'maxColumns');
this.currencySymbol = this.setupCurrencySymbol(currencySymbol);
validateNumberToBeAtLeast(this.maxColumns, 'maxColumns', 1);
this.context = context;
privatePool.set(this, {
licenseKeyValidityState: checkLicenseKeyValidity(this.licenseKey)
});
configCheckIfParametersNotInConflict({
value: this.decimalSeparator,
name: 'decimalSeparator'
}, {
value: this.functionArgSeparator,
name: 'functionArgSeparator'
}, {
value: this.thousandSeparator,
name: 'thousandSeparator'
});
configCheckIfParametersNotInConflict({
value: this.arrayRowSeparator,
name: 'arrayRowSeparator'
}, {
value: this.arrayColumnSeparator,
name: 'arrayColumnSeparator'
});
}
setupCurrencySymbol(currencySymbol) {
const valueAfterCheck = [...configValueFromParamCheck(currencySymbol, Array.isArray, 'array', 'currencySymbol')];
valueAfterCheck.forEach(val => {
if (typeof val !== 'string') {
throw new ExpectedValueOfTypeError('string[]', 'currencySymbol');
}
if (val === '') {
throw new ConfigValueEmpty('currencySymbol');
}
});
return valueAfterCheck;
}
/**
* Proxied property to its private counterpart. This makes the property
* as accessible as the other Config options but without ability to change the value.
*
* @internal
*/
get licenseKeyValidityState() {
return privatePool.get(this).licenseKeyValidityState;
}
getConfig() {
return getFullConfigFromPartial(this);
}
mergeConfig(init) {
const mergedConfig = Object.assign({}, this.getConfig(), init);
Config.warnDeprecatedOptions(init);
return new Config(mergedConfig, false);
}
static warnDeprecatedOptions(options) {
// an example of deprecation warning
// Config.warnDeprecatedIfUsed(options.binarySearchThreshold, 'binarySearchThreshold', '1.1')
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static warnDeprecatedIfUsed(inputValue, paramName, fromVersion, replacementName) {
if (inputValue !== undefined) {
if (replacementName === undefined) {
console.warn(`${paramName} option is deprecated since ${fromVersion}`);
} else {
console.warn(`${paramName} option is deprecated since ${fromVersion}, please use ${replacementName}`);
}
}
}
}
Config.defaultConfig = {
accentSensitive: false,
currencySymbol: ['$'],
caseSensitive: false,
caseFirst: 'lower',
context: undefined,
chooseAddressMappingPolicy: new AlwaysDense(),
dateFormats: ['DD/MM/YYYY', 'DD/MM/YY'],
decimalSeparator: '.',
evaluateNullToZero: false,
functionArgSeparator: ',',
functionPlugins: [],
ignorePunctuation: false,
language: 'enGB',
ignoreWhiteSpace: 'standard',
licenseKey: '',
leapYear1900: false,
localeLang: 'en',
matchWholeCell: true,
arrayColumnSeparator: ',',
arrayRowSeparator: ';',
maxRows: 40000,
maxColumns: 18278,
nullYear: 30,
nullDate: {
year: 1899,
month: 12,
day: 30
},
parseDateTime: defaultParseToDateTime,
precisionEpsilon: 1e-13,
precisionRounding: 10,
smartRounding: true,
stringifyDateTime: defaultStringifyDateTime,
stringifyDuration: defaultStringifyDuration,
timeFormats: ['hh:mm', 'hh:mm:ss.sss'],
thousandSeparator: '',
undoLimit: 20,
useRegularExpressions: false,
useWildcards: true,
useColumnIndex: false,
useStats: false,
useArrayArithmetic: false
};
function getFullConfigFromPartial(partialConfig) {
var _a;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ret = {};
for (const key in Config.defaultConfig) {
const val = (_a = partialConfig[key]) !== null && _a !== void 0 ? _a : Config.defaultConfig[key];
if (Array.isArray(val)) {
ret[key] = [...val];
} else {
ret[key] = val;
}
}
return ret;
}
export function getDefaultConfig() {
return getFullConfigFromPartial({});
}